Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/native-tabs-swift-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-native-bottom-tabs': minor
---

Add iOS Swift Package Manager support
32 changes: 30 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
- name: Setup
uses: ./.github/actions/setup

- name: Check example dependency constraints
run: yarn constraints

- name: Lint files
run: yarn lint

Expand Down Expand Up @@ -73,7 +76,7 @@

- name: Check turborepo cache for Android
run: |
TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status")
TURBO_CACHE_STATUS=$(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).tasks.find(t => t.taskId === 'react-native-bottom-tabs-example#build:android').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand Down Expand Up @@ -133,7 +136,7 @@

- name: Check turborepo cache for iOS
run: |
TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
TURBO_CACHE_STATUS=$(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).tasks.find(t => t.taskId === 'react-native-bottom-tabs-example#build:ios').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand All @@ -153,3 +156,28 @@
run: |
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"

build-ios-swiftpm:
runs-on: macos-26
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- name: Setup
uses: ./.github/actions/setup

- name: Set up SwiftPM integration
run: yarn workspace example-swiftpm spm --yes

- name: Build SwiftPM example for iOS
run: |
xcodebuild \
-project apps/example-swiftpm/ios/ExampleSwiftPM.xcodeproj \
-scheme ExampleSwiftPM \
-configuration Release \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath "$RUNNER_TEMP/example-swiftpm-build" \
ARCHS=arm64 \
CODE_SIGNING_ALLOWED=NO \
build
Comment on lines +160 to +183
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jsconfig.json
# Xcode
#
build/
.build/
*.pbxuser
!default.pbxuser
*.mode1v3
Expand Down
127 changes: 127 additions & 0 deletions .yarn/patches/react-native-gesture-handler-npm-3.2.1-73a74f5c79.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000000000000000000000000000000000000..9655f2e5f4212edb4e93f746087f2897836ec09f
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,105 @@
+// swift-tools-version: 6.0
+// AUTO-SCAFFOLDED by react-native spm scaffold — safe to edit & commit via patch-package.
+// AUTO-SCAFFOLDED-VERSION: 19
+// Cache slot: 0.87.1/dual-flavor
+// Edit the contents below if needed and re-run `npx patch-package <dep-name>`
+// to persist across `npm install`. To regenerate from the podspec, remove
+// this file (or just this marker) and re-run `npx react-native spm scaffold`.
+//
+// Package references are plain relative paths, computed when this file was
+// scaffolded. They stay correct because the file is re-scaffolded per app
+// and cache slot, and any node_modules relayout reinstalls this package
+// (dropping the file) anyway.
+
+import PackageDescription
+
+let package = Package(
+ name: "ReactNativeGestureHandler",
+ platforms: [.iOS(.v15)],
+ products: [
+ .library(name: "ReactNativeGestureHandler", targets: ["ReactNativeGestureHandler"]),
+ ],
+ dependencies: [
+ .package(name: "ReactNative", path: "../../../../xcframeworks"),
+ .package(name: "React-GeneratedCode", path: "../../../ios"),
+ .package(name: "ReactNativeWorklets", path: "../ReactNativeWorklets"),
+ ],
+ targets: [
+ .target(
+ name: "ReactNativeGestureHandler",
+ dependencies: [.product(name: "ReactHeaders", package: "ReactNative"), .product(name: "ReactNativeHeaders", package: "ReactNative"), .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"), .product(name: "ReactAppHeaders", package: "React-GeneratedCode"), .product(name: "ReactNativeWorklets", package: "ReactNativeWorklets")],
+ path: ".",
+ sources: [
+ "apple/Handlers/RNFlingHandler.h",
+ "apple/Handlers/RNFlingHandler.m",
+ "apple/Handlers/RNForceTouchHandler.h",
+ "apple/Handlers/RNForceTouchHandler.m",
+ "apple/Handlers/RNHoverHandler.h",
+ "apple/Handlers/RNHoverHandler.m",
+ "apple/Handlers/RNLongPressHandler.h",
+ "apple/Handlers/RNLongPressHandler.m",
+ "apple/Handlers/RNManualHandler.h",
+ "apple/Handlers/RNManualHandler.m",
+ "apple/Handlers/RNNativeViewHandler.h",
+ "apple/Handlers/RNNativeViewHandler.mm",
+ "apple/Handlers/RNPanHandler.h",
+ "apple/Handlers/RNPanHandler.m",
+ "apple/Handlers/RNPinchHandler.h",
+ "apple/Handlers/RNPinchHandler.m",
+ "apple/Handlers/RNRotationHandler.h",
+ "apple/Handlers/RNRotationHandler.m",
+ "apple/Handlers/RNTapHandler.h",
+ "apple/Handlers/RNTapHandler.m",
+ "apple/RNGHStylusData.h",
+ "apple/RNGHStylusData.m",
+ "apple/RNGHTouchEventType.h",
+ "apple/RNGHUIKit.h",
+ "apple/RNGHVector.h",
+ "apple/RNGHVector.m",
+ "apple/RNGestureHandler.h",
+ "apple/RNGestureHandler.mm",
+ "apple/RNGestureHandlerActionType.h",
+ "apple/RNGestureHandlerButton.h",
+ "apple/RNGestureHandlerButton.mm",
+ "apple/RNGestureHandlerButtonComponentView.h",
+ "apple/RNGestureHandlerButtonComponentView.mm",
+ "apple/RNGestureHandlerDetector.h",
+ "apple/RNGestureHandlerDetector.mm",
+ "apple/RNGestureHandlerDirection.h",
+ "apple/RNGestureHandlerEventHandlerType.h",
+ "apple/RNGestureHandlerEvents.h",
+ "apple/RNGestureHandlerEvents.mm",
+ "apple/RNGestureHandlerManager.h",
+ "apple/RNGestureHandlerManager.mm",
+ "apple/RNGestureHandlerModule.h",
+ "apple/RNGestureHandlerModule.mm",
+ "apple/RNGestureHandlerNativeEventUtils.h",
+ "apple/RNGestureHandlerNativeEventUtils.mm",
+ "apple/RNGestureHandlerPointerEvents.h",
+ "apple/RNGestureHandlerPointerTracker.h",
+ "apple/RNGestureHandlerPointerTracker.mm",
+ "apple/RNGestureHandlerPointerType.h",
+ "apple/RNGestureHandlerRegistry.h",
+ "apple/RNGestureHandlerRegistry.m",
+ "apple/RNGestureHandlerRootViewComponentView.mm",
+ "apple/RNGestureHandlerState.h",
+ "apple/RNManualActivationRecognizer.h",
+ "apple/RNManualActivationRecognizer.m",
+ "apple/RNRootViewGestureRecognizer.h",
+ "apple/RNRootViewGestureRecognizer.m",
+ "shared/runtime/RNGHRuntimeDecorator.cpp",
+ "shared/runtime/RNGHRuntimeDecorator.h",
+ "shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/ComponentDescriptors.h",
+ "shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorComponentDescriptor.h",
+ "shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorShadowNode.cpp",
+ "shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorShadowNode.h",
+ "shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorState.h",
+ ],
+ publicHeadersPath: "apple",
+ cSettings: [.define("REACT_NATIVE_MINOR_VERSION", to: "87"), .define("RNGH_USE_WORKLETS", to: "1"), .headerSearchPath("apple/Handlers"), .headerSearchPath("apple"), .headerSearchPath("shared/runtime"), .headerSearchPath("shared/shadowNodes/react/renderer/components/rngesturehandler_codegen"), .headerSearchPath("."), .unsafeFlags(["-include", "react-native-spm-prefix.h"])],
+ cxxSettings: [.define("REACT_NATIVE_MINOR_VERSION", to: "87"), .define("RNGH_USE_WORKLETS", to: "1"), .headerSearchPath("apple/Handlers"), .headerSearchPath("apple"), .headerSearchPath("shared/runtime"), .headerSearchPath("shared/shadowNodes/react/renderer/components/rngesturehandler_codegen"), .headerSearchPath("."), .unsafeFlags(["-include", "react-native-spm-prefix.h"]), .define("DEBUG", .when(configuration: .debug)), .define("NDEBUG", .when(configuration: .release))],
+ linkerSettings: [.linkedFramework("UIKit"), .linkedFramework("Foundation"), .linkedFramework("CoreGraphics")]
+ ),
+ ],
+ cxxLanguageStandard: .cxx20
+)
diff --git a/react-native-spm-prefix.h b/react-native-spm-prefix.h
new file mode 100644
index 0000000000000000000000000000000000000000..af5cea0557f2f4aa957419f0fc3f250fd55dbaf5
--- /dev/null
+++ b/react-native-spm-prefix.h
@@ -0,0 +1,10 @@
+// AUTO-SCAFFOLDED by react-native spm scaffold — mirrors CocoaPods' default
+// prefix header so ObjC sources that rely on an implicit Foundation/UIKit
+// import compile under SPM (which has no prefix-header mechanism). Safe to
+// delete + regenerate via `npx react-native spm scaffold`.
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#if __has_include(<UIKit/UIKit.h>)
+#import <UIKit/UIKit.h>
+#endif
+#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000000000000000000000000000000000000..7434fc7054313966b52f6ed808eab20544fb87fe
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,73 @@
+// swift-tools-version: 6.0
+// AUTO-SCAFFOLDED by react-native spm scaffold — safe to edit & commit via patch-package.
+// AUTO-SCAFFOLDED-VERSION: 19
+// Cache slot: 0.87.1/dual-flavor
+// Edit the contents below if needed and re-run `npx patch-package <dep-name>`
+// to persist across `npm install`. To regenerate from the podspec, remove
+// this file (or just this marker) and re-run `npx react-native spm scaffold`.
+//
+// Package references are plain relative paths, computed when this file was
+// scaffolded. They stay correct because the file is re-scaffolded per app
+// and cache slot, and any node_modules relayout reinstalls this package
+// (dropping the file) anyway.
+
+import PackageDescription
+
+let package = Package(
+ name: "ReactNativeSafeAreaContext",
+ platforms: [.iOS(.v15)],
+ products: [
+ .library(name: "ReactNativeSafeAreaContext", targets: ["ReactNativeSafeAreaContext"]),
+ ],
+ dependencies: [
+ .package(name: "ReactNative", path: "../../../../xcframeworks"),
+ .package(name: "React-GeneratedCode", path: "../../../ios"),
+ ],
+ targets: [
+ .target(
+ name: "ReactNativeSafeAreaContext",
+ dependencies: [.product(name: "ReactHeaders", package: "ReactNative"), .product(name: "ReactNativeHeaders", package: "ReactNative"), .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"), .product(name: "ReactAppHeaders", package: "React-GeneratedCode")],
+ path: ".",
+ sources: [
+ "common/cpp/react/renderer/components/safeareacontext/RNCSafeAreaViewComponentDescriptor.h",
+ "common/cpp/react/renderer/components/safeareacontext/RNCSafeAreaViewShadowNode.cpp",
+ "common/cpp/react/renderer/components/safeareacontext/RNCSafeAreaViewShadowNode.h",
+ "common/cpp/react/renderer/components/safeareacontext/RNCSafeAreaViewState.cpp",
+ "common/cpp/react/renderer/components/safeareacontext/RNCSafeAreaViewState.h",
+ "ios/Fabric/RNCSafeAreaProviderComponentView.h",
+ "ios/Fabric/RNCSafeAreaProviderComponentView.mm",
+ "ios/Fabric/RNCSafeAreaViewComponentView.h",
+ "ios/Fabric/RNCSafeAreaViewComponentView.mm",
+ "ios/RNCOnInsetsChangeEvent.h",
+ "ios/RNCOnInsetsChangeEvent.m",
+ "ios/RNCSafeAreaContext.h",
+ "ios/RNCSafeAreaContext.mm",
+ "ios/RNCSafeAreaProvider.h",
+ "ios/RNCSafeAreaProvider.m",
+ "ios/RNCSafeAreaProviderManager.h",
+ "ios/RNCSafeAreaProviderManager.m",
+ "ios/RNCSafeAreaShadowView.h",
+ "ios/RNCSafeAreaShadowView.m",
+ "ios/RNCSafeAreaUtils.h",
+ "ios/RNCSafeAreaUtils.m",
+ "ios/RNCSafeAreaView.h",
+ "ios/RNCSafeAreaView.m",
+ "ios/RNCSafeAreaViewEdgeMode.h",
+ "ios/RNCSafeAreaViewEdgeMode.m",
+ "ios/RNCSafeAreaViewEdges.h",
+ "ios/RNCSafeAreaViewEdges.m",
+ "ios/RNCSafeAreaViewLocalData.h",
+ "ios/RNCSafeAreaViewLocalData.m",
+ "ios/RNCSafeAreaViewManager.h",
+ "ios/RNCSafeAreaViewManager.m",
+ "ios/RNCSafeAreaViewMode.h",
+ "ios/RNCSafeAreaViewMode.m",
+ ],
+ publicHeadersPath: "ios",
+ cSettings: [.headerSearchPath("common/cpp"), .headerSearchPath("common/cpp/react/renderer/components/safeareacontext"), .headerSearchPath("ios/Fabric"), .headerSearchPath("ios"), .headerSearchPath("."), .unsafeFlags(["-include", "react-native-spm-prefix.h"])],
+ cxxSettings: [.headerSearchPath("common/cpp"), .headerSearchPath("common/cpp/react/renderer/components/safeareacontext"), .headerSearchPath("ios/Fabric"), .headerSearchPath("ios"), .headerSearchPath("."), .unsafeFlags(["-include", "react-native-spm-prefix.h"]), .define("DEBUG", .when(configuration: .debug)), .define("NDEBUG", .when(configuration: .release))],
+ linkerSettings: [.linkedFramework("UIKit"), .linkedFramework("Foundation"), .linkedFramework("CoreGraphics")]
+ ),
+ ],
+ cxxLanguageStandard: .cxx20
+)
diff --git a/react-native-spm-prefix.h b/react-native-spm-prefix.h
new file mode 100644
index 0000000000000000000000000000000000000000..af5cea0557f2f4aa957419f0fc3f250fd55dbaf5
--- /dev/null
+++ b/react-native-spm-prefix.h
@@ -0,0 +1,10 @@
+// AUTO-SCAFFOLDED by react-native spm scaffold — mirrors CocoaPods' default
+// prefix header so ObjC sources that rely on an implicit Foundation/UIKit
+// import compile under SPM (which has no prefix-header mechanism). Safe to
+// delete + regenerate via `npx react-native spm scaffold`.
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#if __has_include(<UIKit/UIKit.h>)
+#import <UIKit/UIKit.h>
+#endif
+#endif
Loading
Loading