Skip to content

Commit 1b3cf55

Browse files
Fix ARcore dep, iOS deployment (#732)
* Fix hardcoded ARCore AAR path to honor resolutionStrategy.force The -DARCORE_LIBPATH cmake argument was hardcoded to core-1.22.0.aar in Modules/@babylonjs/react-native/android/build.gradle. If a consumer project applies a resolutionStrategy.force on com.google.ar:core (for example to resolve a duplicate-class conflict between core:1.22.0 and installreferrer:2.2 by forcing core:1.26.0), Gradle extracts the AAR into core-1.26.0.aar/jni while the native build still looks for core-1.22.0.aar/jni, failing with: 'libarcore_sdk_c.so missing and no known rule to make it'. Resolve the actual extracted AAR via configurations.extractLibs and rewrite the -DARCORE_LIBPATH cmake argument to match the resolved version, with a graceful fallback to core-1.22.0.aar if resolution fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Allow consumer to override iOS deployment target for generated Xcode project ios/CMakeLists.txt hardcoded the iOS deployment target to 12 in two places: - set(DEPLOYMENT_TARGET "12" CACHE STRING "") (line 12, consumed by the leetal/ios-cmake toolchain to set CMAKE_OSX_DEPLOYMENT_TARGET) - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 12.0 on the BabylonNative target Xcode 26's Clang crashes compiling DeviceImpl_iOS.mm against iOS 12, so projects targeting iOS 16+ had to patch the deployment target from their Podfile post_install hook. Plumb a new BABYLON_IOS_DEPLOYMENT_TARGET environment variable from postinstall.js into the CMake invocation (as -DDEPLOYMENT_TARGET=<value>) and have CMakeLists.txt honour, in order: an explicit -DDEPLOYMENT_TARGET=, the BABYLON_IOS_DEPLOYMENT_TARGET env var, then the historical 12 default. Both DEPLOYMENT_TARGET and XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET now use the resolved value, so the generated ReactNativeBabylon.xcodeproj matches the consuming app's Podfile platform :ios setting without manual patching. Documented in README.md alongside BABYLON_NO_CMAKE_POSTINSTALL and BABYLON_USE_SYSTEM_CMAKE. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bump iOS minimum/default deployment target from 12 to 16 iOS 12 is no longer a viable minimum: Xcode 26's Clang crashes while compiling DeviceImpl_iOS.mm against the iOS 12 SDK, so consumers were forced to override the deployment target via Podfile post_install or via the BABYLON_IOS_DEPLOYMENT_TARGET env var introduced in the previous commit. Bump the default everywhere so unmodified consumer projects work out of the box on Xcode 26+: - ios/CMakeLists.txt: DEPLOYMENT_TARGET default 12 -> 16 (still overridable via -DDEPLOYMENT_TARGET= or BABYLON_IOS_DEPLOYMENT_TARGET). - react-native-babylon.podspec: s.platforms ios 12.0 -> 16.0 so CocoaPods enforces the new minimum on consuming apps. - postinstall.js: update comment to reflect the new default. - README.md: update iOS configuration section and the BABYLON_IOS_DEPLOYMENT_TARGET docs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make com.google.ar:core version configurable via ext.arcoreVersion Both the implementation and �xtractLibs dependency declarations hardcoded com.google.ar:core:1.22.0. In practice this is harmless because Gradle's normal conflict resolution and any consumer-side resolutionStrategy.force on com.google.ar:core override the declared version, but it forced every consumer that wants a newer ARCore (e.g. to resolve the duplicate-class conflict between core:1.22 and installreferrer:2.2 requiring core:1.26+) to add a resolutionStrategy.force AND remember to keep the native build's ARCORE_LIBPATH in sync. Expose the ARCore version as a Gradle ext property using the existing safeExtGet helper, defaulting to 1.22.0 for backwards compatibility: ext.arcoreVersion = '1.26.0' // in the consumer's root build.gradle Use the variable in both implementation and �xtractLibs, in the cmake ARCORE_LIBPATH default, and in the dynamic-resolution fallback. The dynamic resolution (added previously) still picks up the actually-extracted AAR when a resolutionStrategy.force overrides the declared version, so both override mechanisms continue to work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Slim ARCore AAR resolution to match proposed pattern Drop the defensive scaffolding (try/catch, group filter, manual index loop with not-found fallback, status logger.warn) and use List.replaceAll for the cmake-args mutation. Behaviour is unchanged: still resolves the extractLibs configuration after the dependencies block (necessary because the android { } block evaluates cmake.arguments before the dependencies are declared further down in the script) and rewrites -DARCORE_LIBPATH to match the actually-extracted AAR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bump Playground iOS deployment target to 16.0 The @babylonjs/react-native podspec declares an iOS 16 minimum (matching the CMake-generated framework's default deployment target). The test app's Podfile relied on react-native-test-app's lower default, which caused 'pod install' to reject the local pod with Specs satisfying the react-native-babylon dependency were found, but they required a higher minimum deployment target.' Set the Podfile's platform explicitly to keep CI's Pods install in sync with the pod's minimum. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9542c30 commit 1b3cf55

6 files changed

Lines changed: 76 additions & 9 deletions

File tree

Apps/Playground/ios/Podfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
require_relative '../node_modules/react-native-test-app/test_app'
22
require_relative '../node_modules/react-native-permissions/scripts/setup'
33

4+
# Match the @babylonjs/react-native pod's iOS 16 minimum (required for Xcode 26
5+
# builds, where the CMake-generated framework targets iOS 16 by default).
6+
platform :ios, '16.0'
7+
48
workspace 'Playground.xcworkspace'
59

610
# react-native-permissions

Modules/@babylonjs/react-native/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The minimum Android SDK version is 21. This must be set as `minSdkVersion` in th
1616

1717
### iOS Configuration
1818

19-
The minimum deployment target version is 12. This must be set as `iOS Deployment Target` in the consuming project's `project.pbxproj`, and must also be set as `platform` in the consuming project's `Podfile`.
19+
The minimum deployment target version is 16. This must be set as `iOS Deployment Target` in the consuming project's `project.pbxproj`, and must also be set as `platform` in the consuming project's `Podfile`.
2020
Make sure `pod install` is called from the ios folder after npm install.
2121

2222
#### Workspace
@@ -39,6 +39,12 @@ To use the system cmake (e.g. a Homebrew or system install) instead of the cmake
3939
export BABYLON_USE_SYSTEM_CMAKE=1
4040
```
4141

42+
To override the iOS deployment target used by the generated `ReactNativeBabylon.xcodeproj` (defaults to `16.0`), set this variable before running `npm install` so it matches your app's Podfile `platform :ios` value:
43+
```
44+
export BABYLON_IOS_DEPLOYMENT_TARGET=16.0
45+
```
46+
The previous default of iOS 12 caused Xcode 26's Clang to crash while compiling `DeviceImpl_iOS.mm`; the default is now `16.0` and this variable lets you raise it further (or, at your own risk, lower it) without patching the deployment target from a Podfile `post_install` hook.
47+
4248
### Plugins selection
4349

4450
Plugins can be disabled at build time. They are all enabled by default and disabling is done with environment variables:

Modules/@babylonjs/react-native/android/build.gradle

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ def graphics_api = safeExtGet('GRAPHICS_API', "OpenGL")
6666
def rootBuildDir = "${rootProject.rootDir}/../Build/Android"
6767
def extractedLibDir = "${rootBuildDir}/lib"
6868

69+
// ARCore version. Consumers can override by setting ext.arcoreVersion in their
70+
// root build.gradle (e.g. `ext.arcoreVersion = '1.26.0'` to resolve the
71+
// duplicate-class conflict between com.google.ar:core:1.22 and
72+
// com.android.installreferrer:installreferrer:2.2). A consumer's
73+
// resolutionStrategy.force on com.google.ar:core also wins over this value,
74+
// in which case the dynamic ARCORE_LIBPATH resolution below still picks up
75+
// the actually-extracted AAR.
76+
def arcoreVersion = safeExtGet('arcoreVersion', '1.22.0')
77+
6978
def BABYLON_NATIVE_PLUGIN_NATIVECAMERA = System.getenv("BABYLON_NATIVE_PLUGIN_NATIVECAMERA") != "0"
7079
def BABYLON_NATIVE_PLUGIN_NATIVEXR = System.getenv("BABYLON_NATIVE_PLUGIN_NATIVEXR") != "0"
7180

@@ -168,10 +177,17 @@ android {
168177
cmake {
169178
cppFlags "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID"
170179
abiFilters (*reactNativeArchitectures())
180+
// NOTE: -DARCORE_LIBPATH below points at the AAR matching the
181+
// declared `arcoreVersion` (see top of this file). The actual
182+
// resolved ARCore version may differ (consumer
183+
// resolutionStrategy.force, dependency conflict resolution),
184+
// so the argument is rewritten further down in this script
185+
// (search for "arcoreAarFileName") to point at the AAR that
186+
// Gradle actually extracted.
171187
arguments "-DANDROID_STL=c++_shared",
172188
"-DGRAPHICS_API=${graphics_api}",
173189
"-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
174-
"-DARCORE_LIBPATH=${extractedLibDir}/core-1.22.0.aar/jni",
190+
"-DARCORE_LIBPATH=${extractedLibDir}/core-${arcoreVersion}.aar/jni",
175191
"-DREACTNATIVE_DIR=${rootDir}/../node_modules/react-native/",
176192
"-DBABYLON_NATIVE_PLUGIN_NATIVECAMERA=${BABYLON_NATIVE_PLUGIN_NATIVECAMERA ? '1' : '0'}",
177193
"-DBABYLON_NATIVE_PLUGIN_NATIVEXR=${BABYLON_NATIVE_PLUGIN_NATIVEXR ? '1' : '0'}",
@@ -286,9 +302,9 @@ repositories {
286302
dependencies {
287303
//noinspection GradleDynamicVersion
288304
implementation 'com.facebook.react:react-native:+' // From node_modules
289-
implementation 'com.google.ar:core:1.22.0'
305+
implementation "com.google.ar:core:${arcoreVersion}"
290306

291-
extractLibs 'com.google.ar:core:1.22.0'
307+
extractLibs "com.google.ar:core:${arcoreVersion}"
292308

293309
if (REACT_NATIVE_VERSION < 71) {
294310
logger.warn("BabylonReactNative: Extracting files from AAR (pre RN 0.71)")
@@ -388,6 +404,19 @@ def nativeBuildDependsOn(dependsOnTask, variant) {
388404
buildTasks.forEach { task -> task.dependsOn(dependsOnTask) }
389405
}
390406

407+
// Resolve the actual ARCore AAR name. A consumer project may override
408+
// `ext.arcoreVersion` or apply a resolutionStrategy.force to com.google.ar:core
409+
// (e.g. to resolve a conflict with installreferrer 2.2 that requires
410+
// com.google.ar:core 1.26+). Gradle extracts the AAR into a folder named after
411+
// the *resolved* artifact (core-<version>.aar), so the native build's
412+
// -DARCORE_LIBPATH argument must match that resolved name rather than the
413+
// version literal declared in the dependencies block.
414+
def arcoreAar = configurations.extractLibs.resolvedConfiguration.resolvedArtifacts.find { it.name == 'core' }
415+
def arcoreAarName = arcoreAar ? "${arcoreAar.name}-${arcoreAar.moduleVersion.id.version}.aar" : "core-${arcoreVersion}.aar"
416+
android.defaultConfig.externalNativeBuild.cmake.arguments.replaceAll {
417+
it.toString().startsWith('-DARCORE_LIBPATH=') ? "-DARCORE_LIBPATH=${extractedLibDir}/${arcoreAarName}/jni".toString() : it
418+
}
419+
391420
configurations.extractLibs.files.each { file ->
392421
copy {
393422
from zipTree(file)

Modules/@babylonjs/react-native/ios/CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,23 @@ FetchContent_Declare(ios-cmake
99
FetchContent_MakeAvailable(ios-cmake)
1010
set(CMAKE_TOOLCHAIN_FILE "${ios-cmake_SOURCE_DIR}/ios.toolchain.cmake" CACHE PATH "")
1111
set(PLATFORM "OS64COMBINED" CACHE STRING "")
12-
set(DEPLOYMENT_TARGET "12" CACHE STRING "")
12+
13+
# Allow the consuming project to override the iOS deployment target used when
14+
# generating the Xcode project. Resolution order:
15+
# 1. -DDEPLOYMENT_TARGET=<x> on the cmake command line (highest priority)
16+
# 2. BABYLON_IOS_DEPLOYMENT_TARGET environment variable (forwarded by
17+
# postinstall.js so consumers can set it before `npm install`)
18+
# 3. 16.0 (default). iOS 12 used to be the default, but it is known to crash
19+
# Xcode 26's Clang while compiling DeviceImpl_iOS.mm; iOS 16 is now the
20+
# supported minimum.
21+
if(NOT DEFINED DEPLOYMENT_TARGET OR "${DEPLOYMENT_TARGET}" STREQUAL "")
22+
if(DEFINED ENV{BABYLON_IOS_DEPLOYMENT_TARGET} AND NOT "$ENV{BABYLON_IOS_DEPLOYMENT_TARGET}" STREQUAL "")
23+
set(DEPLOYMENT_TARGET "$ENV{BABYLON_IOS_DEPLOYMENT_TARGET}" CACHE STRING "iOS deployment target")
24+
else()
25+
set(DEPLOYMENT_TARGET "16" CACHE STRING "iOS deployment target")
26+
endif()
27+
endif()
28+
message(STATUS "BabylonReactNative iOS DEPLOYMENT_TARGET: ${DEPLOYMENT_TARGET}")
1329
set(ENABLE_ARC OFF CACHE STRING "Enables or disables ARC support.")
1430
set(ENABLE_PCH OFF CACHE STRING "Enables or disables precompiled headers.")
1531
set(CMAKE_XCODE_GENERATE_SCHEME ON)
@@ -91,7 +107,7 @@ target_link_libraries(BabylonNative
91107
# TODO: For some reason these don't work, so we specify these in the CMake command line args.
92108
set_target_properties(BabylonNative PROPERTIES
93109
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC NO
94-
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 12.0
110+
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}
95111
XCODE_ATTRIBUTE_ENABLE_BITCODE YES
96112
XCODE_GENERATE_SCHEME ON
97113
)

Modules/@babylonjs/react-native/postinstall.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,23 @@ function getCmakeExecutable() {
2424
function iosCMake() {
2525
const { spawn } = require('child_process');
2626

27-
const cmake = spawn(getCmakeExecutable(), [
27+
const cmakeArgs = [
2828
'-S', path.join(__dirname, 'ios'),
2929
'-B', path.join(__dirname, 'Build/iOS'),
3030
'-G', 'Xcode',
31-
], { stdio: 'inherit', cwd: __dirname });
31+
];
32+
33+
// Allow the consuming project to override the iOS deployment target used
34+
// when generating the Xcode project. The CMakeLists.txt default is 16.0
35+
// (iOS 12 used to be the default but is known to crash Xcode 26's Clang
36+
// when compiling DeviceImpl_iOS.mm); set this if you need a different
37+
// minimum to match your Podfile `platform :ios` value.
38+
const deploymentTarget = process.env.BABYLON_IOS_DEPLOYMENT_TARGET;
39+
if (deploymentTarget && deploymentTarget.trim() !== '') {
40+
cmakeArgs.push(`-DDEPLOYMENT_TARGET=${deploymentTarget.trim()}`);
41+
}
42+
43+
const cmake = spawn(getCmakeExecutable(), cmakeArgs, { stdio: 'inherit', cwd: __dirname });
3244

3345
cmake.on('exit', code => {
3446
if (code !== 0) {

Modules/@babylonjs/react-native/react-native-babylon.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Pod::Spec.new do |s|
5454
s.license = package["license"]
5555
s.authors = package["author"]
5656

57-
s.platforms = { :ios => "12.0" }
57+
s.platforms = { :ios => "16.0" }
5858
s.source = { :git => package["repository"]["url"], :tag => s.version }
5959

6060
s.source_files = "ios/*.{h,m,mm}"

0 commit comments

Comments
 (0)