From 6dc01dad09c6ee2ac6793db1b11cb98faada9c3b Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Wed, 14 Aug 2024 05:07:56 -0700 Subject: [PATCH] Do not depend on OSS SoLoader anymore (#45873) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45873 I'm removing the Gradle dependency on OSS SoLoader and stubbing it with our own implementation. This will allow us to implement merging of further .so libraries and As Fresco also depends on SoLoader, I had to stub the `NativeLoader` dependency as well. Changelog: [Android] [Breaking] - Do not depend on OSS SoLoader anymore and do not expose Fresco `api` dependency. Reviewed By: mdvacca Differential Revision: D60652007 fbshipit-source-id: 6e70a5c37ba9337fbe8772e192b886ba4693c7f1 --- .../ReactAndroid/build.gradle.kts | 13 +++-- .../hermes-engine/build.gradle.kts | 3 +- .../react-native/gradle/libs.versions.toml | 2 - packages/react-native/package.json | 1 + .../com/facebook/soloader/DoNotOptimize.kt | 10 ++++ .../java/com/facebook/soloader/SoLoader.kt | 55 +++++++++++++++++++ .../soloader/nativeloader/NativeLoader.kt | 28 ++++++++++ .../nativeloader/NativeLoaderDelegate.kt | 23 ++++++++ .../soloader/nativeloader/SystemDelegate.kt | 10 ++++ .../react/uiapp/RNTesterApplication.kt | 4 +- 10 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/DoNotOptimize.kt create mode 100644 packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/SoLoader.kt create mode 100644 packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoader.kt create mode 100644 packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/NativeLoaderDelegate.kt create mode 100644 packages/react-native/sdks/ossonly-soloader/src/main/java/com/facebook/soloader/nativeloader/SystemDelegate.kt 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()