@granite-js/screen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/GraniteScreen.podspec +25 -0
- package/LICENSE +202 -0
- package/android/CMakeLists.txt +62 -0
- package/android/build.gradle +63 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/BundleEvaluator.cpp +27 -0
- package/android/src/main/cpp/BundleEvaluator.h +17 -0
- package/android/src/main/cpp/onLoad.cpp +6 -0
- package/android/src/main/kotlin/run/granite/BundleEvaluator.kt +50 -0
- package/android/src/main/kotlin/run/granite/BundleLoader.kt +40 -0
- package/android/src/main/kotlin/run/granite/DefaultBundleLoader.kt +20 -0
- package/android/src/main/kotlin/run/granite/DefaultErrorView.kt +58 -0
- package/android/src/main/kotlin/run/granite/DefaultLoadingView.kt +51 -0
- package/android/src/main/kotlin/run/granite/GraniteReactDelegate.kt +76 -0
- package/android/src/main/kotlin/run/granite/GraniteReactDelegateImpl.kt +448 -0
- package/android/src/main/kotlin/run/granite/GraniteReactHost.kt +113 -0
- package/android/src/main/kotlin/run/granite/ReactHostFactory.kt +106 -0
- package/gradle-plugin/LICENSE +201 -0
- package/gradle-plugin/README.md +578 -0
- package/gradle-plugin/build.gradle.kts +97 -0
- package/gradle-plugin/gradle/libs.versions.toml +17 -0
- package/gradle-plugin/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle-plugin/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/gradle-plugin/gradle.properties +12 -0
- package/gradle-plugin/gradlew +248 -0
- package/gradle-plugin/gradlew.bat +93 -0
- package/gradle-plugin/settings.gradle.kts +1 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/GraniteExtension.kt +225 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/GranitePlugin.kt +784 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/GraniteRootExtension.kt +107 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/GraniteRootProjectPlugin.kt +290 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/BuildConfigConfigurator.kt +69 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/DependencyConfigurator.kt +232 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/DependencyCoordinates.kt +29 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/DevServerResourceConfigurator.kt +101 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/JniPackagingConfigurator.kt +160 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/NdkConfigurator.kt +135 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/RepositoryConfigurator.kt +148 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/config/ResourceConfigurator.kt +56 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/generators/CMakeGenerator.kt +105 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/generators/CppAutolinkingGenerator.kt +152 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/generators/EntryPointGenerator.kt +100 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/models/AndroidDependencyConfig.kt +23 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/models/AutolinkingConfig.kt +89 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/models/CMakeEntry.kt +47 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/models/NativeModule.kt +177 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/tasks/AssetPackagingTask.kt +194 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/tasks/AutolinkingTask.kt +431 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/tasks/BundleTask.kt +275 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/tasks/CodegenArtifactsTask.kt +218 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/tasks/CodegenSchemaTask.kt +186 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/AutolinkingParser.kt +128 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/ConflictDetector.kt +121 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/JdkValidator.kt +73 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/NodeExecutableFinder.kt +43 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/ReactNativeVersionReader.kt +329 -0
- package/gradle-plugin/src/main/kotlin/run/granite/gradle/utils/TaskDependencyValidator.kt +198 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/GraniteExtensionTest.kt +191 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/GranitePluginTest.kt +156 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/GraniteRootProjectPluginTest.kt +87 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/config/BuildConfigConfiguratorTest.kt +115 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/config/DependencyConfiguratorTest.kt +338 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/config/DevServerResourceConfiguratorTest.kt +205 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/config/ResourceConfiguratorTest.kt +131 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/fixtures/NativeModuleFixtures.kt +67 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/generators/CMakeGeneratorTest.kt +71 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/generators/CppAutolinkingGeneratorTest.kt +344 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/generators/EntryPointGeneratorTest.kt +40 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/models/AutolinkingConfigTest.kt +350 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/models/CMakeEntryTest.kt +200 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/models/NativeModuleTest.kt +562 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/tasks/AssetPackagingTaskTest.kt +318 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/tasks/AutolinkingTaskTest.kt +89 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/tasks/BundleTaskTest.kt +68 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/tasks/CodegenTasksTest.kt +410 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/AutolinkingParserTest.kt +335 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/ConflictDetectorTest.kt +75 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/JdkValidatorTest.kt +88 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/ReactNativeVersionReaderTest.kt +585 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/TaskDependencyValidatorTest.kt +123 -0
- package/gradle-plugin/src/test/kotlin/run/granite/gradle/utils/TaskTestUtils.kt +88 -0
- package/gradle-plugin/src/test/resources/fixtures/sample-rn-config.json +45 -0
- package/ios/BundleLoader/BundleEvaluator.h +16 -0
- package/ios/BundleLoader/BundleEvaluator.mm +76 -0
- package/ios/BundleLoader/BundleLoadable.swift +91 -0
- package/ios/GraniteBundleLoaderTypes.swift +7 -0
- package/ios/GraniteScreen.h +12 -0
- package/ios/ReactNativeHosting/DefaultViews.swift +138 -0
- package/ios/ReactNativeHosting/GraniteDefaultModuleProvider.h +24 -0
- package/ios/ReactNativeHosting/GraniteDefaultModuleProvider.mm +22 -0
- package/ios/ReactNativeHosting/GraniteHostingHelper.swift +103 -0
- package/ios/ReactNativeHosting/GraniteNativeFactory.swift +35 -0
- package/ios/ReactNativeHosting/GraniteNativeFactoryDelegateImpl.swift +30 -0
- package/ios/ReactNativeHosting/GraniteNativeFactoryImpl.swift +24 -0
- package/ios/ReactNativeHosting/GraniteReactHost.swift +39 -0
- package/ios/ReactNativeHosting/GraniteScreen-Bridging-Header.h +12 -0
- package/package.json +59 -0
- package/react-native.config.js +8 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
package run.granite.gradle.generators
|
|
2
|
+
|
|
3
|
+
import run.granite.gradle.models.NativeModule
|
|
4
|
+
import java.io.File
|
|
5
|
+
import java.util.logging.Logger
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generates Android-autolinking.cmake configuration file for React Native native modules.
|
|
9
|
+
*
|
|
10
|
+
* This generator creates a CMake configuration file that:
|
|
11
|
+
* - Adds subdirectories for each native module
|
|
12
|
+
* - Sets REACTNATIVE_MERGED_SO=true for React Native 0.76+
|
|
13
|
+
* - Sanitizes paths (escape spaces, remove CMakeLists.txt)
|
|
14
|
+
* - Creates unique build directory names ({libraryName}_autolinked_build)
|
|
15
|
+
* - Handles both standard and cxxModule CMakeLists.txt
|
|
16
|
+
* - Generates AUTOLINKED_LIBRARIES list with react_codegen_* prefixes
|
|
17
|
+
*/
|
|
18
|
+
object CMakeGenerator {
|
|
19
|
+
private val logger = Logger.getLogger(CMakeGenerator::class.java.name)
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Generates Android-autolinking.cmake file content.
|
|
23
|
+
*
|
|
24
|
+
* @param modules List of all native modules
|
|
25
|
+
* @param projectRoot Root directory of the project for path resolution
|
|
26
|
+
* @return Generated CMake code as string
|
|
27
|
+
*/
|
|
28
|
+
fun generate(modules: List<NativeModule>, projectRoot: File): String {
|
|
29
|
+
// Filter out brick-module as it uses a special codegen pattern
|
|
30
|
+
val cmakeModules = modules.filter { it.hasCMakeConfiguration }
|
|
31
|
+
|
|
32
|
+
if (cmakeModules.isEmpty()) {
|
|
33
|
+
// Skip CMake generation if no modules with native code
|
|
34
|
+
return generateEmptyFile()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Collect all CMake entries from modules
|
|
38
|
+
val allEntries = cmakeModules.flatMap { it.cmakeEntries() }
|
|
39
|
+
|
|
40
|
+
// Filter entries to only include directories that actually exist
|
|
41
|
+
val existingEntries = allEntries.filter { entry ->
|
|
42
|
+
val sanitizedPath = entry.sanitizedPath(projectRoot)
|
|
43
|
+
File(sanitizedPath).exists().also { exists ->
|
|
44
|
+
if (!exists) {
|
|
45
|
+
logger.warning("Skipping non-existent CMake directory: $sanitizedPath")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
val allLibraryTargets = existingEntries.flatMap { it.libraryTargets }
|
|
51
|
+
|
|
52
|
+
return buildString {
|
|
53
|
+
appendLine("# Generated by Granite Gradle Plugin - DO NOT EDIT")
|
|
54
|
+
appendLine("# This file is automatically generated during the build process")
|
|
55
|
+
appendLine()
|
|
56
|
+
|
|
57
|
+
// Set REACTNATIVE_MERGED_SO=true for React Native 0.76+
|
|
58
|
+
appendLine("# Enable merged shared object model for React Native 0.76+")
|
|
59
|
+
appendLine("set(REACTNATIVE_MERGED_SO true)")
|
|
60
|
+
appendLine()
|
|
61
|
+
|
|
62
|
+
if (existingEntries.isNotEmpty()) {
|
|
63
|
+
appendLine("# Add native module directories")
|
|
64
|
+
existingEntries.forEach { entry ->
|
|
65
|
+
appendLine(entry.toCMakeCommand(projectRoot))
|
|
66
|
+
}
|
|
67
|
+
appendLine()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Initialize empty AUTOLINKED_LIBRARIES and conditionally append targets
|
|
71
|
+
// This ensures clean works even when codegen directories don't exist
|
|
72
|
+
appendLine("# Autolinked library targets (conditionally added based on existence)")
|
|
73
|
+
appendLine("set(AUTOLINKED_LIBRARIES \"\")")
|
|
74
|
+
existingEntries.forEach { entry ->
|
|
75
|
+
entry.libraryTargets.forEach { target ->
|
|
76
|
+
appendLine("if(TARGET $target)")
|
|
77
|
+
appendLine(" list(APPEND AUTOLINKED_LIBRARIES $target)")
|
|
78
|
+
appendLine("endif()")
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generates an empty CMake file with explanatory comment.
|
|
86
|
+
*/
|
|
87
|
+
private fun generateEmptyFile(): String = buildString {
|
|
88
|
+
appendLine("# Generated by Granite Gradle Plugin - DO NOT EDIT")
|
|
89
|
+
appendLine("# This file is automatically generated during the build process")
|
|
90
|
+
appendLine()
|
|
91
|
+
appendLine("# No native modules with CMake configuration found")
|
|
92
|
+
appendLine("set(REACTNATIVE_MERGED_SO true)")
|
|
93
|
+
appendLine("set(AUTOLINKED_LIBRARIES)")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Writes Android-autolinking.cmake to the specified output directory.
|
|
98
|
+
*/
|
|
99
|
+
fun generateToFile(modules: List<NativeModule>, projectRoot: File, outputDir: File) {
|
|
100
|
+
val content = generate(modules, projectRoot)
|
|
101
|
+
val outputFile = File(outputDir, "Android-autolinking.cmake")
|
|
102
|
+
outputFile.parentFile.mkdirs()
|
|
103
|
+
outputFile.writeText(content)
|
|
104
|
+
}
|
|
105
|
+
}
|
package/gradle-plugin/src/main/kotlin/run/granite/gradle/generators/CppAutolinkingGenerator.kt
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
package run.granite.gradle.generators
|
|
2
|
+
|
|
3
|
+
import run.granite.gradle.models.NativeModule
|
|
4
|
+
import java.io.File
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generates autolinking.cpp with concrete implementations of autolinking functions.
|
|
8
|
+
*
|
|
9
|
+
* This generator creates C++ code that:
|
|
10
|
+
* - Implements autolinking_ModuleProvider for Java TurboModules
|
|
11
|
+
* - Implements autolinking_cxxModuleProvider for C++ TurboModules
|
|
12
|
+
* - Includes proper headers for C++ TurboModules
|
|
13
|
+
* - Returns nullptr when no match is found (early-return pattern)
|
|
14
|
+
* - Sanitizes C++ identifiers
|
|
15
|
+
*/
|
|
16
|
+
object CppAutolinkingGenerator {
|
|
17
|
+
/**
|
|
18
|
+
* Generates autolinking.cpp file content.
|
|
19
|
+
*
|
|
20
|
+
* @param modules List of all native modules
|
|
21
|
+
* @return Generated C++ code as string
|
|
22
|
+
*/
|
|
23
|
+
fun generate(modules: List<NativeModule>): String {
|
|
24
|
+
val cxxModules = modules.filter { it.hasCxxImplementation }
|
|
25
|
+
val javaModules = modules.filter { it.hasJavaImplementation }
|
|
26
|
+
val fabricLibraries =
|
|
27
|
+
modules
|
|
28
|
+
.filter { it.hasFabricComponents }
|
|
29
|
+
.mapNotNull { module ->
|
|
30
|
+
val libraryName = module.libraryName ?: return@mapNotNull null
|
|
31
|
+
libraryName to module.componentDescriptors
|
|
32
|
+
}
|
|
33
|
+
.groupBy({ it.first }, { it.second })
|
|
34
|
+
.mapValues { (_, descriptorLists) -> descriptorLists.flatten().distinct() }
|
|
35
|
+
.toSortedMap()
|
|
36
|
+
|
|
37
|
+
return buildString {
|
|
38
|
+
appendLine("// Generated by Granite Gradle Plugin - DO NOT EDIT")
|
|
39
|
+
appendLine("// This file is automatically generated during the build process")
|
|
40
|
+
appendLine()
|
|
41
|
+
appendLine("#include <autolinking.h>")
|
|
42
|
+
appendLine()
|
|
43
|
+
|
|
44
|
+
// C++ TurboModule headers
|
|
45
|
+
if (cxxModules.isNotEmpty()) {
|
|
46
|
+
appendLine("// C++ TurboModule headers")
|
|
47
|
+
cxxModules.forEach { module ->
|
|
48
|
+
module.cxxModuleHeaderName?.let { headerName ->
|
|
49
|
+
appendLine("#include <$headerName.h>")
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
appendLine()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Fabric component descriptor headers
|
|
56
|
+
if (fabricLibraries.isNotEmpty()) {
|
|
57
|
+
appendLine("// Fabric component descriptor headers")
|
|
58
|
+
fabricLibraries.forEach { (libraryName, componentDescriptors) ->
|
|
59
|
+
appendLine("#if defined(__has_include) && __has_include(<react/renderer/components/$libraryName/ComponentDescriptors.h>)")
|
|
60
|
+
appendLine("#include <react/renderer/components/$libraryName/ComponentDescriptors.h>")
|
|
61
|
+
appendLine("#endif")
|
|
62
|
+
componentDescriptors.forEach { descriptor ->
|
|
63
|
+
appendLine("#if defined(__has_include) && __has_include(<react/renderer/components/$libraryName/$descriptor.h>)")
|
|
64
|
+
appendLine("#include <react/renderer/components/$libraryName/$descriptor.h>")
|
|
65
|
+
appendLine("#endif")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
appendLine()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
appendLine("namespace facebook::react {")
|
|
72
|
+
appendLine()
|
|
73
|
+
|
|
74
|
+
// autolinking_registerProviders function
|
|
75
|
+
appendLine("void autolinking_registerProviders(")
|
|
76
|
+
appendLine(" std::shared_ptr<const ComponentDescriptorProviderRegistry> registry) {")
|
|
77
|
+
if (fabricLibraries.isNotEmpty()) {
|
|
78
|
+
appendLine(" // Register Fabric component descriptors from autolinked libraries")
|
|
79
|
+
fabricLibraries.forEach { (libraryName, componentDescriptors) ->
|
|
80
|
+
appendLine("#if defined(__has_include) && __has_include(<react/renderer/components/$libraryName/ComponentDescriptors.h>)")
|
|
81
|
+
appendLine(" ${libraryName}_registerComponentDescriptorsFromCodegen(registry);")
|
|
82
|
+
appendLine("#endif")
|
|
83
|
+
componentDescriptors.forEach { descriptor ->
|
|
84
|
+
appendLine("#if defined(__has_include) && __has_include(<react/renderer/components/$libraryName/$descriptor.h>)")
|
|
85
|
+
appendLine(" registry->add(concreteComponentDescriptorProvider<$descriptor>());")
|
|
86
|
+
appendLine("#endif")
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
appendLine(" // No autolinked Fabric components found")
|
|
91
|
+
}
|
|
92
|
+
appendLine("}")
|
|
93
|
+
appendLine()
|
|
94
|
+
|
|
95
|
+
// autolinking_cxxModuleProvider function
|
|
96
|
+
appendLine("std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(")
|
|
97
|
+
appendLine(" const std::string& moduleName,")
|
|
98
|
+
appendLine(" const std::shared_ptr<CallInvoker>& jsInvoker) {")
|
|
99
|
+
if (cxxModules.isNotEmpty()) {
|
|
100
|
+
appendLine(" // Check C++ TurboModules (early-return pattern)")
|
|
101
|
+
cxxModules.forEach { module ->
|
|
102
|
+
module.cxxModuleHeaderName?.let { headerName ->
|
|
103
|
+
appendLine(" if (moduleName == $headerName::kModuleName) {")
|
|
104
|
+
appendLine(" return std::make_shared<$headerName>(jsInvoker);")
|
|
105
|
+
appendLine(" }")
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
appendLine(" // No autolinked C++ TurboModules found")
|
|
110
|
+
}
|
|
111
|
+
appendLine()
|
|
112
|
+
appendLine(" return nullptr;")
|
|
113
|
+
appendLine("}")
|
|
114
|
+
appendLine()
|
|
115
|
+
|
|
116
|
+
// autolinking_ModuleProvider function
|
|
117
|
+
appendLine("std::shared_ptr<TurboModule> autolinking_ModuleProvider(")
|
|
118
|
+
appendLine(" const std::string& moduleName,")
|
|
119
|
+
appendLine(" const JavaTurboModule::InitParams& params) {")
|
|
120
|
+
if (javaModules.isNotEmpty()) {
|
|
121
|
+
appendLine(" // Delegate to Java TurboModule providers (early-return pattern)")
|
|
122
|
+
javaModules.forEach { module ->
|
|
123
|
+
module.libraryName?.let { libraryName ->
|
|
124
|
+
val sanitized = module.sanitizedName()
|
|
125
|
+
appendLine(" auto module_$sanitized = ${libraryName}_ModuleProvider(moduleName, params);")
|
|
126
|
+
appendLine(" if (module_$sanitized != nullptr) {")
|
|
127
|
+
appendLine(" return module_$sanitized;")
|
|
128
|
+
appendLine(" }")
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
appendLine(" // No autolinked Java TurboModules found")
|
|
133
|
+
}
|
|
134
|
+
appendLine()
|
|
135
|
+
appendLine(" return nullptr;")
|
|
136
|
+
appendLine("}")
|
|
137
|
+
appendLine()
|
|
138
|
+
|
|
139
|
+
appendLine("} // namespace facebook::react")
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Writes autolinking.cpp to the specified output directory.
|
|
145
|
+
*/
|
|
146
|
+
fun generateToFile(modules: List<NativeModule>, outputDir: File) {
|
|
147
|
+
val content = generate(modules)
|
|
148
|
+
val outputFile = File(outputDir, "autolinking.cpp")
|
|
149
|
+
outputFile.parentFile.mkdirs()
|
|
150
|
+
outputFile.writeText(content)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package run.granite.gradle.generators
|
|
2
|
+
|
|
3
|
+
import java.io.File
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generates ReactNativeApplicationEntryPoint.java for SoLoader initialization
|
|
7
|
+
* and New Architecture loading.
|
|
8
|
+
*
|
|
9
|
+
* This generator creates Java code that:
|
|
10
|
+
* - Provides ReactNativeApplicationEntryPoint class with static loadReactNative method
|
|
11
|
+
* - Initializes SoLoader with OpenSourceMergedSoMapping
|
|
12
|
+
* - Conditionally loads New Architecture components
|
|
13
|
+
* - Conditionally enables edge-to-edge UI
|
|
14
|
+
* - Places generated code in com.facebook.react package
|
|
15
|
+
* - Throws RuntimeException on SoLoader failure
|
|
16
|
+
*/
|
|
17
|
+
object EntryPointGenerator {
|
|
18
|
+
/**
|
|
19
|
+
* Generates ReactNativeApplicationEntryPoint.java file content.
|
|
20
|
+
*
|
|
21
|
+
* @param packageName The Android package name from project configuration
|
|
22
|
+
* @return Generated Java code as string
|
|
23
|
+
* @throws IllegalStateException if packageName is null
|
|
24
|
+
*/
|
|
25
|
+
fun generate(packageName: String?): String {
|
|
26
|
+
// Validate package name is present
|
|
27
|
+
requireNotNull(packageName) {
|
|
28
|
+
"Android package name not found in react-native config. " +
|
|
29
|
+
"Ensure project has valid android configuration."
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return buildString {
|
|
33
|
+
appendLine("// Generated by Granite Gradle Plugin - DO NOT EDIT")
|
|
34
|
+
appendLine("// This file is automatically generated during the build process")
|
|
35
|
+
appendLine()
|
|
36
|
+
appendLine("package com.facebook.react;")
|
|
37
|
+
appendLine()
|
|
38
|
+
appendLine("import android.content.Context;")
|
|
39
|
+
appendLine("import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;")
|
|
40
|
+
appendLine("import com.facebook.react.soloader.OpenSourceMergedSoMapping;")
|
|
41
|
+
appendLine("import com.facebook.react.views.view.WindowUtilKt;")
|
|
42
|
+
appendLine("import com.facebook.soloader.SoLoader;")
|
|
43
|
+
appendLine()
|
|
44
|
+
appendLine("/**")
|
|
45
|
+
appendLine(" * ReactNativeApplicationEntryPoint provides static initialization for React Native runtime.")
|
|
46
|
+
appendLine(" * This class handles SoLoader initialization and New Architecture component loading.")
|
|
47
|
+
appendLine(" */")
|
|
48
|
+
appendLine("public class ReactNativeApplicationEntryPoint {")
|
|
49
|
+
appendLine()
|
|
50
|
+
appendLine(" /**")
|
|
51
|
+
appendLine(" * Loads the React Native runtime with proper SoLoader and New Architecture initialization.")
|
|
52
|
+
appendLine(" *")
|
|
53
|
+
appendLine(" * @param context Application context for SoLoader initialization")
|
|
54
|
+
appendLine(" * @throws RuntimeException if SoLoader initialization fails")
|
|
55
|
+
appendLine(" */")
|
|
56
|
+
appendLine(" public static void loadReactNative(Context context) {")
|
|
57
|
+
appendLine(" // Initialize SoLoader with merged shared object mapping")
|
|
58
|
+
appendLine(" try {")
|
|
59
|
+
appendLine(" SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);")
|
|
60
|
+
appendLine(" } catch (Exception e) {")
|
|
61
|
+
appendLine(" throw new RuntimeException(\"Failed to initialize SoLoader\", e);")
|
|
62
|
+
appendLine(" }")
|
|
63
|
+
appendLine()
|
|
64
|
+
appendLine(" // Load New Architecture components if enabled")
|
|
65
|
+
appendLine(" // if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {")
|
|
66
|
+
appendLine(" DefaultNewArchitectureEntryPoint.load();")
|
|
67
|
+
appendLine(" WindowUtilKt.setEdgeToEdgeFeatureFlagOn();")
|
|
68
|
+
appendLine(" // }")
|
|
69
|
+
appendLine()
|
|
70
|
+
appendLine(" // Enable edge-to-edge UI if configured")
|
|
71
|
+
appendLine(" // if (BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {")
|
|
72
|
+
appendLine(" // Edge-to-edge feature flag is set in BuildConfig")
|
|
73
|
+
appendLine(" // }")
|
|
74
|
+
appendLine(" }")
|
|
75
|
+
appendLine()
|
|
76
|
+
appendLine(" private ReactNativeApplicationEntryPoint() {")
|
|
77
|
+
appendLine(" // Utility class - prevent instantiation")
|
|
78
|
+
appendLine(" }")
|
|
79
|
+
appendLine("}")
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Writes ReactNativeApplicationEntryPoint.java to the specified output directory.
|
|
85
|
+
*
|
|
86
|
+
* @param packageName Android package name from project configuration
|
|
87
|
+
* @param outputDir Output directory for Java source files
|
|
88
|
+
* @throws IllegalStateException if packageName is null
|
|
89
|
+
*/
|
|
90
|
+
fun generateToFile(packageName: String?, outputDir: File) {
|
|
91
|
+
val content = generate(packageName)
|
|
92
|
+
|
|
93
|
+
// Create package directory structure: com/facebook/react/
|
|
94
|
+
val packageDir = File(outputDir, "src/main/java/com/facebook/react")
|
|
95
|
+
packageDir.mkdirs()
|
|
96
|
+
|
|
97
|
+
val outputFile = File(packageDir, "ReactNativeApplicationEntryPoint.java")
|
|
98
|
+
outputFile.writeText(content)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package run.granite.gradle.models
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Complete Android-specific configuration for a native module.
|
|
5
|
+
* Maps directly to the "platforms.android" JSON structure from react-native config.
|
|
6
|
+
*
|
|
7
|
+
* All fields are nullable as they may be absent in the JSON configuration.
|
|
8
|
+
* Missing fields are treated identically to null fields.
|
|
9
|
+
*/
|
|
10
|
+
data class AndroidDependencyConfig(
|
|
11
|
+
val sourceDir: String?,
|
|
12
|
+
val packageImportPath: String?,
|
|
13
|
+
val packageInstance: String?,
|
|
14
|
+
val dependencyConfiguration: String?,
|
|
15
|
+
val buildTypes: List<String>?,
|
|
16
|
+
val libraryName: String?,
|
|
17
|
+
val componentDescriptors: List<String>?,
|
|
18
|
+
val cmakeListsPath: String?,
|
|
19
|
+
val cxxModuleCMakeListsPath: String?,
|
|
20
|
+
val cxxModuleCMakeListsModuleName: String?,
|
|
21
|
+
val cxxModuleHeaderName: String?,
|
|
22
|
+
val isPureCxxDependency: Boolean?,
|
|
23
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
package run.granite.gradle.models
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Root configuration object parsed from `react-native config` JSON output.
|
|
5
|
+
*
|
|
6
|
+
* Provides filtered views of dependencies for different code generation purposes:
|
|
7
|
+
* - androidDependencies(): All modules with Android native code
|
|
8
|
+
* - javaModules(): Modules with Java TurboModule implementations
|
|
9
|
+
* - cxxModules(): Modules with C++ TurboModule implementations
|
|
10
|
+
* - fabricModules(): Modules with Fabric components
|
|
11
|
+
* - cmakeModules(): Modules with CMake configuration
|
|
12
|
+
*/
|
|
13
|
+
data class AutolinkingConfig(
|
|
14
|
+
val project: ProjectInfo,
|
|
15
|
+
val dependencies: Map<String, DependencyConfig>,
|
|
16
|
+
) {
|
|
17
|
+
/**
|
|
18
|
+
* Filters dependencies to only those with Android native code.
|
|
19
|
+
* Excludes JavaScript-only packages.
|
|
20
|
+
* Reads each module's package.json to check for includesGeneratedCode flag.
|
|
21
|
+
*/
|
|
22
|
+
fun androidDependencies(): List<NativeModule> = dependencies.mapNotNull { (name, config) ->
|
|
23
|
+
config.platforms?.android?.let { androidConfig ->
|
|
24
|
+
NativeModule.from(name, androidConfig, config.root)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns modules that have Java TurboModule implementations.
|
|
30
|
+
* Identified by non-null packageImportPath and packageInstance.
|
|
31
|
+
*/
|
|
32
|
+
fun javaModules(): List<NativeModule> = androidDependencies().filter { it.hasJavaImplementation }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns modules that have C++ TurboModule implementations.
|
|
36
|
+
* Identified by non-null cxxModuleHeaderName.
|
|
37
|
+
*/
|
|
38
|
+
fun cxxModules(): List<NativeModule> = androidDependencies().filter { it.hasCxxImplementation }
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns modules that have Fabric components.
|
|
42
|
+
* Identified by non-empty componentDescriptors array.
|
|
43
|
+
*/
|
|
44
|
+
fun fabricModules(): List<NativeModule> = androidDependencies().filter { it.hasFabricComponents }
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns modules that have CMake configuration.
|
|
48
|
+
* Identified by non-null cmakeListsPath or cxxModuleCMakeListsPath.
|
|
49
|
+
*/
|
|
50
|
+
fun cmakeModules(): List<NativeModule> = androidDependencies().filter { it.hasCMakeConfiguration }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Metadata about the React Native project itself.
|
|
55
|
+
* Used for entry point generation.
|
|
56
|
+
*/
|
|
57
|
+
data class ProjectInfo(
|
|
58
|
+
val name: String?,
|
|
59
|
+
val version: String?,
|
|
60
|
+
val ios: Map<String, Any>?,
|
|
61
|
+
val android: AndroidProjectConfig?,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Android project configuration extracted from react-native config.
|
|
66
|
+
* packageName is required for entry point generation.
|
|
67
|
+
*/
|
|
68
|
+
data class AndroidProjectConfig(
|
|
69
|
+
val sourceDir: String?,
|
|
70
|
+
val manifestPath: String?,
|
|
71
|
+
val packageName: String?,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Top-level configuration for a single dependency.
|
|
76
|
+
*/
|
|
77
|
+
data class DependencyConfig(
|
|
78
|
+
val name: String,
|
|
79
|
+
val root: String,
|
|
80
|
+
val platforms: PlatformConfig?,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Platform-specific configuration container.
|
|
85
|
+
*/
|
|
86
|
+
data class PlatformConfig(
|
|
87
|
+
val ios: Map<String, Any>?,
|
|
88
|
+
val android: AndroidDependencyConfig?,
|
|
89
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package run.granite.gradle.models
|
|
2
|
+
|
|
3
|
+
import java.io.File
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a single add_subdirectory entry in Android-autolinking.cmake.
|
|
7
|
+
*
|
|
8
|
+
* Each CMake entry includes:
|
|
9
|
+
* - sourcePath: Path to the directory containing CMakeLists.txt
|
|
10
|
+
* - buildDirName: Unique build directory name for this module
|
|
11
|
+
* - libraryTargets: List of CMake library targets to be linked
|
|
12
|
+
*/
|
|
13
|
+
data class CMakeEntry(
|
|
14
|
+
val sourcePath: String,
|
|
15
|
+
val buildDirName: String,
|
|
16
|
+
val libraryTargets: List<String>,
|
|
17
|
+
) {
|
|
18
|
+
/**
|
|
19
|
+
* Sanitizes the source path for CMake.
|
|
20
|
+
* - Removes trailing /CMakeLists.txt or \CMakeLists.txt
|
|
21
|
+
* - Converts to absolute path if relative
|
|
22
|
+
* - Replaces backslashes with forward slashes
|
|
23
|
+
*/
|
|
24
|
+
fun sanitizedPath(moduleRoot: File): String {
|
|
25
|
+
var path = sourcePath.removeSuffix("/CMakeLists.txt")
|
|
26
|
+
.removeSuffix("\\CMakeLists.txt")
|
|
27
|
+
|
|
28
|
+
val file = File(path)
|
|
29
|
+
if (!file.isAbsolute) {
|
|
30
|
+
path = File(moduleRoot, path).canonicalPath
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return path.replace('\\', '/')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Generates the add_subdirectory command line with existence check.
|
|
38
|
+
* Wraps with if(EXISTS ...) to prevent CMake errors during clean
|
|
39
|
+
* when codegen directories don't exist yet.
|
|
40
|
+
*/
|
|
41
|
+
fun toCMakeCommand(moduleRoot: File): String {
|
|
42
|
+
val sanitized = sanitizedPath(moduleRoot)
|
|
43
|
+
return """if(EXISTS "$sanitized")
|
|
44
|
+
add_subdirectory("$sanitized" $buildDirName)
|
|
45
|
+
endif()"""
|
|
46
|
+
}
|
|
47
|
+
}
|