Conversation
…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) <noreply@anthropic.com>
PR SummaryMedium Risk Overview Introduces automatic Podfile installer hooks and a kit registry ( Updates the Expo config plugin, sample app, CI, and documentation to default to SPM generation, update matrix testing for both SPM and CocoaPods modes, and detail migration steps for bare and Expo React Native projects. Reviewed by Cursor Bugbot for commit 2a96b2e. 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.
|
|
||
| const swiftPackageOnly = (props.iosKits ?? []).filter(kit => | ||
| readSpmKitTable().swiftPackageOnly.includes(kit) | ||
| ); |
There was a problem hiding this comment.
JSON file read repeatedly inside filter callback
Low Severity
readSpmKitTable() is called inside the .filter() callback, so it reads and parses mparticle_spm_kits.json from disk once per kit in iosKits. The SPM path in getSpmSettings correctly reads it once into a local table variable. The cocoapods path here could do the same to avoid redundant I/O and JSON parsing.
Reviewed by Cursor Bugbot for commit 2a96b2e. Configure here.


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, so their pod-style names are marked.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.MP_USE_COCOAPODS=1. CI's CocoaPods leg sets it, and both check names are unchanged.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.{ 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.
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.Not checked: Expo's hosted builds; a real Podfile with a tvOS target; physical devices. The sample's unit tests run in CI, in both legs.
Size
Hand-written: about 500 lines added and 320 removed in 9 files; 121 added and 64 removed of them in tests, and about 120 in docs.
Generated:
ios/mparticle_spm_kits.json(134 lines), extracted from the mParticle Apple SDK repository.🤖 Generated with Claude Code