feat(ios): resolve Stripe iOS SDK via Swift Package Manager - #2587
Draft
gbirch-stripe wants to merge 20 commits into
Draft
feat(ios): resolve Stripe iOS SDK via Swift Package Manager#2587gbirch-stripe wants to merge 20 commits into
gbirch-stripe wants to merge 20 commits into
Conversation
On React Native 0.75 and above, the Stripe iOS SDK is now resolved from the stripe-ios-spm package through React Native's spm_dependency helper instead of the CocoaPods registry, ahead of stripe-ios deprecating CocoaPods support. This requires building with dynamic frameworks; apps can opt out with $StripeDisableSPM = true to keep CocoaPods resolution while Stripe continues publishing pods. React Native versions below 0.75 keep CocoaPods resolution. stripe_spm.rb hooks Pod::Installer to fail fast on unsupported static linkage, link the StripeCryptoOnramp product when the Onramp subspec is installed, and embed SPM-built dynamic frameworks into the app bundle. Note: example/ios/Podfile.lock still needs regenerating on macOS. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Pod::Target#build_type is a private reader in CocoaPods; the public API is the build_as_* predicate family. Also guard the installer hook against re-aliasing when the original method is private. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
React Native's prebuilt core only wires framework linkage through the new-architecture dependency path, so with dynamic frameworks old-arch pods compile against prebuilt React headers but never link the framework (undefined RCT* symbols). Building from source restores the standard CocoaPods linkage and matches what old-architecture apps actually do. Prebuilt RN stays enabled for new-arch builds. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
The previous fix disabled both prebuilt mechanisms on the old architecture, but only the prebuilt React core has the linkage gap. Turning off RCT_USE_RN_DEP reintroduced source builds of React Native's pinned third-party C++, and fmt does not compile under Xcode 26's Clang (consteval errors). Prebuilt dependencies are delivered as a vendored xcframework whose linkage propagates to dependent pods through standard CocoaPods behavior, so they are safe on both architectures; only the prebuilt React core stays gated to the new architecture. Also documents the Podfile end to end. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Documents stripe_spm.rb end to end (why it exists, the three-layer mechanism, install lifecycle and ordering, and the reasoning behind each step), annotates the podspec fallback blocks and CI config, and adds a maintainer-facing CONTRIBUTING section covering the resolution modes, development toggles, and the product-list/pod-dependency sync requirement. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
react-native-test-app cannot build the old architecture with dynamic frameworks: after the prebuilt-core linkage gap and the fmt source compatibility issue, its own DevSupport pod fails to link (undefined facebook::jsi::* symbols) because it under-declares React dependencies for per-pod linking. These are all harness limitations rather than SDK signal, so the old-arch jobs now build with STRIPE_DISABLE_SPM=1 (static libraries, both prebuilts — the configuration master already uses), which also gives the CocoaPods fallback continuous CI coverage. The SPM resolution mechanism is architecture-independent and remains covered by the new-arch jobs. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
CocoaPods globs private_header_files against the entire pod root without intersecting source_files. For a development pod the root is the whole repo, so '**/*.h' also matched the header-store symlinks in example/ios/Pods. Once SPM resolution removes the Stripe pods from the dependency graph, the same install deletes their checkouts, those symlinks dangle, and pod install crashes mapping private headers through realpath (Errno::ENOENT). Scoping the pattern to the subspec's own headers selects the same files without sweeping the repo. Only machines with a pre-SPM Pods directory were affected; CI missed it because the changed Podfile.lock checksum caused a Pods cache miss. Also extends SPM_FINDINGS.md with this failure and a from-scratch implementation checklist. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
The post_integrate block inherited from the SPM prototype branch stripped react-native-test-app's -DENABLE_SINGLE_APP_MODE flag, which dropped the example app into multi-component picker mode: the example screen gets pushed onto a navigation stack and grows a spurious back button that master doesn't have. app.json configures singleApp mode, so keep the flag and launch directly into the example component. Also records the manual runtime validation results (PaymentSheet renders correctly under SPM resolution) in SPM_FINDINGS.md. Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Committed-By-Agent: claude Orbit-Session-Id: 155f17ce-962c-4e65-9f06-d117f8bc9157
Under dynamic frameworks with Hermes enabled, React Native excludes jsi.cpp from React-jsi (the JSI symbol definitions live in hermes-engine's prebuilt dylib per the One Definition Rule), so any pod whose own C++ references JSI must link hermes.framework directly. react-native-test-app's DevSupport pod declares React-jsi but not hermes-engine, which broke old-arch dynamic-framework builds with undefined facebook::jsi::* symbols. Extend the existing DevSupport xcconfig hack to also cover old-arch SPM builds, force-linking just hermes there (the React frameworks already arrive through normal pod dependencies when the core is built from source). Committed-By-Agent: claude Orbit-Session-Id: c161ea21-96c4-456f-b42b-f920cb035486
With the DevSupport hermes fix in place, drop STRIPE_DISABLE_SPM from e2e-build-ios-old-arch so old arch builds with SPM resolution (dynamic frameworks) like the new-arch jobs. That removes the only job exercising the CocoaPods fallback path, so add a build-only build-ios-fallback workflow (new arch + static libraries + registry pods — the closest match to today's real-world default configuration). Also add unit-test-ios-old-arch so the native unit tests run on both architectures. Committed-By-Agent: claude Orbit-Session-Id: c161ea21-96c4-456f-b42b-f920cb035486
Committed-By-Agent: claude Orbit-Session-Id: c161ea21-96c4-456f-b42b-f920cb035486
The job hung at test launch ("test runner hung before establishing
connection"): CI has no Metro server, the unit-test jobs build no JS
bundle, and with neither available the Debug test app's old-arch launch
path never becomes ready for XCTest. react-native-test-app falls back
to an embedded main.ios.jsbundle when the Metro probe fails, so run
_build_js_bundle before pod install, the same sequence the e2e jobs
use. The new-arch job doesn't need this: the bridgeless launch path
tolerates having no bundle at all.
Committed-By-Agent: claude
Orbit-Session-Id: c161ea21-96c4-456f-b42b-f920cb035486
Old-arch iOS CI now validates SPM mode (build, unit tests, Maestro e2e), with a build-only fallback job covering the CocoaPods path. Append validation log entry 7 (the DevSupport hermes fix landing green first iteration, plus the old-arch Debug launch quirk that made the unit-test job need an embedded JS bundle), move the old-arch coverage gap out of Open items, mark the implementation brief completed, and update the risk assessment: the mechanism is now CI-proven on old arch. Committed-By-Agent: claude Orbit-Session-Id: c161ea21-96c4-456f-b42b-f920cb035486
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Motivation
Testing
Documentation
Select one: