From 7cdb4aecc5e32461b8195254e20f01bd68a4ec71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 28 Jul 2025 11:54:45 +0200 Subject: [PATCH 1/2] first version of fix --- android/build.gradle | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/android/build.gradle b/android/build.gradle index ae2fa5f..dcad4c6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -179,4 +179,54 @@ tasks.configureEach { task -> if (task.name.contains("clean")) { task.dependsOn(deleteCmakeCache) } + + // Make sure that we generate our prefab publication file only after having built the native library + // so that not a header publication file, but a full configuration publication will be generated, which + // will include the .so file + + // TODO: this needs to be fixed to work dynamically on the variant name + if (task.name.contains("prefabDebugConfigurePackage")) { + task.outputs.upToDateWhen { false } + task.dependsOn("externalNativeBuildDebug") + } + if (task.name.contains("prefabReleaseConfigurePackage")) { + task.outputs.upToDateWhen { false } + task.dependsOn("externalNativeBuildRelease") + } } + +afterEvaluate { + def abis = reactNativeArchitectures() + rootProject.allprojects.each { proj -> + if (proj === rootProject) return // skip RNWC and app project + + + def dependsOnWorklets = proj.configurations.findAll { it.canBeResolved }.any { config -> + config.dependencies.any { dep -> + dep.group == project.group && dep.name == project.name + } + } + if (!dependsOnWorklets && proj != project) return // skip if not dependent + println("Project ${proj.path} depends on react-native-worklets-core") + + if (proj.plugins.hasPlugin('com.android.application') || proj.plugins.hasPlugin('com.android.library')) { + def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants + variants.all { variant -> + def variantName = variant.name + abis.each { abi -> + def searchDir = new File(proj.projectDir, ".cxx/${variantName}") + if (!searchDir.exists()) return + def matches = [] + searchDir.eachDir { randomDir -> + def prefabFile = new File(randomDir, "${abi}/prefab_config.json") + if (prefabFile.exists()) matches << prefabFile + } + matches.each { prefabConfig -> + prefabConfig.setLastModified(System.currentTimeMillis()) + println("Touched: ${prefabConfig}") + } + } + } + } + } +} \ No newline at end of file From 3127390cffb01ea54f995758eae4c4d9f57a1d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 28 Jul 2025 12:41:21 +0200 Subject: [PATCH 2/2] mvoe to fix-prefab --- android/build.gradle | 51 +------------------------------- android/gradle/fix-prefab.gradle | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 50 deletions(-) create mode 100644 android/gradle/fix-prefab.gradle diff --git a/android/build.gradle b/android/build.gradle index dcad4c6..b3da4cc 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -51,6 +51,7 @@ def reactNativeArchitectures() { } apply plugin: "com.android.library" +apply from: "./gradle/fix-prefab.gradle" if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" @@ -179,54 +180,4 @@ tasks.configureEach { task -> if (task.name.contains("clean")) { task.dependsOn(deleteCmakeCache) } - - // Make sure that we generate our prefab publication file only after having built the native library - // so that not a header publication file, but a full configuration publication will be generated, which - // will include the .so file - - // TODO: this needs to be fixed to work dynamically on the variant name - if (task.name.contains("prefabDebugConfigurePackage")) { - task.outputs.upToDateWhen { false } - task.dependsOn("externalNativeBuildDebug") - } - if (task.name.contains("prefabReleaseConfigurePackage")) { - task.outputs.upToDateWhen { false } - task.dependsOn("externalNativeBuildRelease") - } } - -afterEvaluate { - def abis = reactNativeArchitectures() - rootProject.allprojects.each { proj -> - if (proj === rootProject) return // skip RNWC and app project - - - def dependsOnWorklets = proj.configurations.findAll { it.canBeResolved }.any { config -> - config.dependencies.any { dep -> - dep.group == project.group && dep.name == project.name - } - } - if (!dependsOnWorklets && proj != project) return // skip if not dependent - println("Project ${proj.path} depends on react-native-worklets-core") - - if (proj.plugins.hasPlugin('com.android.application') || proj.plugins.hasPlugin('com.android.library')) { - def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants - variants.all { variant -> - def variantName = variant.name - abis.each { abi -> - def searchDir = new File(proj.projectDir, ".cxx/${variantName}") - if (!searchDir.exists()) return - def matches = [] - searchDir.eachDir { randomDir -> - def prefabFile = new File(randomDir, "${abi}/prefab_config.json") - if (prefabFile.exists()) matches << prefabFile - } - matches.each { prefabConfig -> - prefabConfig.setLastModified(System.currentTimeMillis()) - println("Touched: ${prefabConfig}") - } - } - } - } - } -} \ No newline at end of file diff --git a/android/gradle/fix-prefab.gradle b/android/gradle/fix-prefab.gradle new file mode 100644 index 0000000..d6c010e --- /dev/null +++ b/android/gradle/fix-prefab.gradle @@ -0,0 +1,51 @@ +tasks.configureEach { task -> + // Make sure that we generate our prefab publication file only after having built the native library + // so that not a header publication file, but a full configuration publication will be generated, which + // will include the .so file + + def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/ + def matcher = task.name =~ prefabConfigurePattern + if (matcher.matches()) { + def variantName = matcher[0][1] + task.outputs.upToDateWhen { false } + task.dependsOn("externalNativeBuild${variantName}") + } +} + +afterEvaluate { + def abis = reactNativeArchitectures() + rootProject.allprojects.each { proj -> + if (proj === rootProject) return + + def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config -> + config.dependencies.any { dep -> + dep.group == project.group && dep.name == project.name + } + } + if (!dependsOnThisLib && proj != project) return + + if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) { + return + } + + def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants + // Touch the prefab_config.json files to ensure that in ExternalNativeJsonGenerator.kt we will re-trigger the prefab CLI to + // generate a libnameConfig.cmake file that will contain our native library (.so). + // See this condition: https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExternalNativeJsonGenerator.kt;l=207-219?q=createPrefabBuildSystemGlue + variants.all { variant -> + def variantName = variant.name + abis.each { abi -> + def searchDir = new File(proj.projectDir, ".cxx/${variantName}") + if (!searchDir.exists()) return + def matches = [] + searchDir.eachDir { randomDir -> + def prefabFile = new File(randomDir, "${abi}/prefab_config.json") + if (prefabFile.exists()) matches << prefabFile + } + matches.each { prefabConfig -> + prefabConfig.setLastModified(System.currentTimeMillis()) + } + } + } + } +}