Skip to content

fix(ios): make the Swift Package Manager opt-in build, launch and archive - #4368

Merged
mfazekas merged 3 commits into
mainfrom
fix/ios-spm-opt-in
Oct 19, 2026
Merged

mfazekas merged 3 commits into
mainfrom
fix/ios-spm-opt-in

Conversation

@mfazekas

@mfazekas mfazekas commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

The opt-in $RNMapboxMapsSwiftPackageManager mode didn't work with static pods. It failed with no such module 'MapboxMaps' because rnmapbox-maps had no include path to the package modules. With the include path added, linking the product into both the pod and the app target produced duplicate symbols. Without the app-target link, the app crashed at launch in dyld, because nothing embedded the dynamic MapboxCommon, MapboxCoreMaps and Turf frameworks. Xcode 26 archives failed with MapboxCommon.xcframework-ios.signature … already exists. With Expo, and with the hook order documented for bare apps, react_native_post_install ran after $RNMapboxMaps.post_install and dropped the package reference.

What changed:

  1. The pod now declares the package with React Native's spm_dependency. That adds the include path and doesn't depend on hook order, and the app target is no longer touched.
  2. The package frameworks are added to the frameworks CocoaPods embeds (ios/rnmapbox_spm.rb). On React Native versions whose spm_dependency embeds package frameworks itself (fix(iOS): embed the dynamic frameworks of spm_dependency Swift packages react/react-native#58781), the pod passes them as embed_frameworks and skips its own entries when the app has an embed script anyway, so they aren't embedded twice.
  3. A script phase removes the duplicate xcframework signatures.
  4. pod install removes the product that earlier versions added to app targets, and logs a warning when it does.
  5. true selects mapbox-maps-ios, with the requirement derived from $RNMapboxMapsVersion. A hash overrides url, requirement or product_name.
  6. The Expo plugin gets a RNMapboxMapsSwiftPackageManager option.

CocoaPods stays the default; nothing changes unless you opt in. Podfile:

$RNMapboxMapsSwiftPackageManager = true
# or { url: '…', requirement: { kind: 'exactVersion', version: '11.23.1' }, product_name: 'MapboxMaps' }

Expo app.json:

["@rnmapbox/maps", { "RNMapboxMapsSwiftPackageManager": true }]

Verified on the RN 0.84 example (Xcode 26.6, iOS 26.5 simulator) with RNMBX_SPM=1 pod install: a Debug simulator launch rendered the map, and an unsigned Release archive succeeded. The archive embeds MapboxCommon, MapboxCoreMaps and Turf once each and defines MapboxMaps.MapView once. With an Expo SDK 54 app, expo prebuild --clean + pod install kept the package reference, and the Release simulator build launched. The default CocoaPods path still runs pod install without changing the app project, and the example still builds. Each failure listed above was first reproduced on main. On RN 0.89.0-nightly-20261018-27e77216e, which includes #58781, the frameworks are embedded once through RN's install_spm_framework, a Debug simulator launch rendered the map, and an unsigned Release archive succeeded.

Checklist

  • I've read CONTRIBUTING.md
  • I updated the doc/other generated code with running yarn generate in the root folder
  • I have tested the new feature on /example app.
    • In V11 mode/ios
    • In New Architecture mode/ios
    • In V11 mode/android
    • In New Architecture mode/android
  • I added/updated a sample - if a new feature was implemented (/example)

Screenshot OR Video

Component to reproduce the issue you're fixing

No component; it's a build setup. Set $RNMapboxMapsSwiftPackageManager = { url: 'https://github.com/mapbox/mapbox-maps-ios.git', requirement: { kind: 'upToNextMinorVersion', minimumVersion: '11.23.1' }, product_name: 'MapboxMaps' } in example/ios/Podfile on main, run pod install and build: it fails with no such module 'MapboxMaps'. On this branch, RNMBX_SPM=1 pod install then builds, launches and archives.

…hive

$RNMapboxMapsSwiftPackageManager failed in several ways with static pods:

- rnmapbox-maps couldn't find the package's modules (no such module 'MapboxMaps');
- the product was linked into both the pod and the app target (duplicate symbols);
- the dynamic MapboxCommon, MapboxCoreMaps and Turf frameworks weren't embedded (dyld crash at launch);
- Xcode 26 archives failed with "MapboxCommon.xcframework-ios.signature already exists";
- react_native_post_install drops every package reference, so a $RNMapboxMaps.post_install that ran
  before it (as the docs and the Expo plugin order it) lost the package.

Use React Native's spm_dependency for the rnmapbox-maps pod, add the package frameworks to the frameworks
CocoaPods embeds, add a script phase that removes the duplicate xcframework signatures, and remove the
product an earlier version added to the app targets. `true` selects mapbox-maps-ios with a requirement
derived from $RNMapboxMapsVersion. The example Podfile enables it with RNMBX_SPM=1.
Writes $RNMapboxMapsSwiftPackageManager into the Podfile, either `true` or the options hash.
… can

react/react-native#58781 makes spm_dependency embed package frameworks
through install_spm_framework, defaulting to the products (MapboxMaps, a
static product). Where it's supported, pass MapboxCommon, MapboxCoreMaps
and Turf as embed_frameworks, and skip our framework_paths_by_config
entries when the app has an embed script anyway (a framework or a dynamic
xcframework), so they aren't embedded twice.
@mfazekas
mfazekas merged commit 4a9152f into main Oct 19, 2026
9 checks passed
@mfazekas
mfazekas deleted the fix/ios-spm-opt-in branch October 19, 2026 03:53

This branch was successfully deployed

1 active deployment
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.

1 participant