@@ -84,6 +84,7 @@ val preparePrefab by
8484 prepareFmt,
8585 prepareFolly,
8686 prepareGlog,
87+ prepareFbjni,
8788 )
8889 dependsOn(" generateCodegenArtifactsFromSchema" )
8990 // To export to a ReactNativePrefabProcessingEntities.kt once all
@@ -435,6 +436,50 @@ val prepareGlog by
435436 outputDir.set(File (thirdPartyNdkDir, " glog" ))
436437 }
437438
439+ val downloadFbjniAarDest = File (downloadsDir, " fbjni-0.7.0.aar" )
440+ val downloadFbjniAar by
441+ tasks.registering(Download ::class ) {
442+ dependsOn(createNativeDepsDirectories)
443+ src(" https://repo1.maven.org/maven2/com/facebook/fbjni/fbjni/0.7.0/fbjni-0.7.0.aar" )
444+ onlyIfModified(true )
445+ overwrite(false )
446+ retries(5 )
447+ quiet(true )
448+ dest(downloadFbjniAarDest)
449+ }
450+
451+ // Extract fbjni headers from AAR for prefab
452+ val prepareFbjni by
453+ tasks.registering {
454+ dependsOn(downloadFbjniAar)
455+ val inputAar = downloadFbjniAarDest
456+ val outputDir = File (prefabHeadersDir, " fbjni" )
457+ outputs.dir(outputDir)
458+ doLast {
459+ outputDir.mkdirs()
460+ // Extract only the fbjni headers from the AAR
461+ val zip = java.util.zip.ZipFile (inputAar)
462+ try {
463+ zip.entries().asSequence().filter { it.name.startsWith(" prefab/modules/fbjni/include/fbjni/" ) }
464+ .forEach { entry ->
465+ val destFile = File (outputDir, entry.name.removePrefix(" prefab/modules/fbjni/include/" ))
466+ destFile.parentFile.mkdirs()
467+ if (entry.isDirectory) {
468+ destFile.mkdirs()
469+ } else {
470+ destFile.outputStream().use { output ->
471+ zip.getInputStream(entry).use { input ->
472+ input.copyTo(output)
473+ }
474+ }
475+ }
476+ }
477+ } finally {
478+ zip.close()
479+ }
480+ }
481+ }
482+
438483// Tasks used by Fantom to download the Native 3p dependencies used.
439484val prepareNative3pDependencies by tasks.registering {
440485 dependsOn(
@@ -444,6 +489,7 @@ val prepareNative3pDependencies by tasks.registering {
444489 prepareFmt,
445490 prepareFolly,
446491 prepareGlog,
492+ prepareFbjni,
447493 )
448494}
449495
@@ -655,6 +701,9 @@ android {
655701 create(" jsi" ) { headers = File (prefabHeadersDir, " jsi" ).absolutePath }
656702 create(" reactnative" ) { headers = File (prefabHeadersDir, " reactnative" ).absolutePath }
657703 create(" hermestooling" ) { headers = File (prefabHeadersDir, " hermestooling" ).absolutePath }
704+ create(" fbjni" ) {
705+ headers = File (prefabHeadersDir, " fbjni" ).absolutePath
706+ }
658707 }
659708
660709 publishing {
@@ -681,9 +730,9 @@ android {
681730 // Generate CMake config file for find_package support
682731 // This is needed for ReactNative-application.cmake to find ReactAndroid via find_package()
683732 val generateReactAndroidConfig by tasks.registering {
684- outputs.dir(buildDir.resolve(" cmake/ReactAndroid" ))
733+ val configDir = buildDir.resolve(" cmake/ReactAndroid" )
734+ outputs.dir(configDir)
685735 doLast {
686- val configDir = outputs.files.first()
687736 configDir.mkdirs()
688737 // Convert paths to CMake-style forward slashes to avoid Windows escape sequence issues
689738 val buildDirCmake = buildDir.path.replace(" \\ " , " /" )
@@ -713,19 +762,25 @@ android {
713762 INTERFACE_INCLUDE_DIRECTORIES "${buildDirCmake} /prefab-headers/jsi"
714763 )
715764
765+ # The fbjni library - from Gradle dependency's prefab module
766+ add_library(fbjni SHARED IMPORTED)
767+ set_target_properties(fbjni PROPERTIES
768+ IMPORTED_LOCATION "${prefabLibsDir} /fbjni/libs/android.${' $' } {CMAKE_ANDROID_ARCH_ABI}/libfbjni.so"
769+ INTERFACE_INCLUDE_DIRECTORIES "${buildDirCmake} /prefab-headers/fbjni"
770+ )
771+
716772 """ .trimIndent()
717773 configDir.resolve(" ReactAndroidConfig.cmake" ).writeText(configContent)
718774 }
719775 }
720776
721777 // Ensure the config file is generated before external native build
722778 // The CMake tasks are created lazily by AGP with names like "configureCMake<Variant>"
723- // We use withType to find and configure the tasks by name pattern
724- // Note: tasks.matching is not reliable for lazily created tasks in AGP 9.1+
725- // Using withType<Task>().configureEach instead
726- tasks.withType<Task >().configureEach {
727- if (name.startsWith(" configureCMake" )) {
728- dependsOn(generateReactAndroidConfig)
779+ // We use task graph callback to find and configure CMake tasks
780+ // whenTaskAdded registers callbacks for tasks as they are created (handles lazy tasks)
781+ tasks.whenTaskAdded { task ->
782+ if (task.name.startsWith(" configureCMake" )) {
783+ task.dependsOn(generateReactAndroidConfig)
729784 }
730785 }
731786}
0 commit comments