Skip to content

Commit 1dab3aa

Browse files
feat(RN): add first protocol event
1 parent f478e65 commit 1dab3aa

47 files changed

Lines changed: 5618 additions & 249 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ apollo-ios-cli
3131

3232
# Android / Gradle
3333
.gradle/
34+
.kotlin/
3435
build/
3536
captures/
3637
.externalNativeBuild

AGENTS.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,56 @@ protocol/ # cross-platform communication layer based on UCP
99
e2e/ # cross-platform end-to-end tests
1010
.github/ # workflows, issue templates, CODEOWNERS
1111
```
12+
13+
## React Native development with local native SDK changes
14+
15+
Until the new native SDK libraries have stable released versions, assume React Native validation needs the local native SDK workflow. Use `--local` whenever running the React Native sample or native React Native tests that depend on the in-repo Swift/Kotlin SDKs.
16+
17+
Use the React Native `--local` workflow when you need to test React Native against native SDK changes that exist in this repository but have not been released as a SemVer/CocoaPods/Maven version yet.
18+
19+
This applies when changes are made under:
20+
21+
- `platforms/swift/` — the iOS Swift SDK / CocoaPods sources
22+
- `platforms/android/` — the Android SDK / Maven artifact sources
23+
24+
It does **not** refer to the React Native wrapper platform folders:
25+
26+
- `platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/`
27+
- `platforms/react-native/modules/@shopify/checkout-kit-react-native/android/`
28+
29+
### What `--local` does
30+
31+
- For React Native iOS, `--local` wires CocoaPods to the in-repo `platforms/swift/` sources via a local path instead of a released pod version.
32+
- For React Native Android, `--local` publishes/uses the in-repo `platforms/android/` SDK through Maven Local so Gradle resolves the local SDK artifact instead of a released Maven version.
33+
34+
### When to use it
35+
36+
Use `--local` whenever you are validating React Native behavior that depends on unreleased native SDK changes, for example:
37+
38+
- a new Swift SDK API that the React Native iOS bridge calls
39+
- a new Android SDK API that the React Native Android bridge calls
40+
- generated protocol/model changes under the native SDKs that the React Native module consumes
41+
- any change in `platforms/swift/` or `platforms/android/` that has not yet been released and consumed through normal dependency versions
42+
43+
Re-run the relevant local workflow whenever `platforms/swift/` or `platforms/android/` changes, because the React Native sample/tests need to re-resolve those local native SDK sources/artifacts.
44+
45+
```bash
46+
# iOS sample using local platforms/swift sources
47+
dev rn ios --local
48+
49+
# Android sample using local platforms/android via Maven Local
50+
dev rn android --local
51+
52+
# React Native Android unit tests using local platforms/android via Maven Local
53+
# `dev rn test android` publishes platforms/android/lib to ~/.m2 first, then runs the RN module tests.
54+
dev rn test android
55+
```
56+
57+
For ad-hoc Android Gradle test commands, publish the local Android SDK first and set `USE_LOCAL_SDK=1` so the React Native module resolves `com.shopify:checkout-kit:1.0.0` from Maven Local instead of the unreleased placeholder artifact:
58+
59+
```bash
60+
cd platforms/react-native
61+
USE_LOCAL_SDK=1 ./scripts/publish_android_snapshot
62+
cd sample/android
63+
USE_LOCAL_SDK=1 ./gradlew :shopify_checkout-kit-react-native:testDebugUnitTest
64+
```

dev.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,35 @@ commands:
276276
build:
277277
desc: Build the @shopify/checkout-kit-react-native module
278278
run: cd platforms/react-native && pnpm module build
279+
test:
280+
desc: Run React Native module tests (JS + iOS + Android)
281+
long_desc: |
282+
Runs unit tests across all three React Native targets:
283+
- JS: Jest tests in `platforms/react-native/modules/@shopify/checkout-kit-react-native/tests/`
284+
- iOS: Swift Package tests at `platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/`
285+
- Android: Gradle JVM tests for `:shopify_checkout-kit-react-native` (requires a local Maven publish of `:lib`)
286+
run: |
287+
set -e
288+
cd platforms/react-native && pnpm test
289+
cd modules/@shopify/checkout-kit-react-native/ios && swift test
290+
cd ../../../../
291+
USE_LOCAL_SDK=1 ./scripts/publish_android_snapshot
292+
cd sample/android && USE_LOCAL_SDK=1 ./gradlew :shopify_checkout-kit-react-native:test
293+
subcommands:
294+
js:
295+
desc: Run JS unit tests via jest
296+
run: cd platforms/react-native && pnpm test
297+
ios:
298+
desc: Run native iOS unit tests (Swift Package at modules/.../ios)
299+
run: cd platforms/react-native/modules/@shopify/checkout-kit-react-native/ios && swift test
300+
android:
301+
desc: Run native Android unit tests for the RN module (publishes/uses local platforms/android SDK)
302+
run: |
303+
set -e
304+
cd platforms/react-native
305+
USE_LOCAL_SDK=1 ./scripts/publish_android_snapshot
306+
cd sample/android
307+
USE_LOCAL_SDK=1 ./gradlew :shopify_checkout-kit-react-native:test
279308
lint:
280309
desc: Run all React Native lint checks (Swift, module, sample)
281310
aliases: [style]

platforms/react-native/README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -621,10 +621,16 @@ shopify.present(checkoutUrl, {
621621
`onClose` and `onFail` are mutually exclusive — exactly one of them fires
622622
per `present(...)` call, after which both handles are released.
623623

624-
> Protocol-level callbacks (`start`, `complete`, `error` on the protocol
625-
> client) are not part of this section and will land in a follow-up release
626-
> alongside a `<CheckoutSheet>` component. Checkout completion is not
627-
> currently surfaced through the per-call callbacks.
624+
> [!IMPORTANT]
625+
> `present(...)` supports one active checkout presentation at a time. Starting
626+
> another presentation while a checkout sheet is already active is unsupported;
627+
> callbacks and protocol handlers are scoped to the currently active
628+
> presentation. For multiple inline checkout surfaces, use component-scoped APIs
629+
> where available.
630+
631+
> Protocol-level callbacks are configured separately from these SDK lifecycle
632+
> callbacks. Checkout completion is not currently surfaced through the per-call
633+
> SDK lifecycle callbacks.
628634

629635
## Identity & customer accounts
630636

platforms/react-native/__mocks__/react-native.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ const exampleConfig = {
4949
colorScheme: 'automatic',
5050
logLevel: 'error',
5151
};
52+
const shopifyCheckoutKitEventEmitter = createMockEmitter();
5253

5354
const ShopifyCheckoutKit = {
5455
version: '0.7.0',
5556
getConstants: jest.fn(() => ({
5657
version: '0.7.0',
5758
dispatchEventTypes: ['close', 'fail', 'geolocationRequest'],
5859
})),
60+
onDispatch: jest.fn((callback: (envelopeJson: string) => void) =>
61+
shopifyCheckoutKitEventEmitter.addListener('onDispatch', callback),
62+
),
5963
preload: jest.fn(),
6064
present: jest.fn(),
6165
dismiss: jest.fn(),
@@ -76,7 +80,7 @@ module.exports = {
7680
PermissionsAndroid: {
7781
requestMultiple: jest.fn(async () => ({})),
7882
},
79-
NativeEventEmitter: jest.fn(() => createMockEmitter()),
83+
NativeEventEmitter: jest.fn(() => shopifyCheckoutKitEventEmitter),
8084
requireNativeComponent,
8185
codegenNativeComponent,
8286
TurboModuleRegistry: {
@@ -90,7 +94,7 @@ module.exports = {
9094
NativeModules: {
9195
ShopifyCheckoutKit: {
9296
...ShopifyCheckoutKit,
93-
eventEmitter: createMockEmitter(),
97+
eventEmitter: shopifyCheckoutKitEventEmitter,
9498
},
9599
},
96100
StyleSheet,

platforms/react-native/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
preset: 'react-native',
33
modulePathIgnorePatterns: ['modules/@shopify/checkout-kit-react-native/lib'],
4-
modulePaths: ['<rootDir>/sample/node_modules'],
4+
modulePaths: ['<rootDir>/node_modules', '<rootDir>/sample/node_modules'],
55
setupFiles: ['<rootDir>/jest.setup.ts'],
66
transform: {
77
'\\.[jt]sx?$': 'babel-jest',

platforms/react-native/metro.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
33

44
const root = path.resolve(__dirname);
55
const sample = path.resolve(root, 'sample');
6+
const protocol = path.resolve(root, '../../protocol/languages/typescript');
67

78
/**
89
* Metro configuration
@@ -13,7 +14,7 @@ const sample = path.resolve(root, 'sample');
1314
const config = mergeConfig(getDefaultConfig(__dirname), {
1415
projectRoot: sample,
1516

16-
watchFolders: [root],
17+
watchFolders: [root, protocol],
1718

1819
resolver: {
1920
resolveRequest: (context, moduleName, platform) => {
@@ -46,6 +47,8 @@ const config = mergeConfig(getDefaultConfig(__dirname), {
4647
'modules',
4748
'@shopify/checkout-kit-react-native',
4849
),
50+
'@shopify/checkout-kit-protocol': protocol,
51+
'@babel/runtime': path.resolve(root, 'node_modules', '@babel/runtime'),
4952
},
5053
},
5154

platforms/react-native/modules/@shopify/checkout-kit-react-native/RNShopifyCheckoutKit.podspec

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ Pod::Spec.new do |s|
1414
s.source = { :git => "https://github.com/Shopify/checkout-kit.git", :tag => "#{s.version}" }
1515

1616
s.source_files = "ios/*.{h,m,mm,swift}"
17+
# `ios/Package.swift` is the manifest for the nested SwiftPM test package
18+
# (CasingTransform / ProtocolRelay unit tests). It imports `PackageDescription`
19+
# which only exists in the SwiftPM toolchain, so it must not be compiled by
20+
# CocoaPods/Xcode when the RN module is consumed from an iOS app.
21+
s.exclude_files = "ios/Package.swift"
1722

1823
s.dependency "React-Core"
1924

platforms/react-native/modules/@shopify/checkout-kit-react-native/android/build.gradle

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
buildscript {
2+
ext.kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : "2.1.20"
3+
24
repositories {
35
google()
46
mavenCentral()
57
}
68

79
dependencies {
810
classpath "com.android.tools.build:gradle:8.11.0"
11+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12+
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
913
}
1014
}
1115

1216
apply plugin: "com.android.library"
1317
apply plugin: "com.facebook.react"
18+
apply plugin: "org.jetbrains.kotlin.android"
19+
apply plugin: "org.jetbrains.kotlin.plugin.serialization"
1420

1521
def getExtOrIntegerDefault(name) {
1622
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties[name]).toInteger()
@@ -73,8 +79,17 @@ android {
7379
sourceCompatibility JavaVersion.VERSION_1_8
7480
targetCompatibility JavaVersion.VERSION_1_8
7581
}
82+
83+
kotlinOptions {
84+
jvmTarget = "1.8"
85+
}
86+
87+
testOptions {
88+
unitTests.includeAndroidResources = true
89+
}
7690
}
7791

92+
7893
repositories {
7994
mavenLocal()
8095
mavenCentral()
@@ -97,6 +112,11 @@ dependencies {
97112

98113
implementation(shopifySdkArtifact)
99114
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.5")
115+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
100116
debugImplementation(shopifySdkArtifact)
117+
118+
testImplementation "junit:junit:4.13.2"
119+
testImplementation "org.assertj:assertj-core:3.27.7"
120+
testImplementation "org.robolectric:robolectric:4.16.1"
101121
}
102122

platforms/react-native/modules/@shopify/checkout-kit-react-native/android/gradle.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ targetSdkVersion=35
33
compileSdkVersion=36
44
ndkVersion=23.1.7779620
55
buildToolsVersion = "35.0.0"
6+
7+
# Opt out of the React Native Gradle plugin's JdkConfiguratorUtils, which otherwise
8+
# silently rewrites compileOptions to 17 and pins the Kotlin JVM toolchain to 17 for
9+
# every com.android.library it sees. We mirror :lib's pinned JVM 1.8 contract instead.
10+
react.internal.disableJavaVersionAlignment=true

0 commit comments

Comments
 (0)