diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt index 4ec27e9f559d94..757c80e99e18c1 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt @@ -7,11 +7,10 @@ package com.facebook.react -import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.Variant import com.facebook.react.tasks.BundleHermesCTask -import com.facebook.react.tasks.NativeLibraryAabCleanupTask -import com.facebook.react.tasks.NativeLibraryApkCleanupTask +import com.facebook.react.utils.NdkConfiguratorUtils.configureJsEnginePackagingOptions +import com.facebook.react.utils.NdkConfiguratorUtils.configureNewArchPackagingOptions import com.facebook.react.utils.ProjectUtils.isHermesEnabled import com.facebook.react.utils.detectedCliPath import com.facebook.react.utils.detectedEntryFile @@ -36,16 +35,20 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio // Additional node and packager commandline arguments val cliPath = detectedCliPath(project.projectDir, config) - val enableHermesInProject = project.isHermesEnabled - val enableHermesInThisVariant = + val isHermesEnabledInProject = project.isHermesEnabled + val isHermesEnabledInThisVariant = if (config.enableHermesOnlyInVariants.get().isNotEmpty()) { - config.enableHermesOnlyInVariants.get().contains(variant.name) && enableHermesInProject + config.enableHermesOnlyInVariants.get().contains(variant.name) && isHermesEnabledInProject } else { - enableHermesInProject + isHermesEnabledInProject } val isDebuggableVariant = config.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) } + configureNewArchPackagingOptions(project, variant) + configureJsEnginePackagingOptions( + config, variant, isHermesEnabledInThisVariant, isDebuggableVariant) + if (!isDebuggableVariant) { val bundleTask = tasks.register("createBundle${targetName}JsAndAssets", BundleHermesCTask::class.java) { @@ -59,8 +62,8 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio it.bundleAssetName.set(config.bundleAssetName) it.jsBundleDir.set(jsBundleDir) it.resourcesDir.set(resourcesDir) - it.hermesEnabled.set(enableHermesInThisVariant) - it.minifyEnabled.set(!enableHermesInThisVariant) + it.hermesEnabled.set(isHermesEnabledInThisVariant) + it.minifyEnabled.set(!isHermesEnabledInThisVariant) it.devEnabled.set(false) it.jsIntermediateSourceMapsDir.set(jsIntermediateSourceMapsDir) it.jsSourceMapsDir.set(jsSourceMapsDir) @@ -71,31 +74,4 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio variant.sources.res?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::resourcesDir) variant.sources.assets?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::jsBundleDir) } - - if (config.enableSoCleanup.get()) { - val nativeLibraryApkCleanupTask = - project.tasks.register( - "nativeLibrary${targetName}ApkCleanup", NativeLibraryApkCleanupTask::class.java) { - it.debuggableVariant.set(isDebuggableVariant) - it.enableHermes.set(enableHermesInThisVariant) - } - val nativeLibraryBundleCleanupTask = - project.tasks.register( - "nativeLibrary${targetName}BundleCleanup", NativeLibraryAabCleanupTask::class.java) { - it.debuggableVariant.set(isDebuggableVariant) - it.enableHermes.set(enableHermesInThisVariant) - } - - variant.artifacts - .use(nativeLibraryApkCleanupTask) - .wiredWithDirectories( - NativeLibraryApkCleanupTask::inputApkDirectory, - NativeLibraryApkCleanupTask::outputApkDirectory) - .toTransform(SingleArtifact.APK) - variant.artifacts - .use(nativeLibraryBundleCleanupTask) - .wiredWithFiles( - NativeLibraryAabCleanupTask::inputBundle, NativeLibraryAabCleanupTask::outputBundle) - .toTransform(SingleArtifact.BUNDLE) - } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTask.kt deleted file mode 100644 index 9e46e419d93d59..00000000000000 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTask.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.react.tasks - -import com.facebook.react.utils.SoCleanerUtils -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -abstract class NativeLibraryAabCleanupTask : DefaultTask() { - - @get:InputFile abstract val inputBundle: RegularFileProperty - - @get:OutputFile abstract val outputBundle: RegularFileProperty - - @get:Input abstract val enableHermes: Property - - @get:Input abstract val debuggableVariant: Property - - @TaskAction - fun run() { - val inputBundleFile = inputBundle.get().asFile - val outputBundleFile = outputBundle.get().asFile - SoCleanerUtils.clean( - input = inputBundleFile, - prefix = "base/lib", - enableHermes = enableHermes.get(), - debuggableVariant = debuggableVariant.get()) - inputBundleFile.copyTo(outputBundleFile, overwrite = true) - } -} diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTask.kt deleted file mode 100644 index 8c0064d473933e..00000000000000 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTask.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.react.tasks - -import com.facebook.react.utils.SoCleanerUtils -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction - -abstract class NativeLibraryApkCleanupTask : DefaultTask() { - - @get:InputDirectory abstract val inputApkDirectory: DirectoryProperty - - @get:OutputDirectory abstract val outputApkDirectory: DirectoryProperty - - @get:Input abstract val enableHermes: Property - - @get:Input abstract val debuggableVariant: Property - - @TaskAction - fun run() { - inputApkDirectory.get().asFile.walk().forEach { - if (it.name.endsWith(".apk")) { - SoCleanerUtils.clean( - input = it, - prefix = "lib/", - enableHermes = enableHermes.get(), - debuggableVariant = debuggableVariant.get()) - } - } - } -} diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt index 9bec0e3bc2a9c2..d081afbfcf0284 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt @@ -8,6 +8,7 @@ package com.facebook.react.utils import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.Variant import com.facebook.react.ReactExtension import com.facebook.react.utils.ProjectUtils.isNewArchEnabled import java.io.File @@ -19,83 +20,140 @@ internal object NdkConfiguratorUtils { project.pluginManager.withPlugin("com.android.application") { project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext -> if (!project.isNewArchEnabled) { - // For Old Arch, we set a pickFirst only on libraries that we know are - // clashing with our direct dependencies (FBJNI, Flipper and Hermes). - ext.packagingOptions.jniLibs.pickFirsts.addAll( - listOf( - "**/libfbjni.so", - "**/libc++_shared.so", - )) - } else { - // We enable prefab so users can consume .so/headers from ReactAndroid and hermes-engine - // .aar - ext.buildFeatures.prefab = true - - // We set some packagingOptions { pickFirst ... } for our users for libraries we own. - ext.packagingOptions.jniLibs.pickFirsts.addAll( - listOf( - // Hermes & JSC are provided by AAR dependencies we pre-bundle. - "**/libhermes.so", - "**/libjsc.so", - // This is the .so provided by FBJNI via prefab - "**/libfbjni.so", - // Those are prefab libraries we distribute via ReactAndroid - // Due to a bug in AGP, they fire a warning on console as both the JNI - // and the prefab .so files gets considered. See more on: - "**/libfabricjni.so", - "**/libfolly_runtime.so", - "**/libglog.so", - "**/libjsi.so", - "**/libreact_codegen_rncore.so", - "**/libreact_debug.so", - "**/libreact_nativemodule_core.so", - "**/libreact_newarchdefaults.so", - "**/libreact_render_componentregistry.so", - "**/libreact_render_core.so", - "**/libreact_render_debug.so", - "**/libreact_render_graphics.so", - "**/libreact_render_imagemanager.so", - "**/libreact_render_mapbuffer.so", - "**/librrc_image.so", - "**/librrc_view.so", - "**/libruntimeexecutor.so", - "**/libturbomodulejsijni.so", - "**/libyoga.so", - // AGP will give priority of libc++_shared coming from App modules. - "**/libc++_shared.so", - )) + // For Old Arch, we don't need to setup the NDK + return@finalizeDsl + } + // We enable prefab so users can consume .so/headers from ReactAndroid and hermes-engine + // .aar + ext.buildFeatures.prefab = true - // If the user has not provided a CmakeLists.txt path, let's provide - // the default one from the framework - if (ext.externalNativeBuild.cmake.path == null) { - ext.externalNativeBuild.cmake.path = - File( - extension.reactNativeDir.get().asFile, - "ReactAndroid/cmake-utils/default-app-setup/CMakeLists.txt") - } + // If the user has not provided a CmakeLists.txt path, let's provide + // the default one from the framework + if (ext.externalNativeBuild.cmake.path == null) { + ext.externalNativeBuild.cmake.path = + File( + extension.reactNativeDir.get().asFile, + "ReactAndroid/cmake-utils/default-app-setup/CMakeLists.txt") + } - // Parameters should be provided in an additive manner (do not override what - // the user provided, but allow for sensible defaults). - val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments - if ("-DGENERATED_SRC_DIR" !in cmakeArgs) { - cmakeArgs.add("-DGENERATED_SRC_DIR=${File(project.buildDir, "generated/source")}") - } - if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) { - cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}") - } - if ("-DREACT_ANDROID_DIR" !in cmakeArgs) { - cmakeArgs.add( - "-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}") - } - if ("-DREACT_ANDROID_BUILD_DIR" !in cmakeArgs) { - cmakeArgs.add( - "-DREACT_ANDROID_BUILD_DIR=${extension.reactNativeDir.file("ReactAndroid/build").get().asFile}") - } - if ("-DANDROID_STL" !in cmakeArgs) { - cmakeArgs.add("-DANDROID_STL=c++_shared") - } + // Parameters should be provided in an additive manner (do not override what + // the user provided, but allow for sensible defaults). + val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments + if ("-DGENERATED_SRC_DIR" !in cmakeArgs) { + cmakeArgs.add("-DGENERATED_SRC_DIR=${File(project.buildDir, "generated/source")}") + } + if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) { + cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}") + } + if ("-DREACT_ANDROID_DIR" !in cmakeArgs) { + cmakeArgs.add( + "-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}") } + if ("-DREACT_ANDROID_BUILD_DIR" !in cmakeArgs) { + cmakeArgs.add( + "-DREACT_ANDROID_BUILD_DIR=${ + extension.reactNativeDir.file("ReactAndroid/build").get().asFile + }") + } + if ("-DANDROID_STL" !in cmakeArgs) { + cmakeArgs.add("-DANDROID_STL=c++_shared") + } + } + } + } + + /** + * This method is used to configure the .so Packaging Options for the given variant. It will make + * sure we specify the correct .pickFirsts for all the .so files we are producing or that we're + * aware of as some of our dependencies are pulling them in. + */ + fun configureNewArchPackagingOptions( + project: Project, + variant: Variant, + ) { + if (!project.isNewArchEnabled) { + // For Old Arch, we set a pickFirst only on libraries that we know are + // clashing with our direct dependencies (FBJNI, Flipper and Hermes). + variant.packaging.jniLibs.pickFirsts.addAll( + listOf( + "**/libfbjni.so", + "**/libc++_shared.so", + )) + } else { + // We set some packagingOptions { pickFirst ... } for our users for libraries we own. + variant.packaging.jniLibs.pickFirsts.addAll( + listOf( + // This is the .so provided by FBJNI via prefab + "**/libfbjni.so", + // Those are prefab libraries we distribute via ReactAndroid + // Due to a bug in AGP, they fire a warning on console as both the JNI + // and the prefab .so files gets considered. See more on: + "**/libfabricjni.so", + "**/libfolly_runtime.so", + "**/libglog.so", + "**/libjsi.so", + "**/libreact_codegen_rncore.so", + "**/libreact_debug.so", + "**/libreact_nativemodule_core.so", + "**/libreact_newarchdefaults.so", + "**/libreact_render_componentregistry.so", + "**/libreact_render_core.so", + "**/libreact_render_debug.so", + "**/libreact_render_graphics.so", + "**/libreact_render_imagemanager.so", + "**/libreact_render_mapbuffer.so", + "**/librrc_image.so", + "**/librrc_view.so", + "**/libruntimeexecutor.so", + "**/libturbomodulejsijni.so", + "**/libyoga.so", + // AGP will give priority of libc++_shared coming from App modules. + "**/libc++_shared.so", + )) + } + } + + /** + * This method is used to configure the .so Cleanup for the given variant. It takes care of + * cleaning up the .so files that are not needed for Hermes or JSC, given a specific variant. + */ + fun configureJsEnginePackagingOptions( + config: ReactExtension, + variant: Variant, + hermesEnabled: Boolean, + debuggableVariant: Boolean + ) { + if (config.enableSoCleanup.get()) { + val (excludes, includes) = getPackagingOptionsForVariant(hermesEnabled, debuggableVariant) + variant.packaging.jniLibs.excludes.addAll(excludes) + variant.packaging.jniLibs.pickFirsts.addAll(includes) + } + } + + fun getPackagingOptionsForVariant( + hermesEnabled: Boolean, + debuggableVariant: Boolean + ): Pair, List> { + val excludes = mutableListOf() + val includes = mutableListOf() + if (hermesEnabled) { + excludes.add("**/libjsc.so") + excludes.add("**/libjscexecutor.so") + includes.add("**/libhermes.so") + if (debuggableVariant) { + excludes.add("**/libhermes-executor-release.so") + includes.add("**/libhermes-executor-debug.so") + } else { + excludes.add("**/libhermes-executor-debug.so") + includes.add("**/libhermes-executor-release.so") } + } else { + excludes.add("**/libhermes.so") + excludes.add("**/libhermes-executor-debug.so") + excludes.add("**/libhermes-executor-release.so") + includes.add("**/libjsc.so") + includes.add("**/libjscexecutor.so") } + return excludes to includes } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/SoCleanerUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/SoCleanerUtils.kt deleted file mode 100644 index ece6924d5aab85..00000000000000 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/SoCleanerUtils.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.react.utils - -import java.io.File -import java.net.URI -import java.nio.file.FileSystem -import java.nio.file.FileSystems -import java.nio.file.Files - -internal object SoCleanerUtils { - - private val zipProperties = mapOf("create" to "false") - - private val archs = listOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a") - - fun clean(input: File, prefix: String, enableHermes: Boolean, debuggableVariant: Boolean) { - val zipDisk: URI = URI.create("jar:file:${input.absolutePath}") - FileSystems.newFileSystem(zipDisk, zipProperties).use { zipfs -> - buildList { - if (enableHermes) { - add("libjsc.so") - add("libjscexecutor.so") - if (debuggableVariant) { - add("libhermes-executor-release.so") - } else { - add("libhermes-executor-debug.so") - } - } else { - add("libhermes.so") - add("libhermes-executor-debug.so") - add("libhermes-executor-release.so") - } - } - .forEach { removeSoFiles(zipfs, prefix, archs, it) } - } - } - - fun removeSoFiles( - zipfs: FileSystem, - prefix: String, - archs: List, - libraryToRemove: String - ) { - archs.forEach { arch -> - try { - Files.delete(zipfs.getPath("$prefix/$arch/$libraryToRemove")) - } catch (e: Exception) { - // File was already missing due to ABI split, nothing to do here. - } - } - } -} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTaskTest.kt deleted file mode 100644 index e48cbda67e6cc8..00000000000000 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryAabCleanupTaskTest.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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.react.tasks - -import com.facebook.react.tests.createTestTask -import com.facebook.react.tests.createZip -import java.io.File -import java.net.URI -import java.nio.file.FileSystems -import java.nio.file.Files.exists -import org.gradle.api.tasks.* -import org.junit.Assert.* -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder - -class NativeLibraryAabCleanupTaskTest { - - @get:Rule val tempFolder = TemporaryFolder() - - @Test - fun nativeLibraryAabCleanupTask_withHermesDebug_cleansCorrectly() { - val inputAab = File(tempFolder.root, "input.aab") - val outputAab = File(tempFolder.root, "output.aab") - createZip( - inputAab, - listOf( - "base/lib/x86/libhermes.so", - "base/lib/x86/libhermes-executor-debug.so", - "base/lib/x86/libhermes-executor-release.so", - "base/lib/x86/libjsc.so", - "base/lib/x86/libjscexecutor.so", - )) - val task = - createTestTask { - it.inputBundle.set(inputAab) - it.outputBundle.set(outputAab) - it.enableHermes.set(true) - it.debuggableVariant.set(true) - } - - task.run() - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${inputAab.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertTrue(exists(it.getPath("base/lib/x86/libhermes.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-release.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libjsc.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun nativeLibraryAabCleanupTask_withHermesRelease_cleansCorrectly() { - val inputAab = File(tempFolder.root, "input.aab") - val outputAab = File(tempFolder.root, "output.aab") - createZip( - inputAab, - listOf( - "base/lib/x86/libhermes.so", - "base/lib/x86/libhermes-executor-debug.so", - "base/lib/x86/libhermes-executor-release.so", - "base/lib/x86/libjsc.so", - "base/lib/x86/libjscexecutor.so", - )) - val task = - createTestTask { - it.inputBundle.set(inputAab) - it.outputBundle.set(outputAab) - it.enableHermes.set(true) - it.debuggableVariant.set(false) - } - - task.run() - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${inputAab.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertTrue(exists(it.getPath("base/lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-debug.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libhermes-executor-release.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libjsc.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun nativeLibraryAabCleanupTask_withJscDebug_cleansCorrectly() { - val inputAab = File(tempFolder.root, "input.aab") - val outputAab = File(tempFolder.root, "output.aab") - createZip( - inputAab, - listOf( - "base/lib/x86/libhermes.so", - "base/lib/x86/libhermes-executor-debug.so", - "base/lib/x86/libhermes-executor-release.so", - "base/lib/x86/libjsc.so", - "base/lib/x86/libjscexecutor.so", - )) - val task = - createTestTask { - it.inputBundle.set(inputAab) - it.outputBundle.set(outputAab) - it.enableHermes.set(false) - it.debuggableVariant.set(true) - } - - task.run() - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${inputAab.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertFalse(exists(it.getPath("base/lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-release.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libjsc.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun nativeLibraryAabCleanupTask_withJscRelease_cleansCorrectly() { - val inputAab = File(tempFolder.root, "input.aab") - val outputAab = File(tempFolder.root, "output.aab") - createZip( - inputAab, - listOf( - "base/lib/x86/libhermes.so", - "base/lib/x86/libhermes-executor-debug.so", - "base/lib/x86/libhermes-executor-release.so", - "base/lib/x86/libjsc.so", - "base/lib/x86/libjscexecutor.so", - )) - val task = - createTestTask { - it.inputBundle.set(inputAab) - it.outputBundle.set(outputAab) - it.enableHermes.set(false) - it.debuggableVariant.set(false) - } - - task.run() - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${inputAab.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertFalse(exists(it.getPath("base/lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("base/lib/x86/libhermes-executor-release.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libjsc.so"))) - assertTrue(exists(it.getPath("base/lib/x86/libjscexecutor.so"))) - } - } -} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTaskTest.kt deleted file mode 100644 index 7abc0e6c12161d..00000000000000 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/NativeLibraryApkCleanupTaskTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.react.tasks - -import com.facebook.react.tests.createTestTask -import com.facebook.react.tests.createZip -import java.io.File -import java.net.URI -import java.nio.file.FileSystems -import java.nio.file.Files.exists -import org.gradle.api.tasks.* -import org.junit.Assert.* -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder - -class NativeLibraryApkCleanupTaskTest { - - @get:Rule val tempFolder = TemporaryFolder() - - @Test - fun nativeLibraryApkCleanupTask_runWithAppApk() { - val tempApk = File(tempFolder.root, "app.apk") - createZip( - tempApk, - listOf( - "lib/x86/libhermes.so", - "lib/x86/libhermes-executor-debug.so", - "lib/x86/libhermes-executor-release.so", - "lib/x86/libjsc.so", - "lib/x86/libjscexecutor.so", - )) - val task = - createTestTask { - it.inputApkDirectory.set(tempFolder.root) - it.outputApkDirectory.set(tempFolder.root) - it.enableHermes.set(true) - it.debuggableVariant.set(true) - } - - task.run() - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempApk.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertTrue(exists(it.getPath("lib/x86/libhermes.so"))) - assertTrue(exists(it.getPath("lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-release.so"))) - assertFalse(exists(it.getPath("lib/x86/libjsc.so"))) - assertFalse(exists(it.getPath("lib/x86/libjscexecutor.so"))) - } - } -} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/NdkConfiguratorUtilsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/NdkConfiguratorUtilsTest.kt new file mode 100644 index 00000000000000..2d0093c6a565d2 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/NdkConfiguratorUtilsTest.kt @@ -0,0 +1,88 @@ +/* + * 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.react.utils + +import com.facebook.react.utils.NdkConfiguratorUtils.getPackagingOptionsForVariant +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class NdkConfiguratorUtilsTest { + + @Test + fun getPackagingOptionsForVariant_withHermesEnabled_andDebuggableVariant() { + val (excludes, includes) = + getPackagingOptionsForVariant(hermesEnabled = true, debuggableVariant = true) + + assertTrue("**/libjsc.so" in excludes) + assertTrue("**/libjscexecutor.so" in excludes) + assertTrue("**/libhermes-executor-release.so" in excludes) + assertFalse("**/libjsc.so" in includes) + assertFalse("**/libjscexecutor.so" in includes) + assertFalse("**/libhermes-executor-release.so" in includes) + + assertTrue("**/libhermes.so" in includes) + assertTrue("**/libhermes-executor-debug.so" in includes) + assertFalse("**/libhermes.so" in excludes) + assertFalse("**/libhermes-executor-debug.so" in excludes) + } + + @Test + fun getPackagingOptionsForVariant_withHermesEnabled_andNonDebuggableVariant() { + val (excludes, includes) = + getPackagingOptionsForVariant(hermesEnabled = true, debuggableVariant = false) + + assertTrue("**/libjsc.so" in excludes) + assertTrue("**/libjscexecutor.so" in excludes) + assertTrue("**/libhermes-executor-debug.so" in excludes) + assertFalse("**/libjsc.so" in includes) + assertFalse("**/libjscexecutor.so" in includes) + assertFalse("**/libhermes-executor-debug.so" in includes) + + assertTrue("**/libhermes.so" in includes) + assertTrue("**/libhermes-executor-release.so" in includes) + assertFalse("**/libhermes.so" in excludes) + assertFalse("**/libhermes-executor-release.so" in excludes) + } + + @Test + fun getPackagingOptionsForVariant_withHermesDisabled_andDebuggableVariant() { + val (excludes, includes) = + getPackagingOptionsForVariant(hermesEnabled = false, debuggableVariant = true) + + assertTrue("**/libhermes.so" in excludes) + assertTrue("**/libhermes-executor-debug.so" in excludes) + assertTrue("**/libhermes-executor-release.so" in excludes) + assertFalse("**/libhermes.so" in includes) + assertFalse("**/libhermes-executor-debug.so" in includes) + assertFalse("**/libhermes-executor-release.so" in includes) + + assertTrue("**/libjsc.so" in includes) + assertTrue("**/libjscexecutor.so" in includes) + assertFalse("**/libjsc.so" in excludes) + assertFalse("**/libjscexecutor.so" in excludes) + } + + @Test + fun getPackagingOptionsForVariant_withHermesDisabled_andNonDebuggableVariant() { + val (excludes, includes) = + getPackagingOptionsForVariant(hermesEnabled = false, debuggableVariant = false) + + assertTrue("**/libhermes.so" in excludes) + assertTrue("**/libhermes-executor-debug.so" in excludes) + assertTrue("**/libhermes-executor-release.so" in excludes) + assertFalse("**/libhermes.so" in includes) + assertFalse("**/libhermes-executor-debug.so" in includes) + assertFalse("**/libhermes-executor-release.so" in includes) + + assertTrue("**/libjsc.so" in includes) + assertTrue("**/libjscexecutor.so" in includes) + assertFalse("**/libjsc.so" in excludes) + assertFalse("**/libjscexecutor.so" in excludes) + } +} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/SoCleanerUtilsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/SoCleanerUtilsTest.kt deleted file mode 100644 index 2c887b48facd44..00000000000000 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/SoCleanerUtilsTest.kt +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.react.utils - -import com.facebook.react.tests.createZip -import com.facebook.react.utils.SoCleanerUtils.clean -import com.facebook.react.utils.SoCleanerUtils.removeSoFiles -import java.io.File -import java.net.URI -import java.nio.file.FileSystems -import java.nio.file.Files.* -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Rule -import org.junit.Test -import org.junit.Test.None -import org.junit.rules.TemporaryFolder - -class SoCleanerUtilsTest { - - @get:Rule val tempFolder = TemporaryFolder() - - @Test - fun clean_withEnableHermesAndDebuggableVariant_removesCorrectly() { - val tempZip = - File(tempFolder.root, "app.apk").apply { - createZip( - this, - listOf( - "lib/x86/libhermes.so", - "lib/x86/libhermes-executor-debug.so", - "lib/x86/libhermes-executor-release.so", - "lib/x86/libjsc.so", - "lib/x86/libjscexecutor.so", - )) - } - - clean(tempZip, "lib", enableHermes = true, debuggableVariant = true) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertTrue(exists(it.getPath("lib/x86/libhermes.so"))) - assertTrue(exists(it.getPath("lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-release.so"))) - assertFalse(exists(it.getPath("lib/x86/libjsc.so"))) - assertFalse(exists(it.getPath("lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun clean_withEnableHermesAndNonDebuggableVariant_removesCorrectly() { - val tempZip = - File(tempFolder.root, "app.apk").apply { - createZip( - this, - listOf( - "lib/x86/libhermes.so", - "lib/x86/libhermes-executor-debug.so", - "lib/x86/libhermes-executor-release.so", - "lib/x86/libjsc.so", - "lib/x86/libjscexecutor.so", - )) - } - - clean(tempZip, "lib", enableHermes = true, debuggableVariant = false) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertTrue(exists(it.getPath("lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-debug.so"))) - assertTrue(exists(it.getPath("lib/x86/libhermes-executor-release.so"))) - assertFalse(exists(it.getPath("lib/x86/libjsc.so"))) - assertFalse(exists(it.getPath("lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun clean_withJscAndDebuggableVariant_removesCorrectly() { - val tempZip = - File(tempFolder.root, "app.apk").apply { - createZip( - this, - listOf( - "lib/x86/libhermes.so", - "lib/x86/libhermes-executor-debug.so", - "lib/x86/libhermes-executor-release.so", - "lib/x86/libjsc.so", - "lib/x86/libjscexecutor.so", - )) - } - - clean(tempZip, "lib", enableHermes = false, debuggableVariant = true) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertFalse(exists(it.getPath("lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-release.so"))) - assertTrue(exists(it.getPath("lib/x86/libjsc.so"))) - assertTrue(exists(it.getPath("lib/x86/libjscexecutor.so"))) - } - } - - @Test - fun clean_withJscAndNonDebuggableVariant_removesCorrectly() { - val tempZip = - File(tempFolder.root, "app.apk").apply { - createZip( - this, - listOf( - "lib/x86/libhermes.so", - "lib/x86/libhermes-executor-debug.so", - "lib/x86/libhermes-executor-release.so", - "lib/x86/libjsc.so", - "lib/x86/libjscexecutor.so", - )) - } - - clean(tempZip, "lib", enableHermes = false, debuggableVariant = false) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - fs.use { - assertFalse(exists(it.getPath("lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-debug.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes-executor-release.so"))) - assertTrue(exists(it.getPath("lib/x86/libjsc.so"))) - assertTrue(exists(it.getPath("lib/x86/libjscexecutor.so"))) - } - } - - @Test(expected = None::class) - fun removeSoFiles_withEmptyZip_doesNothing() { - val tempZip = File(tempFolder.root, "app.apk") - createZip(tempZip, emptyList()) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - val archs = listOf("x86") - val libraryToRemove = "libhello.so" - - removeSoFiles(fs, "lib", archs, libraryToRemove) - } - - @Test - fun removeSoFiles_withValidFiles_filtersThemCorrectly() { - val tempZip = File(tempFolder.root, "app.apk") - createZip( - tempZip, - listOf( - "base/lib/x86_64/libhermes.so", - "base/lib/x86/libhermes.so", - "lib/arm64-v8a/libhermes.so", - "lib/armeabi-v7a/libhermes.so", - "lib/x86/libhermes.so", - "lib/x86_64/libhermes.so", - )) - - val fs = - FileSystems.newFileSystem( - URI.create("jar:file:${tempZip.absoluteFile}"), mapOf("create" to "false")) - val archs = listOf("x86", "x86_64") - val libraryToRemove = "libhermes.so" - - removeSoFiles(fs, "lib", archs, libraryToRemove) - - fs.use { - assertTrue(exists(it.getPath("base/lib/x86/libhermes.so"))) - assertTrue(exists(it.getPath("base/lib/x86_64/libhermes.so"))) - assertTrue(exists(it.getPath("lib/arm64-v8a/libhermes.so"))) - assertTrue(exists(it.getPath("lib/armeabi-v7a/libhermes.so"))) - assertFalse(exists(it.getPath("lib/x86/libhermes.so"))) - assertFalse(exists(it.getPath("lib/x86_64/libhermes.so"))) - } - } -}