Skip to content

Commit f48b970

Browse files
chrispaderclaude
andcommitted
build(ios)!: build with Swift Package Manager
Nitro V1 only builds iOS through Swift Package Manager. Package.swift manifests now build the library and sqlite-vec. The library reads the app's nitroSQLite settings like the podspec did and adds iosSqliteFlags for custom SQLite definitions, and sqlite-vec registers itself when SwiftPM links it. The podspecs remain so React Native CLI can discover the packages. The example app moves to Swift Package Manager with patched manifests for react-native-screens and the clipboard module, and iOS CI resumes on Xcode 27. BREAKING CHANGE: iOS apps must build with Swift Package Manager and Xcode with Swift 6.4 or newer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 57bff2d commit f48b970

34 files changed

Lines changed: 1779 additions & 3084 deletions

‎.github/ci-paths.json‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,23 @@
132132
"packages/react-native-nitro-sqlite-vec/cpp/**",
133133
"packages/react-native-nitro-sqlite/RNNitroSQLite.podspec",
134134
"packages/react-native-nitro-sqlite-vec/RNNitroSqliteVec.podspec",
135-
"example/Gemfile*",
135+
"packages/react-native-nitro-sqlite/Package.swift",
136+
"packages/react-native-nitro-sqlite-vec/Package.swift",
136137
"bun.lock",
137138
"package.json",
138139
"example/package.json",
139140
"packages/react-native-nitro-sqlite/package.json",
140141
"packages/react-native-nitro-sqlite-vec/package.json",
141142
"patches/react-native-nitro-modules*",
142143
"patches/@react-native-harness*",
144+
"patches/react-native-screens*",
145+
"patches/@react-native-clipboard*",
143146
"example/react-native.config.js",
144147
"packages/react-native-nitro-sqlite/react-native.config.js",
145148
"packages/react-native-nitro-sqlite-vec/react-native.config.js",
146149
"packages/react-native-nitro-sqlite/nitro.json",
147150
"!packages/react-native-nitro-sqlite/src/__tests__/**",
148-
"scripts/test-podspec-threadsafe.rb",
151+
"scripts/sqlite-package-config.test.ts",
149152
"example/index.js",
150153
"example/babel.config*.js",
151154
"example/app.json",

‎.github/workflows/ci.yml‎

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ jobs:
5050
android_configuration: ${{ steps.select.outputs.android_configuration }}
5151
ios: ${{ steps.select.outputs.ios }}
5252
macos: ${{ steps.select.outputs.macos }}
53-
ios_pods: ${{ steps.pods.outputs.ios_pods }}
5453
macos_pods: ${{ steps.pods.outputs.macos_pods }}
5554
steps:
5655
- uses: actions/checkout@v7
@@ -89,7 +88,6 @@ jobs:
8988
name: ci-lockfiles
9089
path: |
9190
bun.lock
92-
example/ios/Podfile.lock
9391
example/macos/Podfile.lock
9492
retention-days: 1
9593
- name: Require committed dependency resolutions
@@ -99,7 +97,7 @@ jobs:
9997
git diff --exit-code -- bun.lock
10098
- name: Select native lockfile checks
10199
id: pods
102-
if: steps.select.outputs.dependencies == 'true' && (steps.select.outputs.ios == 'true' || steps.select.outputs.macos == 'true')
100+
if: steps.select.outputs.dependencies == 'true' && steps.select.outputs.macos == 'true'
103101
run: node scripts/ci-dependencies.ts
104102
env:
105103
CI_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before || github.sha }}
@@ -140,10 +138,9 @@ jobs:
140138
- name: Test C++ database lifecycle and SQLite symbols
141139
if: steps.select.outputs.cpp_tests == 'true'
142140
run: bash scripts/test-cpp.sh
143-
- name: Test SQLite thread-safety pod configuration
144-
# Paused because Nitro V1 doesn't generate the CocoaPods files that the podspec loads.
145-
if: false && steps.select.outputs.ios == 'true'
146-
run: ruby scripts/test-podspec-threadsafe.rb
141+
- name: Test SQLite Swift package configuration
142+
if: steps.select.outputs.ios == 'true'
143+
run: node --test scripts/sqlite-package-config.test.ts
147144
- name: Check documentation
148145
if: steps.select.outputs.docs == 'true'
149146
run: |
@@ -153,15 +150,12 @@ jobs:
153150
lockfiles:
154151
name: Native lockfiles
155152
needs: checks
156-
# Paused because Nitro V1 doesn't support CocoaPods. Remove `false &&` to resume it.
153+
# Paused until Nitro V1 supports React Native macOS. Remove `false &&` to resume it.
157154
if: >-
158155
false &&
159156
github.event_name != 'push' && !github.event.pull_request.draft &&
160-
(needs.checks.outputs.ios_pods == 'true' || needs.checks.outputs.macos_pods == 'true')
157+
needs.checks.outputs.macos_pods == 'true'
161158
uses: ./.github/workflows/update-lockfiles.yml
162-
with:
163-
ios: ${{ needs.checks.outputs.ios_pods == 'true' }}
164-
macos: ${{ needs.checks.outputs.macos_pods == 'true' }}
165159

166160
android:
167161
name: Android
@@ -179,10 +173,7 @@ jobs:
179173
ios:
180174
name: iOS
181175
needs: [checks, lockfiles]
182-
# Paused because Nitro V1 builds iOS with Swift Package Manager, which this workflow doesn't set up yet.
183-
# Remove `false &&` to resume it.
184176
if: >-
185-
false &&
186177
!cancelled() && needs.checks.result == 'success' &&
187178
(needs.lockfiles.result == 'success' || needs.lockfiles.result == 'skipped') &&
188179
github.event_name != 'push' && !github.event.pull_request.draft &&

‎.github/workflows/release.yml‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ jobs:
9494
bun run sync:lockfile
9595
bun run check:lockfile
9696
bun install --frozen-lockfile
97-
# The CocoaPods steps are paused because Nitro V1 doesn't support CocoaPods.
97+
# The macOS steps are paused until Nitro V1 supports React Native macOS.
9898
- uses: ruby/setup-ruby@v1
9999
if: false
100100
with:
@@ -104,11 +104,9 @@ jobs:
104104
- name: Select Xcode
105105
if: false
106106
run: sudo xcode-select -s "/Applications/Xcode_26.5.app/Contents/Developer"
107-
- name: Update iOS and macOS lockfiles
107+
- name: Update macOS lockfile
108108
if: false
109-
run: |
110-
bun example pods
111-
bun example pods:macos
109+
run: bun example pods:macos
112110
- name: Commit lockfiles and optional announcement
113111
run: node scripts/commit-release-lockfiles.ts
114112
env:

‎.github/workflows/test-harness-ios.yml‎

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ permissions:
1212

1313
jobs:
1414
test:
15-
name: iOS integration tests, ${{ matrix.config.name }}, Xcode ${{ matrix.config.xcode }}
16-
runs-on: macos-26
15+
name: iOS integration tests, Xcode ${{ matrix.config.xcode }}
16+
# Nitro V1 requires Swift 6.4, which GitHub provides in its Xcode 27 preview image.
17+
runs-on: xcode-27
1718
timeout-minutes: 40
1819
strategy:
1920
matrix:
20-
config: ${{ fromJSON(inputs.full && '[{"name":"static_frameworks","frameworks":"static","xcode":"26.5"},{"name":"no_frameworks","frameworks":"","xcode":"26.5"},{"name":"static_frameworks","frameworks":"static","xcode":"26.2"}]' || '[{"name":"static_frameworks","frameworks":"static","xcode":"26.5"},{"name":"no_frameworks","frameworks":"","xcode":"26.5"}]') }}
21+
config: ${{ fromJSON(inputs.full && '[{"xcode":"27.0"},{"xcode":"27.1"}]' || '[{"xcode":"27.0"}]') }}
2122
env:
22-
USE_CCACHE: 1
23-
USE_FRAMEWORKS: ${{ matrix.config.frameworks }}
24-
IOS_SIMULATOR_NAME: iPhone 17 Pro
25-
IOS_SIMULATOR_OS: ${{ matrix.config.xcode }}
23+
IOS_SIMULATOR_NAME: iPhone 18 Pro
24+
IOS_SIMULATOR_OS: '27.0'
2625
steps:
2726
- uses: actions/checkout@v7
2827
- uses: actions/download-artifact@v8
@@ -41,7 +40,7 @@ jobs:
4140
uses: hendrikmuhs/ccache-action@v1.2
4241
with:
4342
max-size: 500M
44-
key: ${{ runner.os }}-${{ matrix.config.name }}-ccache-example-ios-xcode${{ matrix.config.xcode }}
43+
key: ${{ runner.os }}-ccache-example-ios-xcode${{ matrix.config.xcode }}
4544
create-symlink: true
4645
- name: Setup ccache behavior
4746
run: |
@@ -50,13 +49,6 @@ jobs:
5049
echo "CCACHE_DEPEND=true" >> $GITHUB_ENV
5150
echo "CCACHE_INODECACHE=true" >> $GITHUB_ENV
5251
53-
- name: Setup Ruby (bundle)
54-
uses: ruby/setup-ruby@v1
55-
with:
56-
ruby-version: 3.3.0
57-
bundler-cache: true
58-
working-directory: example
59-
6052
- name: Select Xcode ${{ matrix.config.xcode }}
6153
run: sudo xcode-select -s "/Applications/Xcode_${{ matrix.config.xcode }}.app/Contents/Developer"
6254

@@ -79,9 +71,9 @@ jobs:
7971
xcrun simctl boot "$simulator_udid"
8072
fi
8173
82-
- name: Install Pods
74+
- name: Generate Swift packages
8375
working-directory: example
84-
run: bun pods
76+
run: bun spm
8577

8678
- name: Build App
8779
working-directory: example/ios
@@ -90,7 +82,7 @@ jobs:
9082
xcodebuild \
9183
CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \
9284
-derivedDataPath build/DerivedData -UseModernBuildSystem=YES \
93-
-workspace NitroSQLiteExample.xcworkspace \
85+
-project NitroSQLiteExample.xcodeproj \
9486
-scheme NitroSQLiteExample \
9587
-sdk iphonesimulator \
9688
-configuration Debug \
@@ -104,6 +96,10 @@ jobs:
10496
timeout-minutes: 10
10597
run: xcrun simctl bootstatus "$IOS_SIMULATOR_UDID" -b
10698

99+
# react-native-harness 1.5.0 fails on Xcode 27, where `simctl appinfo` errors for apps that are not installed.
100+
- name: Install app on the iOS simulator
101+
run: xcrun simctl install "$IOS_SIMULATOR_UDID" example/ios/build/DerivedData/Build/Products/Debug-iphonesimulator/NitroSQLiteExample.app
102+
107103
- name: Run iOS integration tests
108104
uses: callstackincubator/react-native-harness@v1.6.0
109105
env:

‎.github/workflows/update-lockfiles.yml‎

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ name: Check native lockfiles
22

33
on:
44
workflow_call:
5-
inputs:
6-
ios:
7-
type: boolean
8-
default: false
9-
macos:
10-
type: boolean
11-
default: false
125

136
permissions:
147
contents: read
@@ -38,12 +31,7 @@ jobs:
3831
working-directory: example
3932
- name: Select Xcode 26.5
4033
run: sudo xcode-select -s '/Applications/Xcode_26.5.app/Contents/Developer'
41-
- name: Refresh iOS lockfile
42-
if: inputs.ios
43-
working-directory: example
44-
run: bun pods
4534
- name: Refresh macOS lockfile
46-
if: inputs.macos
4735
working-directory: example
4836
run: bun pods:macos
4937
- name: Attach refreshed native lockfiles
@@ -52,17 +40,10 @@ jobs:
5240
with:
5341
name: native-lockfiles
5442
path: |
55-
example/ios/Podfile.lock
5643
example/macos/Podfile.lock
5744
example/Gemfile.lock
5845
retention-days: 1
5946
- name: Require committed native dependency resolutions
60-
env:
61-
CHECK_IOS: ${{ inputs.ios }}
62-
CHECK_MACOS: ${{ inputs.macos }}
6347
run: |
64-
lockfiles=()
65-
if [[ "$CHECK_IOS" == true ]]; then lockfiles+=(example/ios/Podfile.lock); fi
66-
if [[ "$CHECK_MACOS" == true ]]; then lockfiles+=(example/macos/Podfile.lock); fi
67-
ruby scripts/ci-pod-lockfiles.rb "${lockfiles[@]}"
48+
ruby scripts/ci-pod-lockfiles.rb example/macos/Podfile.lock
6849
git diff --exit-code -- example/Gemfile.lock

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ To run the example app on Android:
2424
bun example android
2525
```
2626

27-
To run the example app on iOS:
27+
To run the example app on iOS, generate its Swift packages first. Run this again after changing native dependencies:
2828

2929
```sh
30+
bun example spm
3031
bun example ios
3132
```
3233

@@ -49,7 +50,7 @@ Remember to add tests for your change if possible. Run the unit tests by:
4950
bun test
5051
```
5152

52-
To edit the Objective-C files, open `example/ios/SequelExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-nitro-sqlite`.
53+
To edit the Objective-C++ and C++ files, open `example/ios/NitroSQLiteExample.xcodeproj` in Xcode and find the source files in the `RNNitroSQLite` package.
5354

5455
To edit the Kotlin files, open `example/android` in Android studio and find the source files at `rnnitrosqlite` under `Android`.
5556

‎example/.eslintrc.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module.exports = {
22
root: true,
33
extends: '../config/.eslintrc.js',
4+
// SwiftPM links native packages under ios/build, including this repository's packages.
5+
ignorePatterns: ['ios/build'],
46
parserOptions: {
57
project: true,
68
tsconfigRootDir: __dirname,

‎example/ios/.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
# SPM – auto-generated at build time (do not commit)
3+
Package.resolved
4+
build/generated/
5+
build/xcframeworks/
6+
.build/

0 commit comments

Comments
 (0)