Conversation
PR SummaryMedium Risk Overview Introduces a kit mapping registry ( Reviewed by Cursor Bugbot for commit 466bf61. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2a96b2e. Configure here.
2a96b2e to
afaa4f8
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The tvOS validation is bypassed by autolinking, and RoktSDKPlus is incorrectly accepted in CocoaPods mode.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Makes Swift Package Manager the default source for iOS mParticle SDKs while retaining CocoaPods as a deprecated opt-out.
Changes:
- Adds automatic Swift package linking, validation, and a shared kit catalog.
- Updates the Expo plugin, sample app, and CI for the new default.
- Revises migration and setup documentation.
| File | Description |
|---|---|
ios/mparticle_spm.rb |
Adds installer hooks and package management. |
ios/mparticle_spm_kits.json |
Defines supported Swift package kits. |
react-native-mparticle.podspec |
Enables SPM mode by default. |
plugin/src/withMParticleIOS.ts |
Generates SPM or CocoaPods settings. |
plugin/src/withMParticle.ts |
Updates plugin option documentation. |
js/__tests__/plugin-ios-spm.test.ts |
Tests plugin generation and kit metadata. |
sample/ios/Podfile |
Makes the sample use SPM by default. |
.github/workflows/pull-request.yml |
Selects CocoaPods only for its CI leg. |
README.md |
Documents setup and troubleshooting. |
MIGRATING.md |
Adds migration instructions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
4f5545e to
28d1f59
Compare
nickolas-dimitrakas
left a comment
There was a problem hiding this comment.
Requesting changes. Two small items, then this is good to go.
1. The tvOS guard in check_podfile! can't fire.
In SPM mode the podspec is iOS-only, and React Native's autolinking skips pods that don't support the target's platform (AutolinkingUtils.is_platform_supported? in autolinking.rb). A tvOS target therefore never registers react-native-mparticle. check_podfile! looks for that dependency, so it finds nothing and never raises. A tvOS app that upgrades would silently lose the native module instead of getting the error the PR describes. The description also says a real Podfile with a tvOS target wasn't checked. Please detect tvOS while the podspec is evaluated, or otherwise keep a marker before autolinking filters the spec. Please also add a test against a real tvOS-target Podfile.
2. RoktSDKPlus isn't marked Swift-package-only in mparticle_spm_kits.json.
Without that, the Expo 'cocoapods' path accepts iosKits: ['RoktSDKPlus'] and writes a pod 'RoktSDKPlus' line that can't resolve. Upstream v9.6.1 marks it spm_package_only: true.
Non-blocking:
Pod::Installer.prependoverrides CocoaPods' private methods (resolve_dependencies,validate_targets,run_podfile_post_install_hooks). It's verified on 1.15.2 and 1.16.2, but a note in the README, or a version check, would make a future break easier to spot.readSpmKitTable()is called inside a.filter(), so the JSON is read once per kit. Read it once into a local variable, as the SPM path already does.
be49556 to
94f5284
Compare
|
Thanks, both fixed in 94f5284.
Non-blocking: the kit table is read once, and the README names the hooked CocoaPods methods. |
…ault The mParticle Apple SDK will publish no CocoaPods releases after CocoaPods trunk becomes read-only on 2 December 2026. The mParticle core SDK and its kits now come from Swift Package Manager by default, linked into the app target. React Native and this package still install with CocoaPods. The podspec loads ios/mparticle_spm.rb, which hooks pod install itself, so no Podfile call is needed. Kits are listed by CocoaPods name in $RNMParticleSPMKits and mapped through ios/mparticle_spm_kits.json, which covers every kit of the mParticle Apple SDK. pod install stops with both fixes named when a kit pod or tvOS target is left in. $RNMParticleDisableSPM = true keeps the CocoaPods path, which is deprecated. The Expo config plugin now defaults to 'spm' and reads the same kit table; 'cocoapods' is the opt-out. The sample and CI flip to match. BREAKING CHANGE: an app that declares mParticle kit pods must move them to $RNMParticleSPMKits, or set $RNMParticleDisableSPM = true. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
React Native's autolinking skips any pod whose spec doesn't support a target's platform. In Swift Package Manager mode the podspec declared iOS only, so a tvOS target never received react-native-mparticle, the iOS-only check in MParticleSPM.check_podfile! never matched, and pod install succeeded without the native module. Keep tvOS declared in that mode, so autolinking adds the pod and the check stops pod install with the opt-out instructions, which now also name Expo's iosDependencyManager 'cocoapods'. For that opt-out to work on tvOS, remove the unused SafariServices imports from the Fabric Rokt view. The framework doesn't exist on tvOS, so New Architecture tvOS builds failed to compile; the imports date from 3.x. Also from review: - Mark RoktSDKPlus as supported only from Swift Package Manager. Its pod exists, but the Expo plugin's CocoaPods path links it without the Rokt and payment pods under it, so pod install fails. - Read the kit table once in the Expo plugin's CocoaPods path. - README: name the CocoaPods private methods the install hooks override and the CocoaPods versions they were tested with. CI's Swift Package Manager leg now checks that a tvOS Podfile stops with the iOS-only error, and runs RoktNativeLayoutComponentViewPropsTests, which the test list had missed. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Yarn 1 unpacks a local .tgz dependency into .tmp in its cache, keyed only by the file's path, and reuses that copy on later installs even when the tarball has changed. actions/setup-node restores the yarn cache, and the sample's file:../react-native-mparticle-latest.tgz path is the same in every run, so both sample jobs installed the build of this package that was cached when the cache was saved, not the one `yarn dev:pack` had just built. Remove the cached copy before installing. On this branch the iOS sample job had been running a build from before the Fabric props fix and the tvOS podspec change, so the props test and the tvOS check failed. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
df9591d to
466bf61
Compare


Why
CocoaPods trunk becomes read-only on 2 December 2026 (CocoaPods announcement), and CocoaPods is now deprecated as a way to get the mParticle SDKs. Earlier in this series Swift Package Manager was opt-in, so an app that did nothing would stay on CocoaPods. Once this lands, the iOS mParticle core SDK and its kits come from Swift Package Manager by default. The release is already a breaking major for the placeholder change, so apps take one build change now instead of another major later. The CocoaPods path stays available as a deprecated opt-out.
Programme
Part of the plan to support Swift Package Manager in this package before CocoaPods trunk becomes read-only. This is the eighth pull request in the series merging into the
workstation/spm-migrationbranch, which merges intomainonce the series is complete and ships in one release; the plan record is internal and cannot be linked here.What changes
Before:
$RNMParticleUseSPM = trueturned the mode on, and the Podfile had to callmparticle_spm_post_install(installer, kits: [...])with each kit's package URL. The Expo plugin defaulted to'cocoapods'and knew one kit.After:
$RNMParticleDisableSPM = true. The podspec loadsios/mparticle_spm.rb, which hookspod installitself, so there is no Podfile call to add. The hooks run when the Podfile evaluates the podspec, which React Native'suse_native_modules!does.$RNMParticleSPMKitslists kits by CocoaPods name, or{ url:, product:, version: }for any other kit.$RNMParticleSPMCoreVersionoptionally pins the core. An app with no kits needs no change.ios/mparticle_spm_kits.jsonmaps every kit of the mParticle Apple SDK, 32 in all, to its Swift package. The Ruby helper and the Expo plugin read the same file. Two Kochava kits ship only as Swift packages, andRoktSDKPlusis supported only from Swift Package Manager, so these names are marked and the Expo plugin's CocoaPods path rejects them.RoktSDKPlusalready includes the Rokt kit, so listing both is an error.pod install:'spm'and writes only the settings above.'cocoapods'writes the opt-out and the same pods andpre_installhook as before.SafariServicesimports from the Fabric Rokt view. SafariServices doesn't exist on tvOS, so New Architecture tvOS apps failed to compile.MP_USE_COCOAPODS=1. CI's CocoaPods leg sets it, and both check names are unchanged. The Swift Package Manager leg also checks that a tvOS Podfile stops with the iOS-only error, and both legs now run the Fabric view's props test. Both sample jobs now delete yarn's cached unpacked copy of the packed tarball before installing; yarn 1 reuses it by path, so the samples had been building an old copy of this package.Start reading at
ios/mparticle_spm.rb(theInstallerHooksmodule at the end), then the podspec. Left alone on purpose:use_frameworks!linkages.Linked work
Depends on: placeholder names only (#428, branch
thomson-t/spm-07-remove-placeholder-map) and the pull requests below it in this series; merge those first.Related: the opt-in mode this makes the default (#423) and its Expo plugin option (#424); the earlier attempt that linked the SDK through the pod and was reverted (#308, #309).
Rollout
Path: this merges into
workstation/spm-migration, notmain, so nothing reachesmainor a release until the whole series has merged there and that branch is merged intomain. It then ships in the next release, which is a major version.Feature flags: none. The opt-out is
$RNMParticleDisableSPM = truein the Podfile, or"iosDependencyManager": "cocoapods"for Expo.Turning it off: an app sets the opt-out and restores its kit pods. For the package, reverting this pull request makes Swift Package Manager opt-in again in the next release.
What we watch: this repository's issues, for
[mParticle]errors frompod install, the red box for a duplicate SDK, and kits reported as unknown.Risks
pod installafter upgrading. Not prevented, because this is the intended break. It is mitigated by the error naming both fixes, MIGRATING, and the opt-out. We would see that error in partner reports.pod installand build. If the hooks stopped running, the build would fail with the "not linked into the app target" message. We would see that in CI.pod installstopping with the opt-out instructions. After CocoaPods trunk freezes on 2 December, those apps stay on the last pod versions. We would see tvOS reports in this repository's issues.{ url:, product:, version: }, and a test checks every entry's URL and product. We would see "unknown kit" errors.expo prebuildandpod install, which passed locally. We would see build failures reported from Expo's build service.Risk class: medium, because this changes how every iOS app on the release gets the SDK.
Who
Written by: an automated coding agent (Claude Code), at an engineer's request.
Code reviewed before opening: an independent review agent reviewed the change before it was committed; its advisory about leftover custom kits widened the opt-out warning. The review fixes were reviewed the same way, which moved a podspec comment and narrowed a README line.
Design reviewed before opening: the requesting engineer chose Swift Package Manager by default with an opt-out, a new pull request on top of the series, and every supported kit in the table.
Decision this implements: the engineering decision on 2026-09-30 to make Swift Package Manager the default, after a design review compared this package with another React Native SDK that also defaults to Swift Package Manager; the record is internal and cannot be linked.
Checked: on 2026-09-30, with Xcode 27.0, an iOS 26.5 simulator and CocoaPods 1.15.2:
jest(38 tests),yarn build,yarn build:pluginand trunk.pod installlinked the core and Rokt kit, with no mParticle pods inPodfile.lock. Release build, unsigned archive, and one copy of each SDK class, all in the app binary, with static libraries and withuse_frameworks! :linkage => :dynamic. Embedded by name and overlay placements rendered. One embedded run ended inPlacementFailurefrom the placement service; it rendered on the rerun.useFrameworks: static; both placements rendered, with the same one-offPlacementFailureon one embedded run.pod installstopped with the message; after the three-line migration it linked the packages and archived with one copy of each class.Then on 2026-10-05, after this pull request's review, with Xcode 27.0 and CocoaPods 1.16.2:
platform :tvos): before this fix,pod installsucceeded andPodfile.lockhad noreact-native-mparticle; with it,pod installstops with the iOS-only message. With the opt-out,platform :tvos, '15.6'and the README'spre_installhook,pod installsucceeded and the app built for the tvOS Simulator once theSafariServicesimports were gone. That throwaway app also needed a C++17 setting for React Native's ownfmton Xcode 27.pod installfailed because the Rokt and payment pods under it are statically linked.pod installlinked the same two packages; the props, sizing, Swift-layer and duplicate-SDK test classes passed (8 tests).jest(39 tests).Not checked: Expo's hosted builds; tvOS at runtime; physical devices. The sample's unit tests run in CI, in both legs.
Size
Hand-written: about 530 lines added and 325 removed in 11 files; 124 added and 64 removed of them in tests, and about 125 in docs.
Generated:
ios/mparticle_spm_kits.json(138 lines), extracted from the mParticle Apple SDK repository.🤖 Generated with Claude Code