Skip to content

Commit 3fafc47

Browse files
committed
hide communication client
1 parent a604c76 commit 3fafc47

20 files changed

Lines changed: 210 additions & 73 deletions

File tree

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ let package = Package(
4343
),
4444
.target(
4545
name: "ShopifyAcceleratedCheckouts",
46-
dependencies: ["ShopifyCheckoutKit"],
46+
dependencies: ["ShopifyCheckoutKit", "ShopifyCheckoutProtocol"],
4747
path: "platforms/swift/Sources/ShopifyAcceleratedCheckouts",
4848
resources: [.process("Localizable.xcstrings"), .process("Media.xcassets")]
4949
),

platforms/android/lib/api/lib.api

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,6 @@ public final class com/shopify/checkoutkit/Checkout$Companion {
305305
public final fun serializer ()Lkotlinx/serialization/KSerializer;
306306
}
307307

308-
public abstract interface class com/shopify/checkoutkit/CheckoutCommunicationClient {
309-
public abstract fun process (Ljava/lang/String;)Ljava/lang/String;
310-
}
311-
312308
public final class com/shopify/checkoutkit/CheckoutDiscounts {
313309
public static final field Companion Lcom/shopify/checkoutkit/CheckoutDiscounts$Companion;
314310
public fun <init> ()V
@@ -427,7 +423,7 @@ public abstract interface class com/shopify/checkoutkit/CheckoutListener {
427423
}
428424

429425
public final class com/shopify/checkoutkit/CheckoutPresentation {
430-
public final fun connect (Lcom/shopify/checkoutkit/CheckoutCommunicationClient;)V
426+
public final fun connect (Lcom/shopify/checkoutkit/CheckoutProtocol$Client;)V
431427
public final fun onCancel (Lkotlin/jvm/functions/Function0;)V
432428
public final fun onFail (Lkotlin/jvm/functions/Function1;)V
433429
public final fun onGeolocationPermissionsHidePrompt (Lkotlin/jvm/functions/Function0;)V
@@ -448,11 +444,10 @@ public final class com/shopify/checkoutkit/CheckoutProtocol {
448444
public final fun getWindowOpen ()Lcom/shopify/checkoutkit/DelegationDescriptor;
449445
}
450446

451-
public final class com/shopify/checkoutkit/CheckoutProtocol$Client : com/shopify/checkoutkit/CheckoutCommunicationClient {
447+
public final class com/shopify/checkoutkit/CheckoutProtocol$Client {
452448
public fun <init> ()V
453449
public final fun on (Lcom/shopify/checkoutkit/DelegationDescriptor;Lkotlin/jvm/functions/Function1;)Lcom/shopify/checkoutkit/CheckoutProtocol$Client;
454450
public final fun on (Lcom/shopify/checkoutkit/NotificationDescriptor;Lkotlin/jvm/functions/Function1;)Lcom/shopify/checkoutkit/CheckoutProtocol$Client;
455-
public fun process (Ljava/lang/String;)Ljava/lang/String;
456451
}
457452

458453
public final class com/shopify/checkoutkit/CheckoutStatus : java/lang/Enum {
@@ -2502,9 +2497,9 @@ public final class com/shopify/checkoutkit/ShopifyCheckoutKit {
25022497
public static final fun invalidate ()V
25032498
public static final fun preload (Ljava/lang/String;Landroidx/activity/ComponentActivity;)V
25042499
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2505-
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutCommunicationClient;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2500+
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutProtocol$Client;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
25062501
public static final synthetic fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lkotlin/jvm/functions/Function1;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2507-
public static synthetic fun present$default (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutCommunicationClient;ILjava/lang/Object;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2502+
public static synthetic fun present$default (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutProtocol$Client;ILjava/lang/Object;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
25082503
}
25092504

25102505
public final class com/shopify/checkoutkit/Signals {
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package com.shopify.checkoutkit
22

33
/**
4-
* Implement this interface to handle Embedded Checkout Protocol (ECP) messages beyond
5-
* the built-in methods handled natively by the SDK.
6-
*
7-
* Register an implementation via [ShopifyCheckoutKit.present].
4+
* Internal bridge abstraction for processing raw Embedded Checkout Protocol (ECP)
5+
* messages after the WebView has filtered them to supported methods.
86
*/
9-
public interface CheckoutCommunicationClient {
7+
internal interface CheckoutCommunicationClient {
108
/**
119
* Process a JSON-RPC 2.0 ECP message from the checkout web page.
1210
*
@@ -18,5 +16,14 @@ public interface CheckoutCommunicationClient {
1816
* @param message JSON-RPC 2.0 encoded message string
1917
* @return JSON-RPC 2.0 encoded response string, or null to send no response
2018
*/
21-
public fun process(message: String): String?
19+
fun process(message: String): String?
20+
}
21+
22+
internal fun CheckoutProtocol.Client.asCommunicationClient(): CheckoutCommunicationClient =
23+
CheckoutProtocolClientAdapter(this)
24+
25+
private class CheckoutProtocolClientAdapter(
26+
private val client: CheckoutProtocol.Client,
27+
) : CheckoutCommunicationClient {
28+
override fun process(message: String): String? = client.process(message)
2229
}

platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutDialog.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal class CheckoutDialog(
2828
private val checkoutUrl: String,
2929
private val checkoutListener: CheckoutListener,
3030
context: Context,
31-
private val communicationClient: CheckoutCommunicationClient? = null,
31+
private val communicationClient: CheckoutProtocol.Client? = null,
3232
) : ComponentDialog(context) {
3333

3434
private var presentedCheckoutWebView: CheckoutWebView? = null

platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutPresentation.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class CheckoutPresentation internal constructor() {
2121
internal var onGeolocationPermissionsShowPrompt:
2222
((String, GeolocationPermissions.Callback) -> Unit)? = null
2323
internal var onGeolocationPermissionsHidePrompt: (() -> Unit)? = null
24-
internal var communicationClient: CheckoutCommunicationClient? = null
24+
internal var communicationClient: CheckoutProtocol.Client? = null
2525

2626
/**
2727
* Called when checkout fails.
@@ -76,7 +76,7 @@ public class CheckoutPresentation internal constructor() {
7676
/**
7777
* Connects a communication client for Embedded Checkout Protocol messages.
7878
*/
79-
public fun connect(client: CheckoutCommunicationClient?) {
79+
public fun connect(client: CheckoutProtocol.Client?) {
8080
communicationClient = client
8181
}
8282

platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import java.util.concurrent.CountDownLatch
2323
* Entry point for the typed Embedded Checkout Protocol (ECP) client.
2424
*
2525
* Provides static [NotificationDescriptor] instances for every EC notification method,
26-
* plus a fluent [Client] builder that implements [CheckoutCommunicationClient].
26+
* plus a fluent [Client] builder for typed protocol callbacks.
2727
*
2828
* Example usage:
2929
* ```kotlin
@@ -140,15 +140,15 @@ public object CheckoutProtocol {
140140
internal val json: Json = Json { ignoreUnknownKeys = true }
141141

142142
/**
143-
* A typed, fluent implementation of [CheckoutCommunicationClient].
143+
* A typed, fluent protocol client.
144144
*
145145
* Each [on] call returns a new [Client] instance (value semantics),
146146
* making it safe to share a base configuration across multiple presents.
147147
*/
148148
public class Client private constructor(
149149
private val handlers: Map<String, Handler>,
150150
private val delegations: Map<String, Delegation>,
151-
) : CheckoutCommunicationClient {
151+
) {
152152

153153
public constructor() : this(emptyMap(), emptyMap())
154154

@@ -185,7 +185,7 @@ public object CheckoutProtocol {
185185
): Client = Client(handlers, delegations + (descriptor.method to Delegation.Typed(descriptor, handler)))
186186

187187
/** Called by [EmbeddedCheckoutProtocol] for every delegated EC message. */
188-
override fun process(message: String): String? =
188+
internal fun process(message: String): String? =
189189
decodeRequest(message)?.let { request ->
190190
val delegation = delegations[request.method]
191191
if (delegation != null) {

platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutWebView.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ internal class CheckoutWebView(context: Context, attributeSet: AttributeSet? = n
3838
this.listener = listener
3939
}
4040

41-
fun setClient(client: CheckoutCommunicationClient?) {
41+
fun setClient(client: CheckoutProtocol.Client?) {
4242
log.d(LOG_TAG, "Setting communication client $client.")
43-
embeddedCheckoutProtocol.setClient(client)
43+
embeddedCheckoutProtocol.setClient(client?.asCommunicationClient())
4444
}
4545

4646
fun markPresented() {

platforms/android/lib/src/main/java/com/shopify/checkoutkit/EmbeddedCheckoutProtocol.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ internal class EmbeddedCheckoutProtocol(
2626
) {
2727
private val decoder = Json { ignoreUnknownKeys = true }
2828
private val defaultClient: CheckoutProtocol.Client = defaultDelegationClient()
29+
private val defaultCommunicationClient: CheckoutCommunicationClient = defaultClient.asCommunicationClient()
2930
private val defaultClientBindings: Map<String, DefaultClientBinding> = mapOf(
3031
CheckoutProtocol.windowOpen.method to DefaultClientBinding(
31-
client = defaultClient,
32+
client = defaultCommunicationClient,
3233
policy = DefaultClientPolicy.RunIfUnhandled,
3334
),
3435
CheckoutProtocol.error.method to DefaultClientBinding(
35-
client = defaultClient,
36+
client = defaultCommunicationClient,
3637
policy = DefaultClientPolicy.AlwaysRunAfterMerchant,
3738
),
3839
CheckoutProtocol.complete.method to DefaultClientBinding(

platforms/android/lib/src/main/java/com/shopify/checkoutkit/ShopifyCheckoutKit.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public object ShopifyCheckoutKit {
117117
* @param context The context the checkout is being presented from
118118
* @param checkoutListener provides callbacks to allow clients to listen for and respond to checkout lifecycle events
119119
* (failure, cancellation, permission prompts, file chooser).
120-
* @param communicationClient optional handler for supported Embedded Checkout Protocol (ECP)
120+
* @param communicationClient optional typed handler for supported Embedded Checkout Protocol (ECP)
121121
* messages from the checkout web page. Built-in messages
122122
* (`ec.ready` and [ec.start][CheckoutProtocol.start])
123123
* are handled automatically by the SDK.
@@ -129,7 +129,7 @@ public object ShopifyCheckoutKit {
129129
checkoutUrl: String,
130130
context: ComponentActivity,
131131
checkoutListener: T,
132-
communicationClient: CheckoutCommunicationClient? = null,
132+
communicationClient: CheckoutProtocol.Client? = null,
133133
): CheckoutKitDialog? {
134134
log.d("ShopifyCheckoutKit", "Present called with checkoutUrl ${checkoutUrl.redactedUrlForLogging()}.")
135135
if (context.isDestroyed || context.isFinishing) {

platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutPresentationTest.kt

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import org.junit.Before
1616
import org.junit.Test
1717
import org.junit.runner.RunWith
1818
import org.mockito.kotlin.mock
19-
import org.mockito.kotlin.verify
20-
import org.mockito.kotlin.whenever
2119
import org.robolectric.Robolectric
2220
import org.robolectric.RobolectricTestRunner
2321
import org.robolectric.Shadows.shadowOf
@@ -79,10 +77,10 @@ class CheckoutPresentationTest {
7977
}
8078

8179
@Test
82-
fun `present builder forwards connected client to embedded checkout protocol`() {
83-
val rawMessage = """{"jsonrpc":"2.0","method":"ec.messages.change","params":{"checkout":{}}}"""
84-
val client = mock<CheckoutCommunicationClient>()
85-
whenever(client.process(rawMessage)).thenReturn(null)
80+
fun `present builder dispatches connected protocol client`() {
81+
var received: Checkout? = null
82+
val client = CheckoutProtocol.Client()
83+
.on(CheckoutProtocol.start) { checkout -> received = checkout }
8684

8785
ShopifyCheckoutKit.present("https://shopify.com", activity) {
8886
connect(client)
@@ -92,10 +90,10 @@ class CheckoutPresentationTest {
9290
val dialog = ShadowDialog.getLatestDialog() as CheckoutDialog
9391
val webView = dialog.currentWebView()
9492

95-
webView.embeddedCheckoutProtocol().postMessage(rawMessage)
93+
webView.embeddedCheckoutProtocol().postMessage(ecStartMessage(currency = "USD"))
9694
shadowOf(Looper.getMainLooper()).runToEndOfTasks()
9795

98-
verify(client).process(rawMessage)
96+
assertThat(received?.currency).isEqualTo("USD")
9997
}
10098

10199
@Test
@@ -209,4 +207,19 @@ class CheckoutPresentationTest {
209207
field.isAccessible = true
210208
return field.get(this) as EmbeddedCheckoutProtocol
211209
}
210+
211+
private fun ecStartMessage(currency: String): String {
212+
val checkout = """
213+
{
214+
"id":"chk1",
215+
"currency":"$currency",
216+
"status":"incomplete",
217+
"line_items":[],
218+
"totals":[],
219+
"links":[],
220+
"ucp":{"payment_handlers":{},"version":"1.0"}
221+
}
222+
""".trimIndent()
223+
return """{"jsonrpc":"2.0","method":"ec.start","params":{"checkout":$checkout}}"""
224+
}
212225
}

0 commit comments

Comments
 (0)