Skip to content

Commit 9c6a666

Browse files
authored
refactor(android): reorganize Gradle scripts (#2257)
1 parent b750d97 commit 9c6a666

15 files changed

+446
-424
lines changed

android/app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
buildscript {
22
def androidDir = "${buildscript.sourceFile.getParent()}/../"
3-
apply(from: "${androidDir}/test-app-util.gradle")
3+
apply(from: "${androidDir}/autolink.gradle")
44
apply(from: "${androidDir}/dependencies.gradle")
5+
apply(from: "${androidDir}/manifest.gradle")
56
}
67

78
plugins {

android/autolink.gradle

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import groovy.json.JsonSlurper
2+
3+
ext.autolinkModules = { File projectRoot, File output, String testAppDir ->
4+
String[] autolink = ["node", "${testAppDir}/android/autolink.mjs", projectRoot.toString(), output.toString()]
5+
def stderr = new StringBuffer()
6+
def proc = Runtime.runtime.exec(autolink, null, projectRoot)
7+
proc.waitForProcessOutput(null, stderr)
8+
if (proc.exitValue() != 0) {
9+
throw new RuntimeException("Failed to autolink:\n${stderr}")
10+
}
11+
12+
return new JsonSlurper().parseText(output.text)
13+
}
14+
15+
ext.autolinkingInfo = { File buildDir ->
16+
def autolinking = file("${buildDir}/generated/rnta/autolinking.json")
17+
return new JsonSlurper().parseText(autolinking.text)
18+
}

android/config-plugins.gradle

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apply(from: "${buildscript.sourceFile.getParent()}/node.gradle")
2+
3+
ext.applyConfigPlugins = { File rootDir, String testAppDir ->
4+
if (!findNodeModulesPath("@expo/config-plugins", rootDir)) {
5+
return
6+
}
7+
8+
String[] patch = ["node", "${testAppDir}/scripts/apply-config-plugins.mjs", "--android"]
9+
def stderr = new StringBuffer()
10+
def proc = Runtime.runtime.exec(patch, null, rootDir)
11+
proc.waitForProcessOutput(null, stderr)
12+
if (proc.exitValue() != 0) {
13+
throw new RuntimeException("Failed to apply config plugins:\n${stderr}")
14+
}
15+
}

android/dependencies.gradle

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,47 @@
1-
ext {
2-
apply(from: "${buildscript.sourceFile.getParent()}/test-app-util.gradle")
1+
apply(from: "${buildscript.sourceFile.getParent()}/node.gradle")
2+
apply(from: "${buildscript.sourceFile.getParent()}/react-native.gradle")
33

4-
/**
5-
* Returns the recommended Gradle plugin version for the specified React Native
6-
* version.
7-
*/
8-
def getDefaultGradlePluginVersion = { reactNativeVersion ->
9-
// Gradle plugin version can be found in the template:
10-
// https://github.com/facebook/react-native/blob/main/packages/react-native/template/android/build.gradle
11-
if (reactNativeVersion == 0 || reactNativeVersion >= v(0, 73, 0)) {
12-
return ""
13-
} else if (reactNativeVersion >= v(0, 71, 0)) {
14-
return "7.3.1"
15-
} else {
16-
return "7.2.2"
17-
}
4+
/**
5+
* Returns the recommended Gradle plugin version for the specified React Native
6+
* version.
7+
*/
8+
def getDefaultGradlePluginVersion = { int reactNativeVersion ->
9+
// Gradle plugin version can be found in the template:
10+
// https://github.com/facebook/react-native/blob/main/packages/react-native/template/android/build.gradle
11+
if (reactNativeVersion == 0 || reactNativeVersion >= v(0, 73, 0)) {
12+
return ""
13+
} else if (reactNativeVersion >= v(0, 71, 0)) {
14+
return "7.3.1"
15+
} else {
16+
return "7.2.2"
1817
}
18+
}
1919

20-
// TODO: Bump `minSdkVersion` to 24 in 4.0
21-
def getDefaultMinSdkVersion = { reactNativeVersion ->
22-
if (reactNativeVersion >= v(0, 76, 0)) {
23-
return 24
24-
} else {
25-
return 23
26-
}
20+
// TODO: Bump `minSdkVersion` to 24 in 4.0
21+
def getDefaultMinSdkVersion = { int reactNativeVersion ->
22+
if (reactNativeVersion >= v(0, 76, 0)) {
23+
return 24
24+
} else {
25+
return 23
2726
}
27+
}
2828

29+
def getKotlinVersion = { File baseDir ->
30+
def fallbackVersion = "1.7.21"
31+
32+
def packagePath = findNodeModulesPath("react-native", baseDir)
33+
def versionCatalog = file("${packagePath}/gradle/libs.versions.toml")
34+
if (!versionCatalog.exists()) {
35+
return fallbackVersion
36+
}
37+
38+
def m = versionCatalog.text =~ /kotlin = "([.0-9]+)"/
39+
def version = m.size() > 0 ? m[0][1] : fallbackVersion
40+
logger.info("Detected Kotlin version: ${version}")
41+
return version
42+
}
43+
44+
ext {
2945
reactNativeVersion = getPackageVersionNumber("react-native", rootDir)
3046

3147
compileSdkVersion = rootProject.findProperty("react.compileSdkVersion") ?: 34

android/gradle-wrapper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const {
2020
const INT_MAX = 2 ** 31 - 1;
2121

2222
/**
23-
* This table is also used by `android/test-app-util.gradle`!
23+
* This table is also used by `android/utils.gradle`!
2424
*
2525
* We have two implementations because there are currently two ways to build the
2626
* Android app. If built via `@react-native-community/cli`, this script will be

android/manifest.gradle

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import groovy.json.JsonSlurper
2+
import java.nio.file.Paths
3+
4+
def _manifest = null
5+
6+
ext.getAppName = {
7+
def manifest = getManifest()
8+
if (manifest != null) {
9+
def displayName = manifest["displayName"]
10+
if (displayName instanceof String) {
11+
return displayName
12+
}
13+
14+
def name = manifest["name"]
15+
if (name instanceof String) {
16+
return name
17+
}
18+
}
19+
20+
return "ReactTestApp"
21+
}
22+
23+
ext.getApplicationId = {
24+
def manifest = getManifest()
25+
if (manifest != null) {
26+
def config = manifest["android"]
27+
if (config instanceof Object && config.containsKey("package")) {
28+
return config["package"]
29+
}
30+
}
31+
32+
return "com.microsoft.reacttestapp"
33+
}
34+
35+
ext.getArchitectures = { Project project ->
36+
def archs = project.findProperty("react.nativeArchitectures")
37+
?: project.findProperty("reactNativeArchitectures")
38+
return archs != null
39+
? archs.split(",")
40+
: ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
41+
}
42+
43+
ext.getManifest = {
44+
if (_manifest == null) {
45+
def manifestFile = findFile("app.json")
46+
if (manifestFile == null) {
47+
return null
48+
}
49+
50+
_manifest = new JsonSlurper().parseText(manifestFile.text)
51+
}
52+
return _manifest
53+
}
54+
55+
ext.getSigningConfigs = {
56+
def safeSetMap = { varName, map, prop, defaultVal ->
57+
map[varName] = prop.containsKey(varName) ? prop.get(varName) : defaultVal
58+
}
59+
60+
def definedConfigs = new LinkedHashMap<String, Object>()
61+
def manifestFile = findFile("app.json")
62+
if (manifestFile != null) {
63+
def manifest = new JsonSlurper().parseText(manifestFile.text)
64+
65+
if (!manifest["android"]) {
66+
return definedConfigs
67+
}
68+
69+
def signingConfigs = manifest["android"]["signingConfigs"]
70+
if (signingConfigs) {
71+
signingConfigs.each { config ->
72+
def configName = config.key
73+
def props = config.value
74+
def pathStoreFile = props.containsKey("storeFile")
75+
? Paths.get(manifestFile.getParent(), props.get("storeFile")).normalize().toAbsolutePath()
76+
: null
77+
if (pathStoreFile == null || !file(pathStoreFile).exists() || !file(pathStoreFile).isFile()) {
78+
throw new FileNotFoundException("Signing storeFile for flavor ${configName} is missing: " + pathStoreFile)
79+
}
80+
81+
def signConfig = new LinkedHashMap<String, Object>()
82+
safeSetMap("keyAlias", signConfig, props, "androiddebugkey")
83+
safeSetMap("keyPassword", signConfig, props, "android")
84+
safeSetMap("storePassword", signConfig, props, "android")
85+
signConfig["storeFile"] = pathStoreFile.toFile()
86+
definedConfigs[configName] = signConfig
87+
}
88+
}
89+
}
90+
91+
return definedConfigs
92+
}
93+
94+
ext.getSingleAppMode = {
95+
def manifest = getManifest()
96+
if (manifest != null) {
97+
def singleApp = manifest["singleApp"]
98+
if (singleApp instanceof String) {
99+
return singleApp
100+
}
101+
}
102+
103+
return false
104+
}
105+
106+
ext.getVersionCode = {
107+
def manifest = getManifest()
108+
if (manifest != null) {
109+
def config = manifest["android"]
110+
if (config instanceof Object && config.containsKey("versionCode")) {
111+
return config["versionCode"]
112+
}
113+
}
114+
115+
return 1
116+
}
117+
118+
ext.getVersionName = {
119+
def manifest = getManifest()
120+
if (manifest != null) {
121+
def version = manifest["version"]
122+
if (version instanceof String) {
123+
return version
124+
}
125+
}
126+
127+
return "1.0"
128+
}

android/media-types.gradle

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
ext.isFontFile = { File file ->
2+
// https://github.com/facebook/react-native/blob/3dfedbc1aec18a4255e126fde96d5dc7b1271ea7/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/assets/ReactFontManager.java#L28
3+
return [".otf", ".ttf"].any { file.name.endsWith(it) }
4+
}
5+
6+
ext.isMediaFile = { File file ->
7+
// https://developer.android.com/media/platform/supported-formats
8+
return [
9+
".3gp",
10+
".aac",
11+
".amr",
12+
".flac",
13+
".imy",
14+
".m4a",
15+
".mid",
16+
".mkv",
17+
".mp3",
18+
".mp4",
19+
".mxmf",
20+
".ogg",
21+
".ota",
22+
".rtttl",
23+
".rtx",
24+
".ts",
25+
".wav",
26+
".webm",
27+
".xmf",
28+
].any { file.name.endsWith(it) }
29+
}

android/node.gradle

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import groovy.json.JsonSlurper
2+
import java.nio.file.Paths
3+
4+
apply(from: "${buildscript.sourceFile.getParent()}/utils.gradle")
5+
6+
def _dependencies = [:]
7+
8+
/**
9+
* Finds the path of the installed npm package with the given name using Node's
10+
* module resolution algorithm, which searches "node_modules" directories up to
11+
* the file system root. This handles various cases, including:
12+
*
13+
* - Working in the open-source RN repo:
14+
* Gradle: /path/to/react-native/ReactAndroid
15+
* Node module: /path/to/react-native/node_modules/[package]
16+
*
17+
* - Installing RN as a dependency of an app and searching for hoisted
18+
* dependencies:
19+
* Gradle: /path/to/app/node_modules/react-native/ReactAndroid
20+
* Node module: /path/to/app/node_modules/[package]
21+
*
22+
* - Working in a larger repo (e.g., Facebook) that contains RN:
23+
* Gradle: /path/to/repo/path/to/react-native/ReactAndroid
24+
* Node module: /path/to/repo/node_modules/[package]
25+
*
26+
* The search begins at the given base directory (a File object). The returned
27+
* path is a string.
28+
*/
29+
ext.findNodeModulesPath = { String packageName, File baseDir ->
30+
def module = _dependencies[packageName]
31+
if (module != null) {
32+
return module.path
33+
}
34+
35+
def basePath = baseDir.toPath().normalize()
36+
37+
// Node's module resolution algorithm searches up to the root directory,
38+
// after which the base path will be null
39+
while (basePath) {
40+
def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName)
41+
if (candidatePath.toFile().exists()) {
42+
// Resolve the real path in case we're dealing with symlinks
43+
def resolvedPath = candidatePath.toRealPath().toString()
44+
_dependencies[packageName] = [path: resolvedPath]
45+
return resolvedPath
46+
}
47+
48+
basePath = basePath.getParent()
49+
}
50+
51+
return null
52+
}
53+
54+
ext.getPackageManifest = { String packageName, File baseDir ->
55+
def module = _dependencies[packageName]
56+
if (module != null && module.manifest != null) {
57+
return module.manifest
58+
}
59+
60+
def packagePath = findNodeModulesPath(packageName, baseDir)
61+
def packageJson = file("${packagePath}/package.json")
62+
def manifest = new JsonSlurper().parseText(packageJson.text)
63+
_dependencies[packageName].manifest = manifest
64+
return manifest
65+
}
66+
67+
ext.getPackageVersion = { String packageName, File baseDir ->
68+
def manifest = getPackageManifest(packageName, baseDir)
69+
return manifest["version"]
70+
}
71+
72+
ext.getPackageVersionNumber = { String packageName, File baseDir ->
73+
return toVersionNumber(getPackageVersion(packageName, baseDir))
74+
}

0 commit comments

Comments
 (0)