diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 6b894281ab39f1..75373c2e9a4acf 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -693,6 +693,7 @@ android { "src/main/res/views/alert", "src/main/res/views/modal", "src/main/res/views/uimanager")) + kotlin.srcDir(project.file("../sdks/ossonly-soloader/src/main/java")) java.exclude("com/facebook/react/processing") java.exclude("com/facebook/react/module/processing") } @@ -791,6 +792,11 @@ android { tasks.withType().configureEach { exclude("com/facebook/annotationprocessors/**") } dependencies { + implementation(libs.fresco) + implementation(libs.fresco.middleware) + implementation(libs.fresco.imagepipeline.okhttp3) + implementation(libs.fresco.ui.common) + api(libs.androidx.appcompat) api(libs.androidx.appcompat.resources) api(libs.androidx.autofill) @@ -798,12 +804,7 @@ dependencies { api(libs.androidx.tracing) api(libs.fbjni) - api(libs.fresco) - api(libs.fresco.middleware) - api(libs.fresco.imagepipeline.okhttp3) - api(libs.fresco.ui.common) api(libs.infer.annotation) - api(libs.soloader) api(libs.yoga.proguard.annotations) api(libs.jsr305) @@ -824,6 +825,8 @@ dependencies { testImplementation(libs.thoughtworks) } +configurations.all { exclude(group = "com.facebook.soloader") } + react { // TODO: The library name is chosen for parity with Fabric components & iOS // This should be changed to a more generic name, e.g. `ReactCoreSpec`. diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts index 88fa2a87eaa5d0..070a9f2b3771e6 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts @@ -290,7 +290,6 @@ android { dependencies { implementation(libs.fbjni) - implementation(libs.soloader) implementation(libs.yoga.proguard.annotations) implementation(libs.androidx.annotation) } @@ -316,6 +315,8 @@ android { } } +configurations.all { exclude(group = "com.facebook.soloader") } + afterEvaluate { if (!overrideHermesDir) { // If you're not specifying a Hermes Path override, we want to diff --git a/packages/react-native/gradle/libs.versions.toml b/packages/react-native/gradle/libs.versions.toml index bbc7b6221c532e..02795b61df6ea0 100644 --- a/packages/react-native/gradle/libs.versions.toml +++ b/packages/react-native/gradle/libs.versions.toml @@ -29,7 +29,6 @@ nexus-publish = "1.3.0" okhttp = "4.9.2" okio = "2.9.0" robolectric = "4.9.2" -soloader = "0.11.0" xstream = "1.4.20" yoga-proguard-annotations = "1.19.0" # Native Dependencies @@ -56,7 +55,6 @@ fresco-middleware = { module = "com.facebook.fresco:middleware", version.ref = " fresco-imagepipeline-okhttp3 = { module = "com.facebook.fresco:imagepipeline-okhttp3", version.ref = "fresco" } fresco-ui-common = { module = "com.facebook.fresco:ui-common", version.ref = "fresco" } infer-annotation = { module = "com.facebook.infer.annotation:infer-annotation", version.ref = "infer-annotation" } -soloader = { module = "com.facebook.soloader:soloader", version.ref = "soloader" } yoga-proguard-annotations = { module = "com.facebook.yoga:proguard-annotations", version.ref = "yoga-proguard-annotations" } jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" } diff --git a/packages/react-native/package.json b/packages/react-native/package.json index a3d87604d4fe5e..3aaa4f137f9ab4 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -82,6 +82,7 @@ "scripts/react-native-xcode.sh", "sdks/.hermesversion", "sdks/hermes-engine", + "sdks/ossonly-soloader", "sdks/hermesc", "settings.gradle.kts", "src", diff --git a/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/DoNotOptimize.kt b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/DoNotOptimize.kt new file mode 100644 index 00000000000000..cc98d143cdd09a --- /dev/null +++ b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/DoNotOptimize.kt @@ -0,0 +1,10 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.soloader + +public annotation class DoNotOptimize {} diff --git a/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/SoLoader.kt b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/SoLoader.kt new file mode 100644 index 00000000000000..92c315bde72db3 --- /dev/null +++ b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/SoLoader.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +@file:Suppress("UNUSED_EXPRESSION", "ControlFlowWithEmptyBody", "UNUSED_PARAMETER") + +package com.facebook.soloader + +import android.content.Context + +/** + * This class is a stub of SoLoader used ONLY by React Native OSS. + * + * This allows us to do not mutate the SoLoader.init and SoLoader.loadLibrary methods, which are + * used by the React Native, while also allowing us to implement custom JNI_OnLoad calling which + * enables merging of SOs. + */ +public object SoLoader { + + private val loadedLibraries = mutableSetOf() + + private fun mapLibName(input: String) = input + + @Suppress("UNUSED_PARAMETER") + private fun invokeJniOnload(libraryName: String) { + // no-op for now, till we move library to So Merging in OSS + } + + @Deprecated("This method is a no-op and you should not be calling it") + @JvmStatic + public fun init(context: Context, exoPackage: Boolean) { + // Do nothing + } + + @JvmStatic + public fun loadLibrary(libraryName: String): Boolean { + if (libraryName in loadedLibraries) { + return false + } + val mapLibraryName = mapLibName(libraryName) + System.loadLibrary(mapLibraryName) + if (libraryName != mapLibraryName) { + invokeJniOnload(mapLibraryName) + } + return true + } + + @JvmStatic + public fun setInTestMode() { + // Do nothing + } +} diff --git a/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoader.kt b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoader.kt new file mode 100644 index 00000000000000..148976e406339a --- /dev/null +++ b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoader.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.soloader.nativeloader + +/** + * This class is a stub of NativeLoader used ONLY by React Native OSS. + * + * Fresco in OSS depends on NativeLoader, but we don't want to include the real + * NativeLoader/SoLoader in React Native OSS. This stub is used to make Fresco work properly for us. + */ +public object NativeLoader { + + @JvmStatic + public fun loadLibrary(libraryName: String): Boolean { + System.loadLibrary(libraryName) + return true + } + + @JvmStatic public fun isInitialized(): Boolean = true + + @Suppress("UNUSED_PARAMETER") + public fun initIfUninitialized(systemDelegate: SystemDelegate): Unit = Unit +} diff --git a/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoaderDelegate.kt b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoaderDelegate.kt new file mode 100644 index 00000000000000..31d27fcd3a901e --- /dev/null +++ b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoaderDelegate.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.soloader.nativeloader + +/** + * This class is a stub of NativeLoaderDelegate used ONLY by React Native OSS. + * + * Fresco in OSS depends on NativeLoader, but we don't want to include the real + * NativeLoader/SoLoader in React Native OSS. This stub is used to make Fresco work properly for us. + */ +public interface NativeLoaderDelegate { + + public fun loadLibrary(shortName: String?, flags: Int): Boolean + + public fun getLibraryPath(libName: String?): String + + public fun getSoSourcesVersion(): Int +} diff --git a/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/SystemDelegate.kt b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/SystemDelegate.kt new file mode 100644 index 00000000000000..ea8e2a0fa22a98 --- /dev/null +++ b/packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/SystemDelegate.kt @@ -0,0 +1,10 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.soloader.nativeloader + +public class SystemDelegate {} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt index fc380bd2c00775..82511561065f4e 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt @@ -128,7 +128,9 @@ class RNTesterApplication : Application(), ReactApplication { override fun onCreate() { ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik) super.onCreate() - SoLoader.init(this, /* native exopackage */ false) + + // We want the .init() statement to exercise this code when building RNTester with Buck + @Suppress("DEPRECATION") SoLoader.init(this, /* native exopackage */ false) if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { load()