Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,17 @@ To check for lint issues without auto-correcting:

### Public API surface

The library's public API is tracked via a committed baseline at `platforms/android/lib/api/lib.api`, managed by the [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) Gradle plugin. The unified `Breaking Changes` CI workflow runs `./gradlew :lib:apiCheck` on every PR that touches Android sources and fails if the compiled public API diverges from the baseline.
The Android-facing public APIs are tracked via committed baselines managed by the [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) Gradle plugin:

@kiftio kiftio Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewording to cover protocol as well as the lib


- `platforms/android/lib/api/lib.api` for `com.shopify:checkout-kit`.
- `protocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.api` for `com.shopify:embedded-checkout-protocol`.

The unified `Breaking Changes` CI workflow runs `./gradlew :lib:apiCheck` from `platforms/android` and `./gradlew :embedded-checkout-protocol:apiCheck` from `protocol/languages/kotlin` on every PR that touches Android or Kotlin protocol sources. It fails if either compiled public API diverges from the committed baselines.

If your change intentionally modifies the public API:

1. Run `dev android api dump` from the repo root (or `./gradlew :lib:apiDump` from `platforms/android/`) to regenerate the baseline.
2. Review the diff in `platforms/android/lib/api/lib.api` alongside your code changes.
1. Run `dev android api dump` from the repo root to regenerate both baselines. For project-scoped updates, run `./gradlew :lib:apiDump` from `platforms/android/` or `./gradlew :embedded-checkout-protocol:apiDump` from `protocol/languages/kotlin/`.
2. Review the relevant `.api` diff alongside your code changes.
3. Commit the updated `.api` file in the same PR.

If you did _not_ intend to change public API and `apiCheck` is failing, the diff shows what your change inadvertently affected — treat it as a signal that something in your PR has consumer-visible impact.
Expand All @@ -164,16 +169,16 @@ If you did _not_ intend to change public API and `apiCheck` is failing, the diff

Open a pull request with the following changes:

1. Bump the `versionName` in `platforms/android/lib/build.gradle`.
1. Bump `checkoutKitAndroid` in `platforms/android/gradle/libs.versions.toml`.

@kiftio kiftio Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a different var to bump now versions are moved up to a toml file

2. Add an entry to the top of `platforms/android/CHANGELOG.md`.
3. If the React Native package should consume this Android SDK release, update `checkoutKit.nativeSdkVersions.android` in `platforms/react-native/modules/@shopify/checkout-kit-react-native/package.json` to the same version.
3. Update `checkoutKit.nativeSdkVersions.android` in `platforms/react-native/modules/@shopify/checkout-kit-react-native/package.json` to the same lowercase SemVer.

Supported release versions are `X.Y.Z` and prerelease versions are `X.Y.Z-{alpha|beta|rc}.N`.

Once merged, run the [Release package workflow](../../actions/workflows/release.yml):

1. Select `Android` as the platform.
2. Enter the expected version. The workflow reads the SDK version from `platforms/android/lib/build.gradle` and fails if the typed version does not match.
2. Enter the expected version. The workflow reads the SDK version from `platforms/android/gradle/libs.versions.toml` and fails if the typed version does not match.
3. Select `Dry run` first to review the release plan without creating a release.
4. Rerun with `Draft release` to create a draft GitHub Release with the `android/`-prefixed tag (e.g. `android/3.0.1`) for human review.
5. Publish the draft release when ready. Publishing the draft kicks off the [Android publish workflow](../../actions/workflows/android-publish.yml). **A manual approval by a maintainer is required before publication to Maven Central.**
Expand All @@ -195,7 +200,7 @@ The React Native package reads its published native SDK dependency versions from
}
```

When updating the Swift or Android SDK version that React Native should consume, update the matching `checkoutKit.nativeSdkVersions` entry in this package file. These values drive `RNShopifyCheckoutKit.podspec` for iOS and the module/sample Gradle dependencies for Android, so they must stay aligned with the published native SDK versions used by the React Native release.
When updating the Swift or Android SDK version that React Native should consume, update the matching `checkoutKit.nativeSdkVersions` entry in this package file. These values drive `RNShopifyCheckoutKit.podspec` for iOS and the module/sample Gradle dependencies for Android, so they must stay aligned with the published native SDK versions used by the React Native release. Android CI uses the published Maven artifact by default, so `nativeSdkVersions.android` must stay on the published `com.shopify:checkout-kit` lowercase SemVer, not the Kotlin protocol calver.

### Public API surface

Expand Down
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<details>
<summary>Releasing a new Android version?</summary>

- [ ] I have bumped the `versionName` in `platforms/android/lib/build.gradle`
- [ ] I have bumped `checkoutKitAndroid` in `platforms/android/gradle/libs.versions.toml`
- [ ] I have updated `platforms/android/CHANGELOG.md`
- [ ] I have updated the Gradle/Maven version snippets in `platforms/android/README.md`

Expand Down
28 changes: 26 additions & 2 deletions .github/scripts/validate-release-version
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ json_version() {
.github/scripts/package-json-version "$file"
}

json_string_field() {
local file="$1"
local jq_filter="$2"

if ! value=$(jq -er "$jq_filter | strings | select(length > 0)" "$file"); then
echo "::error file=$file::Could not extract version field." >&2
exit 1
fi

printf '%s\n' "$value"
}

version_catalog_value() {
local file="$1"
local key="$2"

extract_first_match "$file" "s/^[[:space:]]*${key}[[:space:]]*=[[:space:]]*\"([^\"]+)\".*/\\1/p"
}

check_same_version() {
local expected="$1"
local file="$2"
Expand Down Expand Up @@ -86,8 +105,13 @@ case "$PLATFORM_INPUT" in
TAG_PREFIX="android/"
PUBLISH_WORKFLOW="android-publish.yml"

ANDROID_VERSION_FILE="platforms/android/lib/build.gradle"
VERSION=$(extract_first_match "$ANDROID_VERSION_FILE" 's/^[[:space:]]*def[[:space:]]+versionName[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p')
ANDROID_VERSION_FILE="platforms/android/gradle/libs.versions.toml"
RN_PACKAGE_FILE="platforms/react-native/modules/@shopify/checkout-kit-react-native/package.json"

VERSION=$(version_catalog_value "$ANDROID_VERSION_FILE" "checkoutKitAndroid")
RN_ANDROID_VERSION=$(json_string_field "$RN_PACKAGE_FILE" '.checkoutKit.nativeSdkVersions.android')

check_same_version "$VERSION" "$RN_PACKAGE_FILE" "$RN_ANDROID_VERSION"
;;

"React Native"|react-native|ReactNative|rn|RN)
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/android-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ jobs:
java-version: 17

- name: Publish Package
run: ./gradlew publishReleasePublicationToOssrh-staging-apiRepository
run: |
./gradlew \
:embedded-checkout-protocol:publishReleasePublicationToOssrh-staging-apiRepository \
:lib:publishReleasePublicationToOssrh-staging-apiRepository
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/breaking-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ jobs:
- name: Check public Android API baseline
run: ./gradlew :lib:apiCheck --console=plain

- name: Check public Kotlin protocol API baseline
run: ../../protocol/languages/kotlin/gradlew -p ../../protocol/languages/kotlin :embedded-checkout-protocol:apiCheck --console=plain

Comment on lines +74 to +76

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this basically a version check or does it do more?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a full BCV API check, so we get an api file to allow us to catch embedded-checkout-protocol API drift over time, like with the Checkout Kit one.

react-native:
name: React Native
if: inputs.react-native == 'true'
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rn-build-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ jobs:
platforms/android/**/*.gradle*
platforms/android/**/gradle-wrapper.properties
platforms/android/gradle.properties
protocol/languages/kotlin/**/*.gradle*
protocol/languages/kotlin/**/*.toml
platforms/react-native/package.json
platforms/react-native/pnpm-lock.yaml
platforms/react-native/sample/package.json
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rn-test-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ jobs:
platforms/android/**/*.gradle*
platforms/android/**/gradle-wrapper.properties
platforms/android/gradle.properties
protocol/languages/kotlin/**/*.gradle*
protocol/languages/kotlin/**/*.toml
platforms/react-native/package.json
platforms/react-native/pnpm-lock.yaml
platforms/react-native/sample/package.json
Expand Down
21 changes: 12 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ platforms/
android/ # Android library and sample apps
react-native/ # React Native wrapper
web/ # Web component package and sample app
protocol/ # cross-platform communication layer based on UCP
protocol/ # cross-platform communication layer and protocol language artifacts based on UCP
e2e/ # cross-platform end-to-end tests
.github/ # workflows, issue templates, CODEOWNERS
```
Expand Down Expand Up @@ -49,6 +49,7 @@ This applies when changes are made under:

- `platforms/swift/` — the iOS Swift SDK / CocoaPods sources
- `platforms/android/` — the Android SDK / Maven artifact sources
- `protocol/languages/kotlin/` — Kotlin protocol artifacts consumed by the Android SDK

It does **not** refer to the React Native wrapper platform folders:

Expand All @@ -58,32 +59,32 @@ It does **not** refer to the React Native wrapper platform folders:
### What `--local` does

- For React Native iOS, `--local` wires CocoaPods to the in-repo `platforms/swift/` sources via a local path instead of a released pod version.
- 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.
- For React Native Android, `--local` publishes/uses the in-repo Android SDK and Kotlin protocol artifacts through Maven Local so Gradle resolves the local `com.shopify:checkout-kit` and `com.shopify:embedded-checkout-protocol` artifacts instead of released Maven versions.

### When to use it

Use `--local` whenever you are validating React Native behavior that depends on unreleased native SDK changes, for example:

- a new Swift SDK API that the React Native iOS bridge calls
- a new Android SDK API that the React Native Android bridge calls
- generated protocol/model changes under the native SDKs that the React Native module consumes
- any change in `platforms/swift/` or `platforms/android/` that has not yet been released and consumed through normal dependency versions
- generated protocol/model changes under `protocol/languages/kotlin/` that the React Native module consumes through Android
- any change in `platforms/swift/`, `platforms/android/`, or `protocol/languages/kotlin/` that has not yet been released and consumed through normal dependency versions

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.
Re-run the relevant local workflow whenever `platforms/swift/`, `platforms/android/`, or `protocol/languages/kotlin/` changes, because the React Native sample/tests need to re-resolve those local native SDK sources/artifacts.

```bash
# iOS sample using local platforms/swift sources
dev rn ios --local

# Android sample using local platforms/android via Maven Local
# Android sample using local Android and Kotlin protocol artifacts via Maven Local
dev rn android --local

# React Native Android unit tests using local platforms/android via Maven Local
# `dev rn test android` publishes platforms/android/lib to ~/.m2 first, then runs the RN module tests.
# React Native Android unit tests using local Android and Kotlin protocol artifacts via Maven Local
# `dev rn test android` publishes the Android SDK artifacts to ~/.m2 first, then runs the RN module tests.
dev rn test android
```

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:
For ad-hoc Android Gradle test commands, publish the local Android SDK first and set `USE_LOCAL_SDK=1` so the React Native sample resolves the local `com.shopify:checkout-kit` and `com.shopify:embedded-checkout-protocol` artifacts from Maven Local:

```bash
cd platforms/react-native
Expand All @@ -92,6 +93,8 @@ cd sample/android
USE_LOCAL_SDK=1 ./gradlew :shopify_checkout-kit-react-native:testDebugUnitTest
```

The React Native Android sample uses exclusive Maven Local resolution for those two `com.shopify` modules when `USE_LOCAL_SDK=1`. Keep that filtering in the sample Gradle build; duplicating exclusive repository filters for the same modules elsewhere can break dependency resolution.

## Sensitive configuration

Treat storefront environment and generated sample app configuration values as
Expand Down
37 changes: 29 additions & 8 deletions dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,25 @@ commands:
subcommands:
build:
desc: Build the protocol target
run: cd protocol/languages/swift && swift build
run: |
set -e
root=$(pwd)
cd protocol/languages/swift
echo "Building Swift protocol..."
swift build
cd $root/protocol/languages/kotlin
echo "Building Kotlin protocol..."
./gradlew :embedded-checkout-protocol:build
test:
desc: Run protocol package tests
run: |
root=$(pwd)
cd protocol/languages/swift
echo "Running tests for Swift..."
swift test
cd $root/protocol/languages/kotlin
echo "Running tests for Kotlin..."
./gradlew :embedded-checkout-protocol:test
cd $root/protocol
echo "Running tests for TypeScript..."
pnpm test
Expand Down Expand Up @@ -227,20 +238,30 @@ commands:
open -a "Android Studio" "$project"

api:
desc: Validate or update the public API baseline (lib/api/lib.api)
desc: Validate or update the public Android API baselines
run: |
echo "Usage: dev android api {check|dump}"
echo ""
echo " check Verify public API matches the committed baseline"
echo " dump Regenerate the baseline after intentional public API changes"
echo " check Verify public APIs match the committed baselines"
echo " dump Regenerate the baselines after intentional public API changes"
exit 1
subcommands:
check:
desc: Verify public API matches the committed baseline
run: cd platforms/android && ./gradlew :lib:apiCheck
desc: Verify public APIs match the committed baselines
run: |
set -e
cd platforms/android
./gradlew :lib:apiCheck
cd ../../protocol/languages/kotlin
./gradlew :embedded-checkout-protocol:apiCheck
dump:
desc: Regenerate the baseline after intentional public API changes
run: cd platforms/android && ./gradlew :lib:apiDump
desc: Regenerate the baselines after intentional public API changes
run: |
set -e
cd platforms/android
./gradlew :lib:apiDump
cd ../../protocol/languages/kotlin
./gradlew :embedded-checkout-protocol:apiDump

# Swift
swift:
Expand Down
Loading
Loading