Skip to content
Draft
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
11 changes: 10 additions & 1 deletion .github/workflows/rn-build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
build-ios:
name: Build iOS Sample
runs-on: ${{ vars.MACOS_RUNNER }}
timeout-minutes: 30
timeout-minutes: 45
defaults:
run:
working-directory: platforms/react-native
Expand Down Expand Up @@ -71,3 +71,12 @@ jobs:

- name: Build iOS sample
run: pnpm sample build:ios

- name: Cache React Native SwiftPM artifacts
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/Library/Caches/ReactNative/spm-artifacts/0.87.0
key: ${{ runner.os }}-react-native-spm-${{ hashFiles('platforms/react-native/sample/package.json', 'platforms/react-native/pnpm-lock.yaml') }}

- name: Build iOS sample with experimental SwiftPM
run: pnpm sample build:ios:spm
27 changes: 22 additions & 5 deletions dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -720,22 +720,36 @@ commands:
optional: --local
run: cd platforms/react-native && pnpm run pod-install -- "$@"

spm:
desc: Sync experimental SwiftPM dependencies for the iOS sample.
long_desc: |
Generates the gitignored Codegen, autolinking, and XCFramework package
trees required by the opt-in SwiftPM Xcode project. Run this after a
fresh clone or dependency update. React Native 0.87 SwiftPM support is
experimental; CocoaPods remains the default.
run: cd platforms/react-native && pnpm sample spm "$@"

build-spm:
desc: Build the iOS sample with experimental SwiftPM support.
run: cd platforms/react-native && pnpm sample build:ios:spm

open:
desc: Open the React Native workspace root or native sample projects
long_desc: |
Opens platforms/react-native in the editor set by DEV_EDITOR in
.dev.env, otherwise `open`. The --ios and --android flags open the
.dev.env, otherwise `open`. The native flags open the
sample app's native projects.

dev rn open Open platforms/react-native
dev rn open --ios Open the sample iOS workspace in Xcode
dev rn open --ios Open the CocoaPods sample workspace in Xcode
dev rn open --ios-spm Open the experimental SwiftPM project in Xcode
dev rn open --android Open the sample Android project in Android Studio
syntax:
optional: "[--ios|--android]"
optional: "[--ios|--ios-spm|--android]"
run: |
set -e
if [ "$#" -gt 1 ]; then
echo "Usage: dev rn open [--ios|--android]" >&2
echo "Usage: dev rn open [--ios|--ios-spm|--android]" >&2
exit 1
fi

Expand All @@ -749,11 +763,14 @@ commands:
--ios)
xed platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcworkspace
;;
--ios-spm)
xed platforms/react-native/sample/ios/CheckoutKitReactNativeDemoSPM.xcodeproj
;;
--android)
open -a "Android Studio" platforms/react-native/sample/android
;;
*)
echo "Usage: dev rn open [--ios|--android]" >&2
echo "Usage: dev rn open [--ios|--ios-spm|--android]" >&2
exit 1
;;
esac
Expand Down
22 changes: 22 additions & 0 deletions platforms/react-native/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ pods need to be installed. The underlying
pnpm sample android
```

### Experimental SwiftPM sample

React Native 0.87 includes an early SwiftPM preview. CocoaPods remains the
default for the iOS sample, while the parallel
`CheckoutKitReactNativeDemoSPM.xcodeproj` exercises the preview without
changing the supported path.

After a fresh clone or dependency update, generate the gitignored SwiftPM
packages and React Native XCFramework links, then build the opt-in project:

```sh
dev rn spm
dev rn build-spm
```

Use `dev rn open --ios-spm` to open the project in Xcode. The project's
`Package.resolved` is committed so direct Xcode builds never update package
pins; do not commit other generated files under `ios/build/` or `ios/.build/`.
Community package manifests are committed as pnpm patches because
React Native's preview requires every native dependency to provide a
`Package.swift`.

## Local SDK development (`--local`)

The RN module wraps the Shopify Swift and Android SDKs, which live in this same monorepo at `platforms/swift/` and `platforms/android/`. The sample app builds against the **published** artifacts on CocoaPods / Maven Central — the same path CI takes.
Expand Down
3 changes: 3 additions & 0 deletions platforms/react-native/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ module.exports = {
transform: {
'\\.[jt]sx?$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/(?!((jest-)?react-native|@react-native(-community)?|@noble/hashes)/)',
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ Pod::Spec.new do |s|
s.platforms = { :ios => "15.0" }
s.source = { :git => "https://github.com/Shopify/checkout-kit.git", :tag => "react-native/#{s.version}" }

s.source_files = "ios/*.{h,m,mm,swift}"
s.source_files = [
"ios/*.{h,m,mm,swift}",
"ios/generated/ReactCodegen/**/*.{h,m,mm,cpp}"
]
s.public_header_files = "ios/generated/ReactCodegen/**/*.h"

s.dependency "React-Core"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import PassKit
import React
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit
import SwiftUI
import UIKit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// swift-tools-version: 6.0

import PackageDescription

let reactNativeHeaders: [Target.Dependency] = [
.product(name: "ReactHeaders", package: "ReactNative"),
.product(name: "ReactNativeHeaders", package: "ReactNative"),
.product(name: "ReactNativeDependenciesHeaders", package: "ReactNative")
]

let package = Package(
name: "CheckoutKitReactNative",
platforms: [.iOS(.v15)],
products: [
.library(
name: "CheckoutKitReactNative",
targets: [
"CheckoutKitReactNativeSwift",
"CheckoutKitReactNativeObjC",
"CheckoutKitReactNativeCodegen"
]
)
],
dependencies: [
.package(name: "ReactNative", path: "../../../../xcframeworks"),
.package(
url: "https://github.com/Shopify/checkout-kit",
exact: "4.0.0-alpha.5"
)
],
targets: [
.target(
name: "CheckoutKitReactNativeSwift",
dependencies: reactNativeHeaders + [
.product(name: "ShopifyCheckoutKit", package: "checkout-kit"),
.product(name: "ShopifyAcceleratedCheckouts", package: "checkout-kit")
],
path: ".",
sources: [
"AcceleratedCheckoutButtons+Extensions.swift",
"AcceleratedCheckoutButtons.swift",
"ProtocolRelay.swift",
"ShopifyCheckoutKit+EventSerialization.swift",
"ShopifyCheckoutKit+Extensions.swift",
"ShopifyCheckoutKit.swift"
],
swiftSettings: [.swiftLanguageMode(.v5)]
),
.target(
name: "CheckoutKitReactNativeObjC",
dependencies: reactNativeHeaders + ["CheckoutKitReactNativeCodegen"],
path: ".",
sources: ["ShopifyCheckoutKit.mm"],
publicHeadersPath: ".",
cxxSettings: [
.define("FOLLY_CFG_NO_COROUTINES", to: "1"),
.define("DEBUG", .when(configuration: .debug)),
.define("NDEBUG", .when(configuration: .release))
]
),
.target(
name: "CheckoutKitReactNativeCodegen",
dependencies: reactNativeHeaders,
path: "generated/ReactCodegen",
publicHeadersPath: ".",
cxxSettings: [
.define("FOLLY_CFG_NO_COROUTINES", to: "1"),
.define("DEBUG", .when(configuration: .debug)),
.define("NDEBUG", .when(configuration: .release))
],
linkerSettings: [.linkedFramework("Foundation")]
)
],
cxxLanguageStandard: .cxx20
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Foundation
#if COCOAPODS
#if canImport(ShopifyCheckoutProtocol)
import ShopifyCheckoutProtocol
#else
import ShopifyCheckoutKit

extension CheckoutProtocol.Client: @retroactive CheckoutCommunicationProtocol {}
#else
import ShopifyCheckoutProtocol
#endif

struct DispatchEnvelope<Payload: Encodable>: Encodable {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTViewManager.h>
#if __has_include(<CheckoutKitReactNativeCodegen/RNShopifyCheckoutKitSpec/RNShopifyCheckoutKitSpec.h>)
#import <CheckoutKitReactNativeCodegen/RNShopifyCheckoutKitSpec/RNShopifyCheckoutKitSpec.h>
#elif __has_include(<RNShopifyCheckoutKitSpec/RNShopifyCheckoutKitSpec.h>)
#import <RNShopifyCheckoutKitSpec/RNShopifyCheckoutKitSpec.h>
#else
#import "generated/ReactCodegen/RNShopifyCheckoutKitSpec/RNShopifyCheckoutKitSpec.h"
#endif
#import <objc/runtime.h>

// Registers the Swift module class (ShopifyCheckoutKit.swift) with the RN
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import PassKit
import React
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit
import SwiftUI
import UIKit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateComponentDescriptorCpp.js
*/

#include "ComponentDescriptors.h"
#include <react/renderer/core/ConcreteComponentDescriptor.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>

namespace facebook::react {

void RNShopifyCheckoutKitSpec_registerComponentDescriptorsFromCodegen(
std::shared_ptr<const ComponentDescriptorProviderRegistry> registry) {
registry->add(concreteComponentDescriptorProvider<RCTAcceleratedCheckoutButtonsComponentDescriptor>());
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateComponentDescriptorH.js
*/

#pragma once

#include "ShadowNodes.h"
#include <react/renderer/core/ConcreteComponentDescriptor.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>

namespace facebook::react {

using RCTAcceleratedCheckoutButtonsComponentDescriptor = ConcreteComponentDescriptor<RCTAcceleratedCheckoutButtonsShadowNode>;

void RNShopifyCheckoutKitSpec_registerComponentDescriptorsFromCodegen(
std::shared_ptr<const ComponentDescriptorProviderRegistry> registry);

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateEventEmitterCpp.js
*/

#include "EventEmitters.h"


namespace facebook::react {

void RCTAcceleratedCheckoutButtonsEventEmitter::onFail(OnFail event) const {
dispatchEvent("fail", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "message", event.message);
payload.setProperty(runtime, "code", event.code);
payload.setProperty(runtime, "statusCode", event.statusCode);
return payload;
});
}


void RCTAcceleratedCheckoutButtonsEventEmitter::onCancel(OnCancel event) const {
dispatchEvent("cancel", [](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);

return payload;
});
}


void RCTAcceleratedCheckoutButtonsEventEmitter::onRenderStateChange(OnRenderStateChange event) const {
dispatchEvent("renderStateChange", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "state", event.state);
payload.setProperty(runtime, "reason", event.reason);
return payload;
});
}


void RCTAcceleratedCheckoutButtonsEventEmitter::onClickLink(OnClickLink event) const {
dispatchEvent("clickLink", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "url", event.url);
return payload;
});
}


void RCTAcceleratedCheckoutButtonsEventEmitter::onDispatch(OnDispatch event) const {
dispatchEvent("dispatch", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "value", event.value);
return payload;
});
}


void RCTAcceleratedCheckoutButtonsEventEmitter::onSizeChange(OnSizeChange event) const {
dispatchEvent("sizeChange", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "height", event.height);
return payload;
});
}

} // namespace facebook::react
Loading
Loading