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
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,48 @@ minimum version number is at least `13`.
+ platform :ios, 13
```

### 4. Optional: Accelerated Checkout Buttons (iOS only)

By default, the iOS native module includes only the core checkout functionality. If you want to use the `AcceleratedCheckoutButtons` component (for Shop Pay and Apple Pay buttons), you need to explicitly include it.

#### Bare React Native or Expo Bare Workflow

Add the `AcceleratedCheckouts` subspec to your `ios/Podfile`:

```ruby
# ios/Podfile
pod "RNShopifyCheckoutSheetKit/AcceleratedCheckouts", :path => "../node_modules/@shopify/checkout-sheet-kit"
```

#### Expo Managed Workflow

For Expo managed apps, use the provided config plugin to enable AcceleratedCheckouts. In your `app.json` or `app.config.js`:

```json
{
"expo": {
"plugins": [
[
"@shopify/checkout-sheet-kit",
{
"enableAcceleratedCheckouts": true
}
]
]
}
}
```

The config plugin will automatically update your iOS Podfile to include the `AcceleratedCheckouts` subspec. After adding the plugin, run:

```sh
npx expo prebuild --clean
```

To disable AcceleratedCheckouts, set `enableAcceleratedCheckouts` to `false` or omit it entirely.

If you only need the default checkout experience, no additional configuration is required.

## Basic Usage

Once the SDK has been added as a package dependency and the minimum platform
Expand Down
118 changes: 118 additions & 0 deletions modules/@shopify/checkout-sheet-kit/EXPO_PLUGIN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Expo Config Plugin

This package includes an Expo config plugin that allows you to configure the AcceleratedCheckouts feature for iOS in managed Expo apps.

## Usage

Add the plugin to your `app.json` or `app.config.js`:

```json
{
"expo": {
"plugins": [
[
"@shopify/checkout-sheet-kit",
{
"enableAcceleratedCheckouts": true
}
]
]
}
}
```

After adding the plugin, regenerate your native projects:

```sh
npx expo prebuild --clean
```

## Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enableAcceleratedCheckouts` | `boolean` | `false` | Whether to include the AcceleratedCheckouts subspec for Shop Pay and Apple Pay buttons |

## How It Works

The config plugin uses Expo's `withDangerousMod` to modify your iOS `Podfile` during the prebuild process:

1. **When `enableAcceleratedCheckouts: true`**:
- Searches for the `RNShopifyCheckoutSheetKit` pod declaration in your Podfile
- Updates it to use the `AcceleratedCheckouts` subspec
- Example: `pod 'RNShopifyCheckoutSheetKit/AcceleratedCheckouts', :path => '...'`

2. **When `enableAcceleratedCheckouts: false` (or omitted)**:
- Ensures the Podfile uses the default Core subspec only
- Example: `pod 'RNShopifyCheckoutSheetKit', :path => '...'`

## Technical Details

### Plugin Implementation

The plugin (`app.plugin.js`) performs the following operations:

1. Locates the `Podfile` in your iOS project root
2. Uses regex patterns to detect existing pod configurations:
- Core-only: `pod 'RNShopifyCheckoutSheetKit'`
- With AcceleratedCheckouts: `pod 'RNShopifyCheckoutSheetKit/AcceleratedCheckouts'`
3. Modifies the Podfile content based on the `enableAcceleratedCheckouts` setting
4. Writes the updated content back to the Podfile

### Why Use a Config Plugin?

Expo's autolinking mechanism doesn't natively support CocoaPods subspecs. Without this plugin, managed Expo apps would always get the default (Core-only) subspec. The config plugin bridges this gap by programmatically modifying the Podfile during the prebuild process.

### Bare Workflow Alternative

If you're using Expo's bare workflow or a standard React Native app, you can skip the config plugin and directly modify your `ios/Podfile`:

```ruby
# ios/Podfile
pod "RNShopifyCheckoutSheetKit/AcceleratedCheckouts", :path => "../node_modules/@shopify/checkout-sheet-kit"
```

## Troubleshooting

### Plugin not taking effect

Make sure to run `npx expo prebuild --clean` after modifying your plugin configuration. The `--clean` flag ensures the iOS project is regenerated from scratch.

### CocoaPods errors after prebuild

If you encounter CocoaPods errors, try:

```sh
cd ios
pod install --repo-update
cd ..
```

### Verifying the configuration

After running prebuild, check your `ios/Podfile` to verify the correct subspec is being used:

```sh
grep "RNShopifyCheckoutSheetKit" ios/Podfile
```

Expected output with AcceleratedCheckouts enabled:
```
pod 'RNShopifyCheckoutSheetKit/AcceleratedCheckouts', :path => '../node_modules/@shopify/checkout-sheet-kit'
```

## Development

To test the plugin locally during development:

1. Make changes to `app.plugin.js`
2. Run `npx expo prebuild --clean` in your test app
3. Verify the Podfile changes are correct
4. Run `pod install` in the iOS directory
5. Build and test the app

## Related Documentation

- [Expo Config Plugins](https://docs.expo.dev/config-plugins/introduction/)
- [CocoaPods Subspecs](https://guides.cocoapods.org/syntax/podspec.html#subspec)
- [Shopify Checkout Kit Documentation](https://github.com/Shopify/checkout-sheet-kit-react-native)
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,24 @@ Pod::Spec.new do |s|

s.platforms = { :ios => "13.0" }
s.source = { :git => "https://github.com/Shopify/checkout-sheet-kit-react-native.git", :tag => "#{s.version}" }
s.swift_version = '5.0'

s.source_files = "ios/*.{h,m,mm,swift}"
s.default_subspec = 'Core'

s.dependency "React-Core"
s.dependency "ShopifyCheckoutSheetKit", "~> 3.4.0-rc.9"
s.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.4.0-rc.9"
s.subspec 'Core' do |ss|
ss.source_files = "ios/ShopifyCheckoutSheetKit*.{h,m,mm,swift}"
ss.dependency "React-Core"
ss.dependency "ShopifyCheckoutSheetKit", "~> 3.4.0-rc.9"
end

s.subspec 'AcceleratedCheckouts' do |ss|
ss.source_files = "ios/AcceleratedCheckout*.swift"
ss.dependency "RNShopifyCheckoutSheetKit/Core"
ss.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.4.0-rc.9"
ss.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) RN_SHOPIFY_CHECKOUT_ACCELERATED_CHECKOUTS=1'
}
end

if fabric_enabled
# Use React Native's helper if available, otherwise add dependencies directly
Expand Down
95 changes: 95 additions & 0 deletions modules/@shopify/checkout-sheet-kit/app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const {
withDangerousMod,
withPlugins,
createRunOncePlugin,
} = require('@expo/config-plugins');
const path = require('path');
const fs = require('fs');

const pkg = require('./package.json');

const withAcceleratedCheckouts = (config, props = {}) => {
const enableAcceleratedCheckouts = props.enableAcceleratedCheckouts ?? false;

return withDangerousMod(config, [
'ios',
async config => {
const podfilePath = path.join(
config.modRequest.platformProjectRoot,
'Podfile',
);

if (!fs.existsSync(podfilePath)) {
throw new Error(
`[@shopify/checkout-sheet-kit] Could not find Podfile at ${podfilePath}`,
);
}

let podfileContent = fs.readFileSync(podfilePath, 'utf8');

const coreSubspecPattern =
/pod\s+['"]RNShopifyCheckoutSheetKit['"]\s*,\s*:path\s*=>\s*['"][^'"]*['"]/;
const acceleratedSubspecPattern =
/pod\s+['"]RNShopifyCheckoutSheetKit\/AcceleratedCheckouts['"]\s*,\s*:path\s*=>\s*['"][^'"]*['"]/;

const hasCoreSubspec = coreSubspecPattern.test(podfileContent);
const hasAcceleratedSubspec =
acceleratedSubspecPattern.test(podfileContent);
const hasAutolinkedPod =
!hasCoreSubspec &&
!hasAcceleratedSubspec &&
/pod\s+['"]RNShopifyCheckoutSheetKit['"]/.test(podfileContent);

if (enableAcceleratedCheckouts) {
if (hasCoreSubspec) {
podfileContent = podfileContent.replace(
coreSubspecPattern,
match => {
return match.replace(
'RNShopifyCheckoutSheetKit',
'RNShopifyCheckoutSheetKit/AcceleratedCheckouts',
);
},
);
fs.writeFileSync(podfilePath, podfileContent, 'utf8');
console.log(
'[@shopify/checkout-sheet-kit] Updated Podfile to use AcceleratedCheckouts subspec',
);
} else if (!hasAcceleratedSubspec && hasAutolinkedPod) {
podfileContent = podfileContent.replace(
/pod\s+['"]RNShopifyCheckoutSheetKit['"]\s*,\s*:path\s*=>\s*['"]([^'"]*)['"]/,
`pod 'RNShopifyCheckoutSheetKit/AcceleratedCheckouts', :path => '$1'`,
);
fs.writeFileSync(podfilePath, podfileContent, 'utf8');
console.log(
'[@shopify/checkout-sheet-kit] Updated Podfile to use AcceleratedCheckouts subspec',
);
}
} else {
if (hasAcceleratedSubspec) {
podfileContent = podfileContent.replace(
acceleratedSubspecPattern,
match => {
return match.replace(
'RNShopifyCheckoutSheetKit/AcceleratedCheckouts',
'RNShopifyCheckoutSheetKit',
);
},
);
fs.writeFileSync(podfilePath, podfileContent, 'utf8');
console.log(
'[@shopify/checkout-sheet-kit] Updated Podfile to use Core subspec only',
);
}
}

return config;
},
]);
};

module.exports = createRunOncePlugin(
withAcceleratedCheckouts,
pkg.name,
pkg.version,
);
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ @interface RCT_EXTERN_MODULE (RCTShopifyCheckoutSheetKit, NSObject)

@end

#if RN_SHOPIFY_CHECKOUT_ACCELERATED_CHECKOUTS
/**
* AcceleratedCheckoutButtons View Manager
*/
Expand Down Expand Up @@ -147,3 +148,4 @@ @interface RCT_EXTERN_MODULE (RCTAcceleratedCheckoutButtonsManager, RCTViewManag
RCT_EXPORT_VIEW_PROPERTY(onSizeChange, RCTDirectEventBlock)

@end
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate {
private var hasListeners = false

internal var checkoutSheet: UIViewController?
#if RN_SHOPIFY_CHECKOUT_ACCELERATED_CHECKOUTS
private var acceleratedCheckoutsConfiguration: Any?
private var acceleratedCheckoutsApplePayConfiguration: Any?
#endif

override var methodQueue: DispatchQueue! {
return DispatchQueue.main
Expand Down Expand Up @@ -213,6 +215,7 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate {
resolve(config)
}

#if RN_SHOPIFY_CHECKOUT_ACCELERATED_CHECKOUTS
@objc func configureAcceleratedCheckouts(
_ storefrontDomain: String,
storefrontAccessToken: String,
Expand Down Expand Up @@ -305,4 +308,34 @@ class RCTShopifyCheckoutSheetKit: RCTEventEmitter, CheckoutDelegate {
return field
}
}
#else
@objc func configureAcceleratedCheckouts(
_ storefrontDomain: String,
storefrontAccessToken: String,
customerEmail: String?,
customerPhoneNumber: String?,
customerAccessToken: String?,
applePayMerchantIdentifier: String?,
applyPayContactFields: [String]?,
supportedShippingCountries: [String]?,
resolve: @escaping RCTPromiseResolveBlock,
reject _: @escaping RCTPromiseRejectBlock
) {
resolve(false)
}

@objc func isAcceleratedCheckoutAvailable(
_ resolve: @escaping RCTPromiseResolveBlock,
reject _: @escaping RCTPromiseRejectBlock
) {
resolve(false)
}

@objc func isApplePayAvailable(
_ resolve: @escaping RCTPromiseResolveBlock,
reject _: @escaping RCTPromiseRejectBlock
) {
resolve(false)
}
#endif
}
1 change: 1 addition & 0 deletions modules/@shopify/checkout-sheet-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"ios",
"android",
"lib",
"app.plugin.js",
"*.podspec",
"!ios/build",
"!android/build",
Expand Down
2 changes: 1 addition & 1 deletion sample/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ target 'ReactNative' do
end
end

pod "RNShopifyCheckoutSheetKit", :path => "../../modules/@shopify/checkout-sheet-kit"
pod "RNShopifyCheckoutSheetKit/AcceleratedCheckouts", :path => "../../modules/@shopify/checkout-sheet-kit"
Loading
Loading