diff --git a/example/ios/Podfile b/example/ios/Podfile
index 629ae52aa..ccc91cbdf 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -59,5 +59,13 @@ target 'QuickCryptoExample' do
end
end
+ # fmt 11.0.2 (bundled by React Native 0.81) fails under Xcode 27's clang
+ # consteval checks; C++17 compiles it without consteval.
+ installer.pods_project.targets.select { |t| t.name == 'fmt' }.each do |target|
+ target.build_configurations.each do |config|
+ config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
+ end
+ end
+
end
end
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index 4cc85ff53..c28228376 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -2837,7 +2837,7 @@ SPEC CHECKSUMS:
MMKVCore: 3d16ce9f7d411e135020915fde98a056859a1efa
NitroMmkv: c68bb2c29c154913707bc6e66791b2b30dd723c1
NitroModules: 1dc73273d6e3aee937eec41ef3ed9470804b9884
- QuickCrypto: a720b137bf86089e3ef05abc6184f298fbc2c914
+ QuickCrypto: ff693664d419b708fbb3cb8ec3f860d44b0f0328
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
RCTDeprecation: c4b9e2fd0ab200e3af72b013ed6113187c607077
RCTRequired: e97dd5dafc1db8094e63bc5031e0371f092ae92a
@@ -2909,6 +2909,6 @@ SPEC CHECKSUMS:
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 11c9686a21e2cd82a094a723649d9f4507200fb0
-PODFILE CHECKSUM: fdc825234ea7a57e35b0bf4e2e0e6049b1652015
+PODFILE CHECKSUM: 2b1fa12c2fb50678fff8af81d9e99e04de1f3032
COCOAPODS: 1.15.2
diff --git a/example/ios/QuickCryptoExample/AppDelegate.swift b/example/ios/QuickCryptoExample/AppDelegate.swift
index 40ff82de0..51f9baf80 100644
--- a/example/ios/QuickCryptoExample/AppDelegate.swift
+++ b/example/ios/QuickCryptoExample/AppDelegate.swift
@@ -21,15 +21,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
reactNativeDelegate = delegate
reactNativeFactory = factory
- window = UIWindow(frame: UIScreen.main.bounds)
+ return true
+ }
+}
+
+// iOS 27 terminates apps that have not adopted the UIScene lifecycle.
+class SceneDelegate: UIResponder, UIWindowSceneDelegate {
+ var window: UIWindow?
- factory.startReactNative(
+ func scene(
+ _ scene: UIScene,
+ willConnectTo session: UISceneSession,
+ options connectionOptions: UIScene.ConnectionOptions
+ ) {
+ guard let windowScene = scene as? UIWindowScene,
+ let appDelegate = UIApplication.shared.delegate as? AppDelegate
+ else { return }
+
+ let window = UIWindow(windowScene: windowScene)
+ self.window = window
+ appDelegate.window = window
+
+ appDelegate.reactNativeFactory?.startReactNative(
withModuleName: "QuickCryptoExample",
in: window,
- launchOptions: launchOptions
+ launchOptions: nil
)
-
- return true
}
}
diff --git a/example/ios/QuickCryptoExample/Info.plist b/example/ios/QuickCryptoExample/Info.plist
index 958e5f7be..f6f325c0d 100644
--- a/example/ios/QuickCryptoExample/Info.plist
+++ b/example/ios/QuickCryptoExample/Info.plist
@@ -39,6 +39,23 @@
MaterialCommunityIcons.ttf
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneConfigurationName
+ Default Configuration
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+
+
+
+
UILaunchStoryboardName
LaunchScreen
UIRequiredDeviceCapabilities
diff --git a/example/test/e2e/runner.mjs b/example/test/e2e/runner.mjs
index 014329b94..b325a4d09 100644
--- a/example/test/e2e/runner.mjs
+++ b/example/test/e2e/runner.mjs
@@ -694,9 +694,28 @@ async function runSuite(device, metroPort) {
owned.session,
...selector,
]);
+ // iOS 27 reports a non-interactive full-screen toolbar above the content, so
+ // agent-device refuses the semantic press; a real tap at the frame works.
+ const runAll = (
+ await agent([
+ 'get',
+ 'attrs',
+ 'id="run-all-tests-button"',
+ '--session',
+ owned.session,
+ ...selector,
+ ])
+ ).data?.node;
+ const pressTarget =
+ runAll?.interactionBlocked === 'covered' && runAll.rect
+ ? [
+ String(Math.round(runAll.rect.x + runAll.rect.width / 2)),
+ String(Math.round(runAll.rect.y + runAll.rect.height / 2)),
+ ]
+ : ['id="run-all-tests-button"'];
await agent([
'press',
- 'id="run-all-tests-button"',
+ ...pressTarget,
'--settle',
'--timeout',
'10000',
diff --git a/packages/react-native-quick-crypto/QuickCrypto.podspec b/packages/react-native-quick-crypto/QuickCrypto.podspec
index 8e026e553..d3dad1c60 100644
--- a/packages/react-native-quick-crypto/QuickCrypto.podspec
+++ b/packages/react-native-quick-crypto/QuickCrypto.podspec
@@ -1,6 +1,7 @@
require "json"
require "digest"
require "shellwords"
+require "pathname"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
@@ -203,14 +204,24 @@ Pod::Spec.new do |s|
# Every translation unit calls the renamed OpenSSL symbols. Missing a rename
# is a link error, never a silent bind to a foreign OpenSSL.
- openssl_include = File.join(openssl_dir, "include")
- force_include = "-include \"#{openssl_prefix_header}\""
+ # Real paths expressed relative to the Pods sandbox keep the evaluated spec (and
+ # so the Podfile.lock checksum) identical across checkout locations.
+ pods_relative = lambda do |path|
+ sandbox = defined?(Pod::Config) && Pod::Config.instance.sandbox_root
+ next path unless sandbox
+ sandbox_dir = Pathname.new(sandbox.to_s)
+ real_sandbox = sandbox_dir.exist? ? sandbox_dir.realpath : Pathname.new(File.realpath(sandbox_dir.dirname)).join(sandbox_dir.basename)
+ "$(PODS_ROOT)/" + Pathname.new(File.realpath(path)).relative_path_from(real_sandbox).to_s
+ end
+
+ openssl_include = pods_relative.call(File.join(openssl_dir, "include"))
+ force_include = "-include \"#{pods_relative.call(openssl_prefix_header)}\""
xcconfig["OTHER_CFLAGS"] = "$(inherited) #{force_include}"
xcconfig["OTHER_CPLUSPLUSFLAGS"] = "$(inherited) #{force_include}"
# Add cpp subdirectories to header search paths
cpp_headers = [
- # Absolute path as well as the pod-relative one: in monorepos the podspec is
+ # Real path (relative to $(PODS_ROOT)) as well as the pod-relative one: in monorepos the podspec is
# reached through a symlink but sources resolve to their real paths.
"\"$(PODS_TARGET_SRCROOT)/ios/openssl/include\"",
"\"#{openssl_include}\"",
@@ -228,10 +239,10 @@ Pod::Spec.new do |s|
]
if sodium_enabled
- # Use absolute path from __dir__ which resolves symlinks correctly.
+ # Use the real path from __dir__, which resolves symlinks correctly.
# This is necessary in monorepo setups where the podspec is accessed via symlink
# but the source files are resolved to their real paths during compilation.
- real_sodium_include = File.join(__dir__, "ios", "libsodium-stable", "src", "libsodium", "include")
+ real_sodium_include = pods_relative.call(File.join(__dir__, "ios", "libsodium-stable", "src", "libsodium", "include"))
sodium_headers = [
"\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include\"",
"\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include/sodium\"",