@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,107 @@
|
|
|
1
|
+
package run.granite.gradle
|
|
2
|
+
|
|
3
|
+
import org.gradle.api.Project
|
|
4
|
+
import org.gradle.api.provider.Property
|
|
5
|
+
import run.granite.gradle.config.DependencyCoordinates
|
|
6
|
+
import run.granite.gradle.utils.ReactNativeVersionReader
|
|
7
|
+
import java.io.File
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* DSL configuration extension for Granite Root Project plugin.
|
|
11
|
+
*
|
|
12
|
+
* Configure the plugin in your root build.gradle.kts:
|
|
13
|
+
* ```
|
|
14
|
+
* graniteRoot {
|
|
15
|
+
* // Optional: Explicit version override (auto-detected from node_modules if not set)
|
|
16
|
+
* // reactNativeVersion.set("0.84.0")
|
|
17
|
+
* // hermesVersion.set("250829098.0.6")
|
|
18
|
+
*
|
|
19
|
+
* // Optional: Override Maven group (for custom Maven repositories)
|
|
20
|
+
* // reactGroup.set("com.facebook.react")
|
|
21
|
+
* // hermesGroup.set("com.facebook.hermes")
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
abstract class GraniteRootExtension(private val project: Project) {
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* React Native version (auto-detected from node_modules if not set)
|
|
29
|
+
*/
|
|
30
|
+
abstract val reactNativeVersion: Property<String>
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hermes version (auto-detected from node_modules if not set)
|
|
34
|
+
*/
|
|
35
|
+
abstract val hermesVersion: Property<String>
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* React Native Maven group.
|
|
39
|
+
* Default: com.facebook.react
|
|
40
|
+
*/
|
|
41
|
+
abstract val reactGroup: Property<String>
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Hermes Maven group.
|
|
45
|
+
* Default: com.facebook.hermes
|
|
46
|
+
*/
|
|
47
|
+
abstract val hermesGroup: Property<String>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Location of the node_modules directory.
|
|
51
|
+
* Default: rootProject.file("node_modules")
|
|
52
|
+
*/
|
|
53
|
+
abstract val nodeModulesDir: Property<File>
|
|
54
|
+
|
|
55
|
+
init {
|
|
56
|
+
// Set default conventions
|
|
57
|
+
reactGroup.convention(DependencyCoordinates.DEFAULT_REACT_GROUP)
|
|
58
|
+
hermesGroup.convention(DependencyCoordinates.DEFAULT_HERMES_GROUP)
|
|
59
|
+
nodeModulesDir.convention(project.file("node_modules"))
|
|
60
|
+
// reactNativeVersion and hermesVersion are intentionally left without conventions
|
|
61
|
+
// They will be auto-detected if not explicitly set
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Gets the resolved DependencyCoordinates.
|
|
66
|
+
*
|
|
67
|
+
* If versions are explicitly set, uses those values.
|
|
68
|
+
* Otherwise, auto-detects from node_modules/react-native.
|
|
69
|
+
*
|
|
70
|
+
* @return DependencyCoordinates for dependency substitution
|
|
71
|
+
* @throws IllegalStateException if auto-detection fails and no explicit versions set
|
|
72
|
+
*/
|
|
73
|
+
internal fun getCoordinates(): DependencyCoordinates {
|
|
74
|
+
val reactNativeDir = nodeModulesDir.get().resolve("react-native")
|
|
75
|
+
|
|
76
|
+
// Auto-detect base coordinates if needed
|
|
77
|
+
val baseCoordinates = if (!reactNativeVersion.isPresent || !hermesVersion.isPresent) {
|
|
78
|
+
if (!reactNativeDir.exists()) {
|
|
79
|
+
error(
|
|
80
|
+
"""
|
|
81
|
+
|React Native directory not found: ${reactNativeDir.absolutePath}
|
|
82
|
+
|
|
|
83
|
+
|Either set versions explicitly in graniteRoot { } or ensure node_modules/react-native exists.
|
|
84
|
+
|
|
|
85
|
+
|Example:
|
|
86
|
+
| graniteRoot {
|
|
87
|
+
| reactNativeVersion.set("0.84.0")
|
|
88
|
+
| hermesVersion.set("250829098.0.6")
|
|
89
|
+
| }
|
|
90
|
+
""".trimMargin(),
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
ReactNativeVersionReader.readCoordinates(reactNativeDir)
|
|
94
|
+
} else {
|
|
95
|
+
null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build final coordinates: explicit > auto-detected
|
|
99
|
+
return DependencyCoordinates(
|
|
100
|
+
reactVersion = reactNativeVersion.orNull ?: baseCoordinates!!.reactVersion,
|
|
101
|
+
hermesVersion = baseCoordinates?.hermesVersion ?: "",
|
|
102
|
+
hermesV1Version = hermesVersion.orNull ?: baseCoordinates!!.hermesV1Version,
|
|
103
|
+
reactGroup = reactGroup.get(),
|
|
104
|
+
hermesGroup = hermesGroup.get(),
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
package run.granite.gradle
|
|
2
|
+
|
|
3
|
+
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
|
4
|
+
import com.android.build.api.variant.LibraryAndroidComponentsExtension
|
|
5
|
+
import org.gradle.api.JavaVersion
|
|
6
|
+
import org.gradle.api.Plugin
|
|
7
|
+
import org.gradle.api.Project
|
|
8
|
+
import org.gradle.api.artifacts.Configuration
|
|
9
|
+
import run.granite.gradle.config.DependencyConfigurator
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Granite Root Project Plugin
|
|
13
|
+
*
|
|
14
|
+
* Plugin applied to the root project to automatically configure
|
|
15
|
+
* React Native dependency substitution.
|
|
16
|
+
*
|
|
17
|
+
* This plugin performs the following roles:
|
|
18
|
+
* - react-native → react-android dependency substitution
|
|
19
|
+
* - hermes-engine → hermes-android dependency substitution
|
|
20
|
+
* - com.facebook.react:hermes-android → com.facebook.hermes:hermes-android substitution (RN 0.84+)
|
|
21
|
+
* - Version forcing (force)
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ```
|
|
25
|
+
* // root build.gradle.kts
|
|
26
|
+
* plugins {
|
|
27
|
+
* id("run.granite.rootproject")
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* graniteRoot {
|
|
31
|
+
* // Optional: Explicit version override
|
|
32
|
+
* // reactNativeVersion.set("0.84.0")
|
|
33
|
+
* // hermesVersion.set("250829098.0.6")
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @see GraniteRootExtension for configuration options
|
|
38
|
+
*/
|
|
39
|
+
class GraniteRootProjectPlugin : Plugin<Project> {
|
|
40
|
+
|
|
41
|
+
companion object {
|
|
42
|
+
/** Plugin identifier used in build.gradle.kts: `id("run.granite.rootproject")`. */
|
|
43
|
+
const val PLUGIN_ID = "run.granite.rootproject"
|
|
44
|
+
|
|
45
|
+
/** Name of the DSL extension block: `graniteRoot { ... }`. */
|
|
46
|
+
const val EXTENSION_NAME = "graniteRoot"
|
|
47
|
+
|
|
48
|
+
// Uses Granite-specific properties (operates independently from react.internal.*)
|
|
49
|
+
private const val INTERNAL_DISABLE_JAVA_VERSION_ALIGNMENT =
|
|
50
|
+
"granite.internal.disableJavaVersionAlignment"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override fun apply(project: Project) {
|
|
54
|
+
// 1. Root project validation
|
|
55
|
+
validateRootProject(project)
|
|
56
|
+
|
|
57
|
+
// 2. Create extension
|
|
58
|
+
val extension = project.extensions.create(
|
|
59
|
+
EXTENSION_NAME,
|
|
60
|
+
GraniteRootExtension::class.java,
|
|
61
|
+
project,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
// 3. Configure PrivateReactExtension for React Native Gradle Plugin compatibility
|
|
65
|
+
configurePrivateReactExtension(project)
|
|
66
|
+
|
|
67
|
+
// 4. Configure Java toolchains IMMEDIATELY (before afterEvaluate)
|
|
68
|
+
// This must run before afterEvaluate for finalizeDsl to work
|
|
69
|
+
configureJavaToolChains(project)
|
|
70
|
+
|
|
71
|
+
// 5. Configure dependency substitution after evaluation
|
|
72
|
+
project.afterEvaluate {
|
|
73
|
+
configureDependencySubstitution(project, extension)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
project.logger.lifecycle("Granite Root Project plugin applied to ${project.name}")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun validateRootProject(project: Project) {
|
|
80
|
+
if (project != project.rootProject) {
|
|
81
|
+
error(
|
|
82
|
+
"""
|
|
83
|
+
|Granite Root Project plugin can only be applied to the root project.
|
|
84
|
+
|
|
|
85
|
+
|Current project: ${project.path}
|
|
86
|
+
|Root project: ${project.rootProject.path}
|
|
87
|
+
|
|
|
88
|
+
|Solution: Move the plugin application to your root build.gradle.kts:
|
|
89
|
+
| plugins {
|
|
90
|
+
| id("run.granite.rootproject")
|
|
91
|
+
| }
|
|
92
|
+
""".trimMargin(),
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun configureDependencySubstitution(project: Project, extension: GraniteRootExtension) {
|
|
98
|
+
val coordinates = extension.getCoordinates()
|
|
99
|
+
val substitutions = DependencyConfigurator.getDependencySubstitutions(coordinates)
|
|
100
|
+
val hermesVersion = coordinates.getEffectiveHermesVersion()
|
|
101
|
+
|
|
102
|
+
project.logger.lifecycle(
|
|
103
|
+
"Granite: Configuring dependency substitution " +
|
|
104
|
+
"(react: ${coordinates.reactVersion}, hermes: $hermesVersion)",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
project.allprojects {
|
|
108
|
+
val targetProject = this
|
|
109
|
+
|
|
110
|
+
targetProject.configurations.all configBlock@{
|
|
111
|
+
// Filter: only Classpath configurations
|
|
112
|
+
if (!name.endsWith("CompileClasspath") && !name.endsWith("RuntimeClasspath")) {
|
|
113
|
+
return@configBlock
|
|
114
|
+
}
|
|
115
|
+
// Filter: skip AGP internal metadata configurations
|
|
116
|
+
if (name.contains("Metadata", ignoreCase = true)) {
|
|
117
|
+
return@configBlock
|
|
118
|
+
}
|
|
119
|
+
// Skip already resolved or non-resolvable configurations
|
|
120
|
+
if (!isCanBeResolved || state == Configuration.State.RESOLVED) {
|
|
121
|
+
return@configBlock
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Apply dependency substitution rules
|
|
125
|
+
resolutionStrategy.dependencySubstitution {
|
|
126
|
+
for ((oldCoordinate, newCoordinate, reason) in substitutions) {
|
|
127
|
+
substitute(module(oldCoordinate))
|
|
128
|
+
.using(module(newCoordinate))
|
|
129
|
+
.because(reason)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Force versions for consistency
|
|
134
|
+
resolutionStrategy.force(
|
|
135
|
+
"${coordinates.reactGroup}:react-android:${coordinates.reactVersion}",
|
|
136
|
+
"${coordinates.hermesGroup}:hermes-android:$hermesVersion",
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
project.logger.lifecycle(
|
|
142
|
+
"Granite: Dependency substitution configured for all projects " +
|
|
143
|
+
"(${substitutions.size} rules applied)",
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Configures Java 17 toolchain for all projects.
|
|
149
|
+
*
|
|
150
|
+
* Uses finalizeDsl in the same way as React Native's JdkConfiguratorUtils.kt.
|
|
151
|
+
* finalizeDsl runs after the android { } block evaluation but before AGP internal finalization.
|
|
152
|
+
*
|
|
153
|
+
* - Sets Java 17 for projects with com.android.application / com.android.library plugins
|
|
154
|
+
* - Sets jvmToolchain(17) for org.jetbrains.kotlin.android / org.jetbrains.kotlin.jvm plugins
|
|
155
|
+
*
|
|
156
|
+
* Disable: Set granite.internal.disableJavaVersionAlignment=true in gradle.properties
|
|
157
|
+
*
|
|
158
|
+
* @param project Root project
|
|
159
|
+
*/
|
|
160
|
+
private fun configureJavaToolChains(project: Project) {
|
|
161
|
+
// Check if disabled at root project level
|
|
162
|
+
if (project.hasProperty(INTERNAL_DISABLE_JAVA_VERSION_ALIGNMENT)) {
|
|
163
|
+
project.logger.lifecycle("Granite: Java version alignment disabled via property")
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
project.allprojects {
|
|
168
|
+
val targetProject = this
|
|
169
|
+
|
|
170
|
+
// Can also be disabled at project level
|
|
171
|
+
if (targetProject.hasProperty(INTERNAL_DISABLE_JAVA_VERSION_ALIGNMENT)) {
|
|
172
|
+
return@allprojects
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Android Application plugin - set compileOptions via finalizeDsl
|
|
176
|
+
targetProject.pluginManager.withPlugin("com.android.application") {
|
|
177
|
+
targetProject.extensions
|
|
178
|
+
.getByType(ApplicationAndroidComponentsExtension::class.java)
|
|
179
|
+
.finalizeDsl { ext ->
|
|
180
|
+
ext.compileOptions.sourceCompatibility = JavaVersion.VERSION_17
|
|
181
|
+
ext.compileOptions.targetCompatibility = JavaVersion.VERSION_17
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Android Library plugin - set compileOptions via finalizeDsl
|
|
186
|
+
targetProject.pluginManager.withPlugin("com.android.library") {
|
|
187
|
+
targetProject.extensions
|
|
188
|
+
.getByType(LibraryAndroidComponentsExtension::class.java)
|
|
189
|
+
.finalizeDsl { ext ->
|
|
190
|
+
ext.compileOptions.sourceCompatibility = JavaVersion.VERSION_17
|
|
191
|
+
ext.compileOptions.targetCompatibility = JavaVersion.VERSION_17
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Kotlin Android plugin (uses reflection to avoid compile-time dependency)
|
|
196
|
+
targetProject.pluginManager.withPlugin("org.jetbrains.kotlin.android") {
|
|
197
|
+
try {
|
|
198
|
+
val kotlinExtension = targetProject.extensions.findByName("kotlin")
|
|
199
|
+
if (kotlinExtension != null) {
|
|
200
|
+
val jvmToolchainMethod = kotlinExtension.javaClass
|
|
201
|
+
.getMethod("jvmToolchain", Int::class.javaPrimitiveType)
|
|
202
|
+
jvmToolchainMethod.invoke(kotlinExtension, 17)
|
|
203
|
+
}
|
|
204
|
+
} catch (e: Exception) {
|
|
205
|
+
targetProject.logger.debug(
|
|
206
|
+
"Granite: Could not set jvmToolchain for ${targetProject.name}: ${e.message}",
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Kotlin JVM plugin configuration
|
|
212
|
+
targetProject.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
|
|
213
|
+
try {
|
|
214
|
+
val kotlinExtension = targetProject.extensions.findByName("kotlin")
|
|
215
|
+
if (kotlinExtension != null) {
|
|
216
|
+
val jvmToolchainMethod = kotlinExtension.javaClass
|
|
217
|
+
.getMethod("jvmToolchain", Int::class.javaPrimitiveType)
|
|
218
|
+
jvmToolchainMethod.invoke(kotlinExtension, 17)
|
|
219
|
+
}
|
|
220
|
+
} catch (e: Exception) {
|
|
221
|
+
targetProject.logger.debug(
|
|
222
|
+
"Granite: Could not set jvmToolchain for ${targetProject.name}: ${e.message}",
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
project.logger.lifecycle("Granite: Configured Java 17 toolchain for all projects")
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Pre-emptively creates and configures PrivateReactExtension from the React Native Gradle Plugin.
|
|
233
|
+
*
|
|
234
|
+
* Background:
|
|
235
|
+
* - PrivateReactExtension is created on the rootProject to share configuration between app and library modules
|
|
236
|
+
* - The default convention assumes rootProject.dir/../ (standard RN app's android/ directory structure)
|
|
237
|
+
* - In monorepo setups where rootProject.dir IS the package.json location, ../ points to the wrong path
|
|
238
|
+
* - When the application module does not apply com.facebook.react, root.set() is never called
|
|
239
|
+
*
|
|
240
|
+
* Solution:
|
|
241
|
+
* - This plugin creates the extension first and sets root to rootProject.dir
|
|
242
|
+
* - ReactPlugin uses findByType to reuse an existing extension, so there is no conflict
|
|
243
|
+
*/
|
|
244
|
+
private fun configurePrivateReactExtension(project: Project) {
|
|
245
|
+
try {
|
|
246
|
+
val privateReactExtensionClass = Class.forName(
|
|
247
|
+
"com.facebook.react.internal.PrivateReactExtension",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
val existing = project.extensions.findByType(privateReactExtensionClass)
|
|
251
|
+
if (existing != null) {
|
|
252
|
+
// If already exists, only configure root
|
|
253
|
+
setRootProperty(existing, project)
|
|
254
|
+
project.logger.lifecycle(
|
|
255
|
+
"Granite: Configured existing PrivateReactExtension root to ${project.projectDir}",
|
|
256
|
+
)
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Create new instance
|
|
261
|
+
val extension = project.extensions.create(
|
|
262
|
+
"privateReact",
|
|
263
|
+
privateReactExtensionClass,
|
|
264
|
+
project,
|
|
265
|
+
)
|
|
266
|
+
setRootProperty(extension, project)
|
|
267
|
+
project.logger.lifecycle(
|
|
268
|
+
"Granite: Created PrivateReactExtension with root=${project.projectDir}",
|
|
269
|
+
)
|
|
270
|
+
} catch (e: Exception) {
|
|
271
|
+
project.logger.warn(
|
|
272
|
+
"Granite: Could not configure PrivateReactExtension: ${e.message}. " +
|
|
273
|
+
"React Native Gradle Plugin may not be available on the classpath.",
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private fun setRootProperty(extension: Any, project: Project) {
|
|
279
|
+
try {
|
|
280
|
+
val rootProperty = extension.javaClass.getMethod("getRoot").invoke(extension)
|
|
281
|
+
if (rootProperty is org.gradle.api.file.DirectoryProperty) {
|
|
282
|
+
rootProperty.set(project.layout.projectDirectory)
|
|
283
|
+
}
|
|
284
|
+
} catch (e: Exception) {
|
|
285
|
+
project.logger.warn(
|
|
286
|
+
"Granite: Could not set PrivateReactExtension root: ${e.message}",
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package run.granite.gradle.config
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.LibraryExtension
|
|
4
|
+
import org.gradle.api.Project
|
|
5
|
+
import run.granite.gradle.GraniteExtension
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configurator for Android BuildConfig field generation.
|
|
9
|
+
*
|
|
10
|
+
* Generates BuildConfig fields to expose:
|
|
11
|
+
* - Feature flags (New Architecture, Hermes always enabled)
|
|
12
|
+
* - Development server configuration
|
|
13
|
+
* - React Native version information
|
|
14
|
+
*
|
|
15
|
+
* These constants are available at runtime and compile-time for conditional logic.
|
|
16
|
+
*/
|
|
17
|
+
class BuildConfigConfigurator(
|
|
18
|
+
private val project: Project,
|
|
19
|
+
private val extension: GraniteExtension,
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configures BuildConfig fields for the Android library.
|
|
24
|
+
*
|
|
25
|
+
* Adds fields that are available in generated BuildConfig class:
|
|
26
|
+
* - IS_HERMES_ENABLED: Boolean flag for Hermes JavaScript engine (always true)
|
|
27
|
+
* - IS_NEW_ARCHITECTURE_ENABLED: Boolean flag for TurboModules/Fabric (always true)
|
|
28
|
+
* - REACT_NATIVE_VERSION: String with React Native version
|
|
29
|
+
*/
|
|
30
|
+
fun configure(androidExtension: LibraryExtension) {
|
|
31
|
+
androidExtension.apply {
|
|
32
|
+
// Enable BuildConfig generation for library module
|
|
33
|
+
buildFeatures.buildConfig = true
|
|
34
|
+
|
|
35
|
+
// Add common BuildConfig fields
|
|
36
|
+
defaultConfig {
|
|
37
|
+
// Hermes JavaScript engine flag (always enabled)
|
|
38
|
+
buildConfigField(
|
|
39
|
+
"boolean",
|
|
40
|
+
"IS_HERMES_ENABLED",
|
|
41
|
+
"true",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// New Architecture (TurboModules + Fabric) flag (always enabled)
|
|
45
|
+
buildConfigField(
|
|
46
|
+
"boolean",
|
|
47
|
+
"IS_NEW_ARCHITECTURE_ENABLED",
|
|
48
|
+
"true",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
// React Native version
|
|
52
|
+
buildConfigField(
|
|
53
|
+
"String",
|
|
54
|
+
"REACT_NATIVE_VERSION",
|
|
55
|
+
"\"${extension.reactNativeVersion.get()}\"",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// Bundle asset name
|
|
59
|
+
buildConfigField(
|
|
60
|
+
"String",
|
|
61
|
+
"BUNDLE_ASSET_NAME",
|
|
62
|
+
"\"${extension.bundleAssetName.get()}\"",
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
project.logger.lifecycle("BuildConfig fields configured for ${project.name}")
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
package run.granite.gradle.config
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.LibraryExtension
|
|
4
|
+
import org.gradle.api.JavaVersion
|
|
5
|
+
import org.gradle.api.Project
|
|
6
|
+
import run.granite.gradle.GraniteExtension
|
|
7
|
+
import run.granite.gradle.utils.ReactNativeVersionReader
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configures React Native and related dependencies for the library module.
|
|
11
|
+
*
|
|
12
|
+
* This configurator automatically adds required dependencies:
|
|
13
|
+
* - react-native (implementation)
|
|
14
|
+
* - hermes-android (implementation)
|
|
15
|
+
* - soloader (implementation)
|
|
16
|
+
*
|
|
17
|
+
* Versions are resolved from the React Native installation to ensure compatibility.
|
|
18
|
+
*/
|
|
19
|
+
class DependencyConfigurator(
|
|
20
|
+
private val project: Project,
|
|
21
|
+
private val extension: GraniteExtension,
|
|
22
|
+
) {
|
|
23
|
+
|
|
24
|
+
companion object {
|
|
25
|
+
// Default Maven group (official React Native Maven group)
|
|
26
|
+
const val DEFAULT_GROUP = "com.facebook.react"
|
|
27
|
+
|
|
28
|
+
// Dependency coordinates
|
|
29
|
+
private const val REACT_NATIVE_ARTIFACT = "react-android"
|
|
30
|
+
private const val HERMES_ARTIFACT = "hermes-android"
|
|
31
|
+
|
|
32
|
+
private const val SOLOADER_GROUP = "com.facebook.soloader"
|
|
33
|
+
private const val SOLOADER_ARTIFACT = "soloader"
|
|
34
|
+
private const val SOLOADER_VERSION = "0.12.1" // Compatible with RN 0.84+
|
|
35
|
+
|
|
36
|
+
// Deprecated coordinates for substitution
|
|
37
|
+
private const val DEPRECATED_REACT_NATIVE = "com.facebook.react:react-native"
|
|
38
|
+
private const val DEPRECATED_HERMES_ENGINE = "com.facebook.react:hermes-engine"
|
|
39
|
+
|
|
40
|
+
// Hermes group (RN 0.84+)
|
|
41
|
+
private const val HERMES_GROUP = "com.facebook.hermes"
|
|
42
|
+
|
|
43
|
+
// Additional deprecated coordinate
|
|
44
|
+
private const val DEPRECATED_HERMES_ANDROID = "com.facebook.react:hermes-android"
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates dependency substitution rules.
|
|
48
|
+
*
|
|
49
|
+
* @param version React Native version
|
|
50
|
+
* @param group React Native Maven group (default: com.facebook.react)
|
|
51
|
+
* @return List of triples (original coordinate, replacement coordinate, reason)
|
|
52
|
+
*/
|
|
53
|
+
fun getDependencySubstitutions(
|
|
54
|
+
version: String,
|
|
55
|
+
group: String,
|
|
56
|
+
): List<Triple<String, String, String>> {
|
|
57
|
+
val substitutions = mutableListOf<Triple<String, String, String>>()
|
|
58
|
+
|
|
59
|
+
// Base substitution rules: deprecated coordinates → new coordinates
|
|
60
|
+
substitutions.add(
|
|
61
|
+
Triple(
|
|
62
|
+
DEPRECATED_REACT_NATIVE,
|
|
63
|
+
"$group:$REACT_NATIVE_ARTIFACT:$version",
|
|
64
|
+
"The react-native artifact was deprecated in favor of react-android",
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
substitutions.add(
|
|
68
|
+
Triple(
|
|
69
|
+
DEPRECATED_HERMES_ENGINE,
|
|
70
|
+
"$group:$HERMES_ARTIFACT:$version",
|
|
71
|
+
"The hermes-engine artifact was deprecated in favor of hermes-android",
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
// Cross-group substitution: when using custom Maven group
|
|
76
|
+
if (group != DEFAULT_GROUP) {
|
|
77
|
+
substitutions.add(
|
|
78
|
+
Triple(
|
|
79
|
+
"$DEFAULT_GROUP:$REACT_NATIVE_ARTIFACT",
|
|
80
|
+
"$group:$REACT_NATIVE_ARTIFACT:$version",
|
|
81
|
+
"Modified to use correct Maven group",
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
substitutions.add(
|
|
85
|
+
Triple(
|
|
86
|
+
"$DEFAULT_GROUP:$HERMES_ARTIFACT",
|
|
87
|
+
"$group:$HERMES_ARTIFACT:$version",
|
|
88
|
+
"Modified to use correct Maven group",
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return substitutions
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Creates dependency substitution rules (DependencyCoordinates version).
|
|
98
|
+
*
|
|
99
|
+
* Supports the new Hermes group structure in React Native 0.84+:
|
|
100
|
+
* - com.facebook.react:react-native → {reactGroup}:react-android:{reactVersion}
|
|
101
|
+
* - com.facebook.react:hermes-engine → {hermesGroup}:hermes-android:{hermesVersion}
|
|
102
|
+
* - com.facebook.react:hermes-android → {hermesGroup}:hermes-android:{hermesVersion}
|
|
103
|
+
*
|
|
104
|
+
* @param coordinates Dependency coordinate information
|
|
105
|
+
* @return List of triples (original coordinate, replacement coordinate, reason)
|
|
106
|
+
*/
|
|
107
|
+
fun getDependencySubstitutions(coordinates: DependencyCoordinates): List<Triple<String, String, String>> {
|
|
108
|
+
val substitutions = mutableListOf<Triple<String, String, String>>()
|
|
109
|
+
val hermesVersion = coordinates.getEffectiveHermesVersion()
|
|
110
|
+
val hermesCoordinate = "${coordinates.hermesGroup}:$HERMES_ARTIFACT:$hermesVersion"
|
|
111
|
+
|
|
112
|
+
// 1. react-native -> react-android
|
|
113
|
+
substitutions.add(
|
|
114
|
+
Triple(
|
|
115
|
+
DEPRECATED_REACT_NATIVE,
|
|
116
|
+
"${coordinates.reactGroup}:$REACT_NATIVE_ARTIFACT:${coordinates.reactVersion}",
|
|
117
|
+
"The react-native artifact was deprecated in favor of react-android",
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
// 2. hermes-engine -> hermes-android (new group)
|
|
122
|
+
substitutions.add(
|
|
123
|
+
Triple(
|
|
124
|
+
DEPRECATED_HERMES_ENGINE,
|
|
125
|
+
hermesCoordinate,
|
|
126
|
+
"The hermes-engine artifact was deprecated in favor of hermes-android",
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
// 3. com.facebook.react:hermes-android → com.facebook.hermes:hermes-android (NEW!)
|
|
131
|
+
substitutions.add(
|
|
132
|
+
Triple(
|
|
133
|
+
DEPRECATED_HERMES_ANDROID,
|
|
134
|
+
hermesCoordinate,
|
|
135
|
+
"The hermes-android artifact was moved to com.facebook.hermes publishing group",
|
|
136
|
+
),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
// 4. Custom React group substitution
|
|
140
|
+
if (coordinates.reactGroup != DEFAULT_GROUP) {
|
|
141
|
+
substitutions.add(
|
|
142
|
+
Triple(
|
|
143
|
+
"$DEFAULT_GROUP:$REACT_NATIVE_ARTIFACT",
|
|
144
|
+
"${coordinates.reactGroup}:$REACT_NATIVE_ARTIFACT:${coordinates.reactVersion}",
|
|
145
|
+
"Modified to use correct Maven group",
|
|
146
|
+
),
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 5. Custom Hermes group substitution
|
|
151
|
+
if (coordinates.hermesGroup != HERMES_GROUP) {
|
|
152
|
+
substitutions.add(
|
|
153
|
+
Triple(
|
|
154
|
+
"$HERMES_GROUP:$HERMES_ARTIFACT",
|
|
155
|
+
hermesCoordinate,
|
|
156
|
+
"Modified to use correct Maven group",
|
|
157
|
+
),
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return substitutions
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Configures all required React Native dependencies.
|
|
167
|
+
*
|
|
168
|
+
* Called during project evaluation (afterEvaluate) to ensure configuration is complete.
|
|
169
|
+
*/
|
|
170
|
+
fun configure() {
|
|
171
|
+
val reactNativeDir = extension.getReactNativeDirResolved()
|
|
172
|
+
|
|
173
|
+
// Read all coordinates (React + Hermes)
|
|
174
|
+
val coordinates = ReactNativeVersionReader.readCoordinates(reactNativeDir)
|
|
175
|
+
ReactNativeVersionReader.validateVersion(coordinates.reactVersion)
|
|
176
|
+
|
|
177
|
+
project.logger.lifecycle(
|
|
178
|
+
"Configuring React Native dependencies (version: ${coordinates.reactVersion}, " +
|
|
179
|
+
"hermes: ${coordinates.getEffectiveHermesVersion()}, " +
|
|
180
|
+
"hermesGroup: ${coordinates.hermesGroup})",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
// Note: Dependency substitution is now handled by run.granite.rootproject plugin.
|
|
184
|
+
// See GraniteRootProjectPlugin for the centralized substitution logic.
|
|
185
|
+
|
|
186
|
+
// Add React Native core dependencies
|
|
187
|
+
addReactNativeDependencies(coordinates.reactVersion, coordinates.reactGroup)
|
|
188
|
+
|
|
189
|
+
// Add Hermes engine
|
|
190
|
+
addHermesDependency(coordinates)
|
|
191
|
+
|
|
192
|
+
// Add SoLoader (required for native library loading)
|
|
193
|
+
addSoLoaderDependency()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Adds React Native core dependencies.
|
|
198
|
+
*/
|
|
199
|
+
private fun addReactNativeDependencies(version: String, group: String) {
|
|
200
|
+
project.dependencies.add(
|
|
201
|
+
"implementation",
|
|
202
|
+
"$group:$REACT_NATIVE_ARTIFACT:$version",
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
project.logger.debug("Added dependency: $group:$REACT_NATIVE_ARTIFACT:$version")
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Adds Hermes JavaScript engine dependency (DependencyCoordinates version).
|
|
210
|
+
*/
|
|
211
|
+
private fun addHermesDependency(coordinates: DependencyCoordinates) {
|
|
212
|
+
val hermesVersion = coordinates.getEffectiveHermesVersion()
|
|
213
|
+
project.dependencies.add(
|
|
214
|
+
"implementation",
|
|
215
|
+
"${coordinates.hermesGroup}:$HERMES_ARTIFACT:$hermesVersion",
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
project.logger.debug("Added dependency: ${coordinates.hermesGroup}:$HERMES_ARTIFACT:$hermesVersion")
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Adds SoLoader dependency for native library loading.
|
|
223
|
+
*/
|
|
224
|
+
private fun addSoLoaderDependency() {
|
|
225
|
+
project.dependencies.add(
|
|
226
|
+
"implementation",
|
|
227
|
+
"$SOLOADER_GROUP:$SOLOADER_ARTIFACT:$SOLOADER_VERSION",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
project.logger.debug("Added dependency: $SOLOADER_GROUP:$SOLOADER_ARTIFACT:$SOLOADER_VERSION")
|
|
231
|
+
}
|
|
232
|
+
}
|