Skip to content

Commit 9229144

Browse files
committed
hide communication client
1 parent 1c274f9 commit 9229144

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 {
@@ -2484,9 +2479,9 @@ public final class com/shopify/checkoutkit/ShopifyCheckoutKit {
24842479
public static final fun configure (Lcom/shopify/checkoutkit/ConfigurationUpdater;)V
24852480
public static final fun getConfiguration ()Lcom/shopify/checkoutkit/Configuration;
24862481
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2487-
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutCommunicationClient;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2482+
public static final fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lcom/shopify/checkoutkit/DefaultCheckoutListener;Lcom/shopify/checkoutkit/CheckoutProtocol$Client;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
24882483
public static final synthetic fun present (Ljava/lang/String;Landroidx/activity/ComponentActivity;Lkotlin/jvm/functions/Function1;)Lcom/shopify/checkoutkit/CheckoutKitDialog;
2489-
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;
2484+
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;
24902485
}
24912486

24922487
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
@@ -29,7 +29,7 @@ internal class CheckoutDialog(
2929
private val checkoutUrl: String,
3030
private val checkoutListener: CheckoutListener,
3131
context: Context,
32-
private val communicationClient: CheckoutCommunicationClient? = null,
32+
private val communicationClient: CheckoutProtocol.Client? = null,
3333
) : ComponentDialog(context) {
3434

3535
private val backNavigationCallback = object : OnBackPressedCallback(enabled = true) {

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
@@ -24,7 +24,7 @@ import java.util.concurrent.CountDownLatch
2424
* Entry point for the typed Embedded Checkout Protocol (ECP) client.
2525
*
2626
* Provides static [NotificationDescriptor] instances for every EC notification method,
27-
* plus a fluent [Client] builder that implements [CheckoutCommunicationClient].
27+
* plus a fluent [Client] builder for typed protocol callbacks.
2828
*
2929
* Example usage:
3030
* ```kotlin
@@ -113,15 +113,15 @@ public object CheckoutProtocol {
113113
internal val json: Json = Json { ignoreUnknownKeys = true }
114114

115115
/**
116-
* A typed, fluent implementation of [CheckoutCommunicationClient].
116+
* A typed, fluent protocol client.
117117
*
118118
* Each [on] call returns a new [Client] instance (value semantics),
119119
* making it safe to share a base configuration across multiple presents.
120120
*/
121121
public class Client private constructor(
122122
private val handlers: Map<String, Handler>,
123123
private val delegations: Map<String, Delegation>,
124-
) : CheckoutCommunicationClient {
124+
) {
125125

126126
public constructor() : this(emptyMap(), emptyMap())
127127

@@ -158,7 +158,7 @@ public object CheckoutProtocol {
158158
): Client = Client(handlers, delegations + (descriptor.method to Delegation.Typed(descriptor, handler)))
159159

160160
/** Called by [EmbeddedCheckoutProtocol] for every delegated EC message. */
161-
override fun process(message: String): String? =
161+
internal fun process(message: String): String? =
162162
decodeRequest(message)?.let { request ->
163163
delegations[request.method]?.dispatch(request) ?: run {
164164
dispatchNotification(request)

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
@@ -29,9 +29,9 @@ internal class CheckoutWebView(context: Context, attributeSet: AttributeSet? = n
2929
this.listener = listener
3030
}
3131

32-
fun setClient(client: CheckoutCommunicationClient?) {
32+
fun setClient(client: CheckoutProtocol.Client?) {
3333
log.d(LOG_TAG, "Setting communication client $client.")
34-
embeddedCheckoutProtocol.setClient(client)
34+
embeddedCheckoutProtocol.setClient(client?.asCommunicationClient())
3535
}
3636

3737
override fun getListener(): CheckoutWebViewListener {

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
@@ -30,13 +30,14 @@ internal class EmbeddedCheckoutProtocol(
3030
) {
3131
private val decoder = Json { ignoreUnknownKeys = true }
3232
private val defaultClient: CheckoutProtocol.Client = defaultDelegationClient()
33+
private val defaultCommunicationClient: CheckoutCommunicationClient = defaultClient.asCommunicationClient()
3334
private val defaultClientBindings: Map<String, DefaultClientBinding> = mapOf(
3435
CheckoutProtocol.windowOpen.method to DefaultClientBinding(
35-
client = defaultClient,
36+
client = defaultCommunicationClient,
3637
policy = DefaultClientPolicy.RunIfUnhandled,
3738
),
3839
CheckoutProtocol.error.method to DefaultClientBinding(
39-
client = defaultClient,
40+
client = defaultCommunicationClient,
4041
policy = DefaultClientPolicy.AlwaysRunAfterMerchant,
4142
),
4243
)

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
@@ -78,7 +78,7 @@ public object ShopifyCheckoutKit {
7878
* @param context The context the checkout is being presented from
7979
* @param checkoutListener provides callbacks to allow clients to listen for and respond to checkout lifecycle events
8080
* (failure, cancellation, permission prompts, file chooser).
81-
* @param communicationClient optional handler for supported Embedded Checkout Protocol (ECP)
81+
* @param communicationClient optional typed handler for supported Embedded Checkout Protocol (ECP)
8282
* messages from the checkout web page. Built-in messages
8383
* ([ec.ready][EmbeddedCheckoutProtocol.METHOD_READY] and [ec.start][CheckoutProtocol.start])
8484
* are handled automatically by the SDK.
@@ -90,7 +90,7 @@ public object ShopifyCheckoutKit {
9090
checkoutUrl: String,
9191
context: ComponentActivity,
9292
checkoutListener: T,
93-
communicationClient: CheckoutCommunicationClient? = null,
93+
communicationClient: CheckoutProtocol.Client? = null,
9494
): CheckoutKitDialog? {
9595
log.d("ShopifyCheckoutKit", "Present called with checkoutUrl $checkoutUrl.")
9696
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)