Skip to content

feat(plugin): add iosDependencyManager 'spm' to the Expo config plugin - #424

Open
thomson-t wants to merge 1 commit into
thomson-t/spm-03-spm-core-modefrom
thomson-t/spm-04-expo-spm
Open

thomson-t wants to merge 1 commit into
thomson-t/spm-03-spm-core-modefrom
thomson-t/spm-04-expo-spm

Conversation

@thomson-t

@thomson-t thomson-t commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Why

Expo apps configure this package through its config plugin rather than by editing the Podfile, and Expo regenerates the native iOS project on every clean prebuild. So the opt-in Swift Package Manager mode from the previous pull request is out of reach for them unless the plugin can switch it on. Once this lands, an Expo app sets one option in app.json and gets the mParticle SDK and its kits from Swift Package Manager, with a single copy of each. Apps that don't set it get exactly the project they get today.

Programme

Part of the plan to support Swift Package Manager in this package before the CocoaPods central repository becomes read-only on 2026-12-02 (CocoaPods announcement). This is the fourth of eight pull requests, all merging into the workstation/spm-migration branch, which merges into main once the series is complete, and shipping together in one release; the plan record is internal and cannot be linked here.

What changes

Before: the plugin always adds the mParticle dynamic-framework pre_install hook and one pod line per iosKits entry.

After: a new plugin option, iosDependencyManager, takes 'cocoapods' (the default, unchanged) or 'spm'. With 'spm', the plugin:

  • turns on the Swift Package Manager mode in the generated Podfile and loads the helper by node resolution, so monorepos and hoisted installs work;
  • calls mparticle_spm_post_install in post_install, with one entry per kit;
  • adds no mParticle pods and no pre_install hook.

Two supporting options: iosSdkVersion pins the core SDK exactly, and iosSpmKits lists kits as { url, product, version? }. iosKits names are mapped to their Swift packages (mParticle-Rokt today); any other name fails prebuild with a message that points to iosSpmKits. Values are checked before they are written into the Podfile. Re-running prebuild adds nothing twice, and replaces the helper call when the settings change.

A small helper change: a kit given without a version now gets the core SDK's version, since mParticle kits are released together with the core. The README documents the three options, the helper change, and that switching modes needs expo prebuild --clean. The changelog is generated by the release-draft workflow.

Start reading at applyMParticlePodfileMods in plugin/src/withMParticleIOS.ts. The CocoaPods branch is the previous code, unchanged, moved into this exported function so jest can test it.

Linked work

Depends on: the opt-in Swift Package Manager mode (branch thomson-t/spm-03-spm-core-mode), whose helper this calls; merge that first.
Unblocks: the Swift layer (branch thomson-t/spm-05-swift-rokt-bridge).
Related: #429, later in this series, makes 'spm' the default and maps every kit of the mParticle Apple SDK in iosKits.

Rollout

Path: this merges into workstation/spm-migration, not main, so nothing reaches main or a release until the whole series has merged there and that branch is merged into main. It then ships in the next release.
Feature flags: the plugin option iosDependencyManager, 'cocoapods' by default. An app's developer sets 'spm' and runs npx expo prebuild --clean.
Turning it off: an app sets 'cocoapods' (or removes the option) and runs npx expo prebuild --clean. For the package, reverting this pull request and releasing again removes the option in the next version.
What we watch: this repository's issues, for Expo prebuild errors or duplicate-SDK reports from Expo apps.

Risks

  • Expo apps that don't set the option could get a different Podfile; prevented because the CocoaPods branch is the previous code unchanged, a jest test pins its output, and a real prebuild produced a byte-identical Podfile to the published 3.4.0 plugin; we would see changed pods after upgrading.
  • A value from app.json could inject Ruby into the generated Podfile; prevented because URLs must be https:// with no quotes, and names and versions are limited to letters, digits and ._+-, with a test that a quote is rejected; we would see a prebuild error naming the value.
  • An unmapped iosKits name would silently add nothing in this mode; prevented because prebuild fails with a message naming the kit and iosSpmKits; we would see that message.
  • Switching modes without a clean prebuild leaves the other mode's lines in place; contained because the helper's check then fails pod install, and the README says to prebuild with --clean; we would see that error.
  • The same kit listed in both iosKits and iosSpmKits gets the last entry's version; not addressed, because it is an unlikely misconfiguration; we would see an unexpected kit version.

Risk class: low.

Who

Written by: an automated coding agent (Claude Code), at an engineer's request, following the internal Swift Package Manager migration plan.
Code reviewed before opening: an independent review agent reviewed the change before it was committed; its advisory about switching modes led to the README note.
Design reviewed before opening: the requesting engineer approved the migration plan, which specifies these options and the node-resolved helper path.
Decision this implements: the requesting engineer's approval of the migration plan on 2026-09-28; the record is internal and cannot be linked.
Checked: on 2026-09-28:

  • jest: 33 tests, including 7 new ones for the Podfile changes, all passing.
  • A copy of ExpoTestApp (Expo 57, React Native 0.86.3, New Architecture) in 'spm' mode, both without and with useFrameworks: 'static':
    • expo prebuild --clean linked the core and the Rokt kit as Swift packages, with no mParticle pods;
    • a Release build and an unsigned archive succeeded;
    • the archive holds one copy of each SDK class;
    • embedded placements by name and by tag, and an overlay placement, rendered on an iOS 26.5 simulator (Xcode 27.0).
  • In 'cocoapods' mode, the generated Podfile is byte-identical to the one from the published 3.4.0 plugin.
    Not checked: Xcode 16; Expo's own Swift Package Manager autolinking preview; Objective-C AppDelegate templates in 'spm' mode (Expo 52, below the supported range).

Size

Hand-written: about 410 lines added and 53 removed in 5 files; 163 of the added lines are tests.
Generated: none.

🤖 Generated with Claude Code

@thomson-t
thomson-t added this pull request to stack #427 September 29, 2026 21:25
@thomson-t
thomson-t marked this pull request as ready for review September 30, 2026 13:19
@thomson-t
thomson-t requested a review from a team as a code owner September 30, 2026 13:19
Copilot AI balanced review requested due to automatic review settings September 30, 2026 13:19
@cursor

cursor Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Adds an opt-in configuration option for Expo projects with no breaking changes to existing CocoaPods behavior. Input values are validated to prevent Podfile injection.

Overview
Adds opt-in Swift Package Manager support to the Expo config plugin via a new iosDependencyManager: 'spm' option (defaulting to 'cocoapods').

When 'spm' is selected, the plugin configures the generated Podfile with $RNMParticleUseSPM = true and injects mparticle_spm_post_install during post-install rather than adding CocoaPods dependencies and dynamic framework pre_install hooks. Known kits from iosKits (such as mParticle-Rokt) are mapped to their Swift packages, while extra packages and custom SDK versions can be configured via new iosSpmKits and iosSdkVersion options.

Also updates the mparticle_spm_post_install Ruby helper so kits without an explicit version inherit the core SDK version, and adds unit test coverage for the Podfile modifications.

Reviewed by Cursor Bugbot for commit af231a4. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation is consistent, validated, documented, and adequately covered by targeted tests.

Review effort: Balanced
Findings: None

What changed in this PR

Adds Expo config-plugin support for selecting Swift Package Manager for iOS mParticle dependencies while preserving CocoaPods as the default.

Changes:

  • Adds SPM plugin options, validation, Podfile generation, and idempotent updates.
  • Defaults kit versions to the core SDK version.
  • Adds tests and documentation for configuration and migration.
File Description
README.md Documents Expo SPM options and usage.
plugin/​src/​withMParticleIOS.ts Implements CocoaPods/SPM Podfile configuration.
plugin/​src/​withMParticle.ts Defines the new plugin options and kit type.
js/​__tests__/​plugin-ios-spm.test.ts Tests generation, validation, and idempotency.
ios/​mparticle_spm.rb Applies the core version to unversioned kits.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

With `iosDependencyManager: 'spm'`, the plugin turns on the pod's Swift
Package Manager mode and calls mparticle_spm_post_install in post_install.
It requires the helper through node resolution and skips the dynamic
pre_install hook and the kit pods. iosKits names map to their Swift packages
(mParticle-Rokt today); other kits go in iosSpmKits, and iosSdkVersion pins
the core. Values are validated before they are written into the Podfile.
The default, 'cocoapods', produces exactly the Podfile it did before.

The Podfile edits move into an exported applyMParticlePodfileMods so jest
can cover both modes. The helper now gives a kit without a version the
core's version, since mParticle kits release in lockstep with the core.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants