|
| 1 | +# SwiftPM (Apple platforms) — Preview |
| 2 | + |
| 3 | +[🏠 Home](../../../../../__docs__/README.md) |
| 4 | + |
| 5 | +> **Preview.** SwiftPM support is an early preview: the commands, flags, |
| 6 | +> generated layout, and distribution model may change in future releases, and it |
| 7 | +> is not yet recommended for production. CocoaPods remains the supported |
| 8 | +> default. |
| 9 | +
|
| 10 | +The scripts in `scripts/spm/` let a React Native iOS app consume React Native |
| 11 | +through **Swift Package Manager** instead of CocoaPods, using prebuilt |
| 12 | +XCFrameworks. Support is opt-in and additive: `npx react-native spm` injects |
| 13 | +package references into the app's existing `.xcodeproj` in place, and `deinit` |
| 14 | +reverses exactly what it injected. |
| 15 | + |
| 16 | +The motivation, staged migration plan, and open questions live in |
| 17 | +[RFC0994](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0994-swift-package-manager-support-for-react-native-ios-projects.md). |
| 18 | +The documents here describe how the implementation actually works. |
| 19 | + |
| 20 | +## 🚀 Usage |
| 21 | + |
| 22 | +```bash |
| 23 | +cd ios |
| 24 | +npx react-native spm # add on first run, update thereafter |
| 25 | +``` |
| 26 | + |
| 27 | +**If any autolinked dependency ships no `Package.swift`, this stops with |
| 28 | +`error: Package.swift is missing for library "<name>"` and exit code 2.** That |
| 29 | +is deliberate — `add` and `update` never scaffold silently, so a missing |
| 30 | +manifest is visible and fixed on purpose. Generate the manifests first, then |
| 31 | +re-run setup: |
| 32 | + |
| 33 | +```bash |
| 34 | +npx react-native spm scaffold # writes Package.swift into node_modules/<dep>/ |
| 35 | +npx react-native spm # then inject as usual |
| 36 | +``` |
| 37 | + |
| 38 | +Because `node_modules` isn't committed, persist each scaffolded manifest with |
| 39 | +`npx patch-package <dep>` and commit the patch — otherwise the same error |
| 40 | +returns on every fresh install and in CI. Better still, contribute the manifest |
| 41 | +upstream. See |
| 42 | +[Community packages without a Package.swift](./spm-scripts.md#community-packages-without-a-packageswift). |
| 43 | + |
| 44 | +See **[spm-scripts.md](./spm-scripts.md)** for the CLI actions and flags, |
| 45 | +CocoaPods migration, brownfield apps, what to commit, fresh clones and CI, and |
| 46 | +troubleshooting. |
| 47 | + |
| 48 | +## 📐 Design |
| 49 | + |
| 50 | +Three documents cover the design, each owning one area: |
| 51 | + |
| 52 | +| Document | Covers | |
| 53 | +| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 54 | +| [spm-scripts.md](./spm-scripts.md) | The tool itself: CLI surface, the six-step pipeline, [every file it creates or modifies](./spm-scripts.md#files-the-tool-touches), the two auto-sync hooks, and how Debug/Release flavor selection works. | |
| 55 | +| [spm-header-paths-contract.md](./spm-header-paths-contract.md) | How headers and package references resolve. The contract is **zero-`-I`**: no header search paths and no `unsafeFlags` in any generated manifest. Also covers remote mode. | |
| 56 | +| [spm-autolinking-plugins.md](./spm-autolinking-plugins.md) | The extension seam for frameworks with their own module system (Expo is the first consumer): discovery, the full context/return contract including `flavoredFrameworks`, `watchPaths` and `scriptPhases`, and failure behavior. | |
| 57 | + |
| 58 | +Two ideas explain most of the architecture: |
| 59 | + |
| 60 | +- **Headers go through SwiftPM; runtime binaries do not.** A `binaryTarget` |
| 61 | + cannot vary by build configuration, but React Native ships flavored binaries |
| 62 | + (a debug `React.framework` carries the dev menu and assertions; release strips |
| 63 | + them). So the package graph vends headers only, and the flavored frameworks |
| 64 | + are linked and embedded through generated Xcode build settings instead. |
| 65 | +- **Generated state is regenerable, and the injection is reversible.** |
| 66 | + Everything under `build/` is gitignored and rebuilt from the app's |
| 67 | + `package.json`; everything written into the `.xcodeproj` is recorded in a |
| 68 | + `.spm-injected.json` marker so `deinit` can undo precisely that. |
| 69 | + |
| 70 | +## 🔗 Relationship with other systems |
| 71 | + |
| 72 | +### Part of |
| 73 | + |
| 74 | +- iOS build system — the alternative to the CocoaPods integration in |
| 75 | + [`scripts/cocoapods/`](../../cocoapods). |
| 76 | + |
| 77 | +### Used by this |
| 78 | + |
| 79 | +- **Prebuilt XCFrameworks** from [`scripts/ios-prebuild/`](../../ios-prebuild) — |
| 80 | + produces the `React`, `ReactNativeDependencies`, `hermes-engine`, and |
| 81 | + headers-only artifacts that these scripts download, stage, and link. |
| 82 | +- **Codegen** (`generate-codegen-artifacts.js`) — its output is installed as a |
| 83 | + local `React-GeneratedCode` package rather than a Pod. |
| 84 | +- **`@react-native-community/cli config`** — supplies the autolinking metadata |
| 85 | + (`autolinking.json`) that the SwiftPM autolinker turns into a `Package.swift`. |
| 86 | + Overridable via `--configCommand`. |
| 87 | + |
| 88 | +### Uses this |
| 89 | + |
| 90 | +- Apps opting into SwiftPM, via the `spm` React Native CLI command. |
| 91 | +- Frameworks layering their own module system on top of React Native, via |
| 92 | + [autolinking plugins](./spm-autolinking-plugins.md). |
0 commit comments