Skip to content

feat(ios): warn in debug builds when two mParticle SDK copies are loaded - #421

Open
thomson-t wants to merge 1 commit into
workstation/spm-migrationfrom
thomson-t/spm-01-duplicate-sdk-warning
Open

thomson-t wants to merge 1 commit into
workstation/spm-migrationfrom
thomson-t/spm-01-duplicate-sdk-warning

Conversation

@thomson-t

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

Copy link
Copy Markdown
Contributor

Why

Some apps get the mParticle SDK from two places at once: the core through CocoaPods, which this package pulls in, and a kit, such as the Rokt kit, added with Swift Package Manager. The app then contains two copies of the SDK. It builds and archives without any warning, then crashes at runtime in ways that are hard to trace back to the cause. Once this lands, a developer running a debug build sees a clear error on screen naming the problem, before the app ever reaches testers. Release builds are unchanged.

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 first 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: a debug build with two copies of the SDK runs until it crashes, for example with unrecognized selector from isKitActive, with only "Class … is implemented in both" lines in the console.

After: in Debug builds only, the first time the RNMParticle module is created, it counts how many images inside the app bundle define MParticle and RoktEmbeddedView. If either is defined more than once, it calls RCTLogError, which shows a red box: "[mParticle] The mParticle SDK is loaded more than once (MParticle x2, RoktEmbeddedView x2). This happens when the SDK comes from both CocoaPods and Swift Package Manager. See README › Swift Package Manager." The check is inside #if DEBUG, so Release builds contain none of it.

The README gains a short "Swift Package Manager" section under iOS setup that explains the error and how to fix it; later pull requests in this series extend it. The changelog is generated by the release-draft workflow.

Start reading at warnIfSDKLoadedTwice in ios/RNMParticle/RNMParticle.mm.

Linked work

Unblocks: the next pull request in this series, which moves the SDK header imports into one private header (branch thomson-t/spm-02-sdk-import-header, stacked on this one).

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. It is live in Debug builds of apps that upgrade.
Feature flags: none.
Turning it off: a published version cannot be recalled. Reverting this pull request and releasing again removes the check in the next version.
What we watch: there is no production dashboard for a client library. After the release, we watch this repository's issues for reports of the red box in apps that have only one copy of the SDK.

Risks

  • A false alarm in an app with one copy of the SDK; prevented because only images inside the app bundle are counted and each class is counted once per image, and a unit test asserts MParticle counts as 1 in the sample's test host; we would see the red box reported by an app with a normal setup.
  • The check slows app start-up; contained because it runs once, in Debug builds only, and scans only the app's own images rather than every system library (scanning all of them took about 57 seconds in testing); we would see a slower first launch in debug.
  • A unit-test bundle that links the SDK statically a second time, on top of the app it tests, gets the red box during tests; not addressed, because that test process really does contain two copies; we would see a red-box log line in that app's test output.
  • An app that mixes the two managers but loads the second copy outside the app bundle is not detected; not addressed, because iOS apps load third-party code only from their own bundle; we would see the crash without the red box.

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.
Design reviewed before opening: the requesting engineer approved the migration plan, which specifies this check.
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, with Xcode 27.0 on an iOS 26.5 simulator, the sample app (React Native 0.84, New Architecture, Debug):

  • the CI test classes plus the new RNMParticleDuplicateSDKTests passed;
  • a normal run showed no red box and no warning in the log;
  • a run with the Rokt kit also added through Swift Package Manager, on top of the pods, showed the red box, with the message above in the log;
  • a Release build contains no trace of the check.
    Not checked: the Old Architecture at runtime. CI, which builds with Xcode 16, passed on this pull request.

Size

Hand-written: about 100 lines added in 5 files (35 of them a test).
Generated: none.

Notes for reviewers

How the count works. objc_copyImageNames lists every loaded image. Only images whose path starts with NSBundle.mainBundle.bundlePath are kept, and objc_copyClassNamesForImage gives each one's classes. Both arrays are freed. The count runs in -init under dispatch_once, because the module is created lazily when JavaScript first uses it, after every linked image has loaded.

Why only MParticle is asserted in the test. The sample test target links this package a second time on top of the app it hosts (see RNMPRoktPlaceholderTests.m), so the wrapper's own classes exist twice there. MParticle lives in the SDK framework, which both share.

CI. The iOS job runs a fixed -only-testing list, so the new test class is added to it.

Evidence. Normal run: no loaded more than once line among about 2,000 app log lines, and the sample screen rendered. Mixed run (Rokt kit 9.6.1 through Swift Package Manager on the app target, core 9.6.1 through pods): the build succeeded silently, stderr had 422 "implemented in both" lines, and the red box showed the message with MParticle x2, RoktEmbeddedView x2.

🤖 Generated with Claude Code

Taking the mParticle core from CocoaPods and a kit from Swift Package
Manager links the SDK twice. The app builds and archives silently, then
crashes at runtime. In Debug builds, RNMParticle now counts the app-bundle
images that define MParticle and RoktEmbeddedView the first time the
module is created, and raises a red box naming the duplicates. Release
builds contain none of it.

Adds an XCTest for the counting helper (and runs it in CI), and a short
README section the message points to.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@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
The duplicate SDK check is wrapped in #if DEBUG macros, ensuring zero runtime impact or overhead in release builds.

Overview
Adds a debug-only runtime check to RNMParticle that detects when multiple copies of the mParticle or Rokt SDKs are loaded in the application bundle. The check inspects loaded bundle images via the Objective-C runtime upon module initialization and triggers RCTLogError if duplicate class definitions like MParticle or RoktEmbeddedView are detected.

Updates documentation with troubleshooting guidance for duplicate SDKs resulting from mixing CocoaPods and Swift Package Manager. Also adds native unit tests (RNMParticleDuplicateSDKTests) and updates the Xcode project and CI test workflow to run them.

Reviewed by Cursor Bugbot for commit 2dedf01. 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 Debug-only detection, tests, CI integration, and documentation are consistent and contain no identified blocking issues.

Review effort: Balanced
Findings: None

What changed in this PR

Adds a Debug-only iOS diagnostic for duplicate mParticle SDK installations.

Changes:

  • Detects duplicate SDK classes and reports them through RCTLogError.
  • Adds unit tests and CI coverage for image counting.
  • Documents the dependency-manager conflict and resolution.
File Description
ios/​RNMParticle/​RNMParticle.mm Implements duplicate SDK detection.
sample/​ios/​MParticleSampleTests/​RNMParticleDuplicateSDKTests.m Tests class-image counting.
sample/​ios/​MParticleSample.xcodeproj/​project.pbxproj Registers the new tests.
.github/​workflows/​pull-request.yml Runs the tests in CI.
README.md Documents SPM conflict resolution.

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

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