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
107 changes: 99 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ jobs:

- 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=$(node -p "($(yarn turbo run build:android --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand Down Expand Up @@ -251,7 +251,7 @@ jobs:
env:
JAVA_OPTS: '-XX:MaxHeapSize=6g'
run: |
yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}"
yarn turbo run build:android --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}"

- name: Verify 16KB page alignment
run: bash scripts/check-16kb.sh
Expand Down Expand Up @@ -319,7 +319,7 @@ jobs:

- name: Check turborepo cache for Android (zig)
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=$(node -p "($(yarn turbo run build:android --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand Down Expand Up @@ -361,7 +361,7 @@ jobs:
env:
JAVA_OPTS: '-XX:MaxHeapSize=6g'
run: |
yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}"
yarn turbo run build:android --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}"

- name: Verify 16KB page alignment (zig)
run: bash scripts/check-16kb.sh
Expand Down Expand Up @@ -392,7 +392,7 @@ jobs:

- 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=$(node -p "($(yarn turbo run build:ios --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand All @@ -414,7 +414,98 @@ jobs:

- name: Build example for iOS
run: |
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
yarn turbo run build:ios --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}"

build-android-rn87:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

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

- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: zulu
java-version: 17

- name: Accept Android SDK licenses
run: yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null || true

- name: Cache Gradle
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-rn87-${{ hashFiles('examples/ExampleSpm/android/gradle/wrapper/gradle-wrapper.properties', 'yarn.lock') }}
restore-keys: |
${{ runner.os }}-gradle-rn87-
${{ runner.os }}-gradle-

- name: Build RN 0.87 example for Android
env:
JAVA_OPTS: '-XX:MaxHeapSize=6g'
run: yarn example:spm build:android

- name: Verify benchmark TurboModule registration
run: |
grep -Fq 'add(BenchmarkFilePackage())' examples/ExampleSpm/android/app/src/main/java/com/examplespm/MainApplication.kt
grep -Fq ': NativeBenchmarkFileSpec' examples/ExampleSpm/android/app/src/main/java/com/examplespm/BenchmarkFileModule.kt

build-ios-spm-rn87:
runs-on: macos-latest

env:
XCODE_VERSION: latest-stable

steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

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

- name: Use appropriate Xcode version
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
with:
xcode-version: ${{ env.XCODE_VERSION }}

- name: Cache React Native SwiftPM artifacts
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/Library/Caches/ReactNative/spm-artifacts
key: ${{ runner.os }}-react-native-spm-${{ hashFiles('examples/ExampleSpm/package.json', 'Package.swift', 'yarn.lock', '.yarn/patches/**') }}
restore-keys: |
${{ runner.os }}-react-native-spm-

- name: Generate the podless SwiftPM project
run: |
yarn example:spm spm:setup
test ! -d examples/ExampleSpm/ios/Pods

- name: Verify benchmark TurboModule registration
run: |
grep -q '@"BenchmarkFile": @"BenchmarkFileModule"' examples/ExampleSpm/ios/build/generated/ios/ReactCodegen/RCTModuleProviders.mm

- name: Build RN 0.87 example for iOS with SwiftPM
run: |
IOS_BUILD_LOG="$RUNNER_TEMP/ios-spm-rn87-build.log"
if ! yarn example:spm build:ios 2>&1 | tee "$IOS_BUILD_LOG"; then
grep -n -m 30 -E 'error:|fatal error:' "$IOS_BUILD_LOG" || true
exit 1
fi

- name: Upload SwiftPM build log
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ios-spm-rn87-build-log
path: ${{ runner.temp }}/ios-spm-rn87-build.log
if-no-files-found: ignore

build-ios-zig:
runs-on: macos-latest
Expand Down Expand Up @@ -443,7 +534,7 @@ jobs:

- name: Check turborepo cache for iOS (zig)
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=$(node -p "($(yarn turbo run build:ios --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")

if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
Expand Down Expand Up @@ -473,4 +564,4 @@ jobs:

- name: Build example for iOS (zig)
run: |
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
yarn turbo run build:ios --filter=@preeternal/react-native-file-hash-example --cache-dir="${{ env.TURBO_CACHE_DIR }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000000000000000000000000000000000000..f3381059164fc8a31f0d976d09bc79713417743a
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,65 @@
+// swift-tools-version: 6.0
+
+import PackageDescription
+
+let reactHeaders: [Target.Dependency] = [
+ .product(name: "ReactHeaders", package: "ReactNative"),
+ .product(name: "ReactNativeHeaders", package: "ReactNative"),
+ .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"),
+ .product(name: "ReactAppHeaders", package: "React-GeneratedCode"),
+]
+
+let package = Package(
+ name: "ReactNativeDocumentsPicker",
+ platforms: [.iOS(.v15)],
+ products: [
+ .library(name: "Picker", targets: ["ReactNativeDocumentsPicker"]),
+ ],
+ dependencies: [
+ .package(name: "ReactNative", path: "../../../../xcframeworks"),
+ .package(name: "React-GeneratedCode", path: "../../../ios"),
+ ],
+ targets: [
+ .target(
+ name: "ReactNativeDocumentsPickerSwift",
+ dependencies: reactHeaders,
+ path: "ios/swift",
+ linkerSettings: [
+ .linkedFramework("Foundation"),
+ .linkedFramework("UIKit"),
+ .linkedFramework("UniformTypeIdentifiers"),
+ ]
+ ),
+ .target(
+ name: "ReactNativeDocumentsPicker",
+ dependencies: ["ReactNativeDocumentsPickerSwift"] + reactHeaders,
+ path: "ios",
+ sources: ["RNDocumentPicker.mm"],
+ publicHeadersPath: ".",
+ cSettings: [.headerSearchPath(".")],
+ cxxSettings: [
+ .headerSearchPath("."),
+ .unsafeFlags([
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ "-DFOLLY_CFG_NO_COROUTINES=1",
+ "-DFOLLY_HAVE_CLOCK_GETTIME=1",
+ "-Wno-comma",
+ "-Wno-shorten-64-to-32",
+ "-DRN_FABRIC_ENABLED",
+ "-fcxx-modules",
+ ]),
+ .define("DEBUG", .when(configuration: .debug)),
+ .define("NDEBUG", .when(configuration: .release)),
+ ],
+ linkerSettings: [
+ .linkedFramework("Foundation"),
+ .linkedFramework("UIKit"),
+ .linkedFramework("UniformTypeIdentifiers"),
+ ]
+ ),
+ ],
+ swiftLanguageModes: [.v5],
+ cxxLanguageStandard: .cxx20
+)
diff --git a/ios/RNDocumentPicker.mm b/ios/RNDocumentPicker.mm
index b31f00970609691e01dd571a5b960b02102adc81..69b2653f3e279533803148b08d1797e3de90560b 100644
--- a/ios/RNDocumentPicker.mm
+++ b/ios/RNDocumentPicker.mm
@@ -8,7 +8,9 @@
// if it cannot be found, try cleaning the build folder and Xcode derived data folder

// When using use_frameworks! :linkage => :static in Podfile
-#if __has_include(<react_native_document_picker/react_native_document_picker-Swift.h>)
+#if defined(SWIFT_PACKAGE)
+@import ReactNativeDocumentsPickerSwift;
+#elif __has_include(<react_native_document_picker/react_native_document_picker-Swift.h>)
#import <react_native_document_picker/react_native_document_picker-Swift.h>
#else
#import "react_native_document_picker-Swift.h"
diff --git a/ios/swift/DocPicker.swift b/ios/swift/DocPicker.swift
index a5b5b070c1d62d895f89c19bbf205e2ef7df7dbc..b211cc350981aaf94fd4003573de765e9e93b5d6 100644
--- a/ios/swift/DocPicker.swift
+++ b/ios/swift/DocPicker.swift
@@ -1,6 +1,7 @@
// LICENSE: see License.md in the package root

import Foundation
+import UIKit
import UniformTypeIdentifiers

@objc public class DocPicker: PickerBase {
diff --git a/ios/swift/DocSaver.swift b/ios/swift/DocSaver.swift
index 9d0f0b6bb635ccaeb0f89f55ebc814267e0e492e..1c3103fff37fd23fb1ccafa389fa5ea75aa7537b 100644
--- a/ios/swift/DocSaver.swift
+++ b/ios/swift/DocSaver.swift
@@ -8,6 +8,7 @@
// LICENSE: see License.md in the package root

import Foundation
+import UIKit
import UniformTypeIdentifiers

@objc public class DocSaver: PickerBase {
diff --git a/ios/swift/ModalStyles.swift b/ios/swift/ModalStyles.swift
new file mode 100644
index 0000000000000000000000000000000000000000..1ffcd5a46744a30240dd07d37ae1676698bc3da0
--- /dev/null
+++ b/ios/swift/ModalStyles.swift
@@ -0,0 +1,27 @@
+import UIKit
+
+func documentPickerTransitionStyle(_ value: String) -> UIModalTransitionStyle? {
+ switch value {
+ case "coverVertical": return .coverVertical
+ case "flipHorizontal": return .flipHorizontal
+ case "crossDissolve": return .crossDissolve
+ case "partialCurl": return .partialCurl
+ default: return nil
+ }
+}
+
+func documentPickerPresentationStyle(_ value: String) -> UIModalPresentationStyle? {
+ switch value {
+ case "fullScreen": return .fullScreen
+ case "pageSheet": return .pageSheet
+ case "formSheet": return .formSheet
+ case "currentContext": return .currentContext
+ case "custom": return .custom
+ case "overFullScreen": return .overFullScreen
+ case "overCurrentContext": return .overCurrentContext
+ case "popover": return .popover
+ case "none": return .none
+ case "automatic": return .automatic
+ default: return nil
+ }
+}
diff --git a/ios/swift/PickerBase.swift b/ios/swift/PickerBase.swift
index 05304e17b8de510c06573ea7f341b1985ef480ab..142dc6d19ddaec82aba66a6c89a3708f92385dbf 100644
--- a/ios/swift/PickerBase.swift
+++ b/ios/swift/PickerBase.swift
@@ -8,6 +8,7 @@
// LICENSE: see License.md in the package root

import Foundation
+import UIKit
import UniformTypeIdentifiers
import React

diff --git a/ios/swift/PickerOptions.swift b/ios/swift/PickerOptions.swift
index 98ee79ae80a3224c555c3c9d609bd7d10b15db96..3cdc2fd94cc3eb5e0ac0ffeb41dde73d36bf871c 100644
--- a/ios/swift/PickerOptions.swift
+++ b/ios/swift/PickerOptions.swift
@@ -35,10 +35,10 @@ public struct PickerOptions: Sendable {
self.requestLongTermAccess = requestLongTermAccess

if let transitionStyle = dictionary["transitionStyle"] as? String {
- self.transitionStyle = RCTConvert.uiModalTransitionStyle(transitionStyle)
+ self.transitionStyle = documentPickerTransitionStyle(transitionStyle)
}
if let presentationStyle = dictionary["presentationStyle"] as? String {
- self.presentationStyle = RCTConvert.uiModalPresentationStyle(presentationStyle)
+ self.presentationStyle = documentPickerPresentationStyle(presentationStyle)
}
if let initialDirectoryUri = dictionary["initialDirectoryUri"] as? String, let url = URL(string: initialDirectoryUri) {
self.initialDirectoryUri = url
diff --git a/ios/swift/SaverOptions.swift b/ios/swift/SaverOptions.swift
index b6c4b458d61c07638eb28a36acee9fdfe1103688..7791f9ddd544eac8275de0b0984a71eb559316d8 100644
--- a/ios/swift/SaverOptions.swift
+++ b/ios/swift/SaverOptions.swift
@@ -23,10 +23,10 @@ public struct SaverOptions: Sendable {
self.shouldShowFileExtensions = shouldShowFileExtensions

if let transitionStyle = dictionary["transitionStyle"] as? String {
- self.transitionStyle = RCTConvert.uiModalTransitionStyle(transitionStyle)
+ self.transitionStyle = documentPickerTransitionStyle(transitionStyle)
}
if let presentationStyle = dictionary["presentationStyle"] as? String {
- self.presentationStyle = RCTConvert.uiModalPresentationStyle(presentationStyle)
+ self.presentationStyle = documentPickerPresentationStyle(presentationStyle)
}
if let initialDirectoryUri = dictionary["initialDirectoryUri"] as? String, let url = URL(string: initialDirectoryUri) {
self.initialDirectoryUri = url
Loading
Loading