@callstack/react-native-brownfield 3.11.0 → 3.13.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 +26 -0
- package/gradle-plugin/brownfield/build.gradle.kts +134 -0
- package/gradle-plugin/brownfield/config/detekt/detekt.yml +936 -0
- package/gradle-plugin/brownfield/gradle/libs.versions.toml +19 -0
- package/gradle-plugin/brownfield/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle-plugin/brownfield/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/gradle-plugin/brownfield/gradle.properties +14 -0
- package/gradle-plugin/brownfield/gradlew +249 -0
- package/gradle-plugin/brownfield/gradlew.bat +92 -0
- package/gradle-plugin/brownfield/settings.gradle +7 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/artifacts/ArtifactsResolver.kt +132 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/exceptions/NameSpaceNotFound.kt +4 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/exceptions/TaskNotFound.kt +4 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/ExpoPublishingHelper.kt +432 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/BrownfieldPrimitives.kt +31 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/ExpoProjectionPrimitives.kt +22 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/LocalMavenUtils.kt +83 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/ReflectionUtils.kt +79 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/VersionMediatingDependencySet.kt +100 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/CustomDependencyResolver.kt +50 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/ProjectConfigurations.kt +107 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RClassTransformer.kt +131 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNBrownfieldPlugin.kt +171 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +149 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/AssetTaskProcessor.kt +29 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ExplodeTaskProvider.kt +63 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/JNILibsProcessor.kt +165 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ManifestTaskProcessor.kt +74 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/MergeProcessor.kt +55 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ProguardProcessor.kt +61 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ResourceTaskProcessor.kt +26 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantHelper.kt +61 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantPackagesProperty.kt +21 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantTaskProvider.kt +103 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/BaseProject.kt +17 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/BundleTaskProvider.kt +46 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Constants.kt +58 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/ExplodeAarTask.kt +72 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/GradleILogger.kt +59 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Logging.kt +24 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/ModuleInfo.kt +22 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/AndroidArchiveLibrary.kt +77 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/DirectoryManager.kt +20 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Extension.kt +44 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/StringExtensions.kt +5 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/StringMatcher.kt +21 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Utils.kt +59 -0
- package/ios/Expo/ExpoHostRuntime.swift +3 -2
- package/ios/ReactNativeBrownfield.swift +1 -1
- package/ios/Vanilla/ReactNativeHostRuntime.swift +5 -2
- package/ios/swiftpm/Sources/BrownfieldBundleSupport/BrownfieldBundleURLResolver.swift +11 -5
- package/ios/swiftpm/Tests/BrownfieldBundleSupportTests/BrownfieldBundleURLResolverTests.swift +17 -5
- package/lib/commonjs/expo-config-plugin/android/utils/constants.js +1 -1
- package/lib/commonjs/expo-config-plugin/android/utils/constants.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js +2 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/expo-config-plugin/android/utils/constants.js +1 -1
- package/lib/module/expo-config-plugin/android/utils/constants.js.map +1 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js +2 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
- package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/constants.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
- package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +6 -4
- package/scripts/sync-gradle-plugin-source.js +58 -0
- package/src/expo-config-plugin/android/utils/constants.ts +1 -1
- package/src/expo-config-plugin/ios/xcodeHelpers.ts +14 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.plugin
|
|
2
|
+
|
|
3
|
+
import com.android.build.api.variant.LibraryAndroidComponentsExtension
|
|
4
|
+
import com.android.build.gradle.LibraryExtension
|
|
5
|
+
import com.callstack.react.brownfield.exceptions.NameSpaceNotFound
|
|
6
|
+
import com.callstack.react.brownfield.utils.Extension
|
|
7
|
+
import com.callstack.react.brownfield.utils.Utils
|
|
8
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
9
|
+
import org.gradle.api.Project
|
|
10
|
+
import org.gradle.api.Task
|
|
11
|
+
import org.gradle.api.tasks.Copy
|
|
12
|
+
import java.io.File
|
|
13
|
+
|
|
14
|
+
object RNSourceSets {
|
|
15
|
+
private lateinit var project: Project
|
|
16
|
+
private lateinit var extension: Extension
|
|
17
|
+
private lateinit var androidExtension: LibraryExtension
|
|
18
|
+
|
|
19
|
+
fun configure(
|
|
20
|
+
project: Project,
|
|
21
|
+
extension: Extension,
|
|
22
|
+
) {
|
|
23
|
+
this.project = project
|
|
24
|
+
this.extension = extension
|
|
25
|
+
|
|
26
|
+
androidExtension = this.project.extensions.getByType(LibraryExtension::class.java)
|
|
27
|
+
|
|
28
|
+
configureSourceSets()
|
|
29
|
+
configureTasks()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private fun getAppProject(): Project = project.rootProject.project(extension.appProjectName)
|
|
33
|
+
|
|
34
|
+
private fun getAppBuildDir() = getAppProject().layout.buildDirectory.get()
|
|
35
|
+
|
|
36
|
+
private fun getModuleBuildDir() = project.layout.buildDirectory.get()
|
|
37
|
+
|
|
38
|
+
private fun configureSourceSets() {
|
|
39
|
+
// 1. Get the 'androidComponents' extension for the new Variant API
|
|
40
|
+
val componentsExtension = project.extensions.getByType(LibraryAndroidComponentsExtension::class.java)
|
|
41
|
+
|
|
42
|
+
// Move the non-variant-specific configuration out of the loop
|
|
43
|
+
androidExtension.sourceSets.named("main") { sourceSet ->
|
|
44
|
+
// This path is not variant-specific, so it's added once here.
|
|
45
|
+
sourceSet.java.srcDir("${getModuleBuildDir()}/generated/autolinking/src/main/java")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 2. Use the onVariants block to configure each variant
|
|
49
|
+
componentsExtension.onVariants { variant ->
|
|
50
|
+
val variantName = variant.name
|
|
51
|
+
val bundledAssetsVariantName =
|
|
52
|
+
Utils.getBundledAssetsVariantName(
|
|
53
|
+
variantName = variantName,
|
|
54
|
+
buildTypeName = variant.buildType,
|
|
55
|
+
isDebuggable = variant.debuggable,
|
|
56
|
+
)
|
|
57
|
+
val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized()
|
|
58
|
+
|
|
59
|
+
// 3. Lazily configure the 'variant-specific' source set using .named()
|
|
60
|
+
androidExtension.sourceSets.named(variantName) { sourceSet ->
|
|
61
|
+
// Paths are collected and added, similar to your improved version
|
|
62
|
+
val bundlePathSegments =
|
|
63
|
+
listOf(
|
|
64
|
+
// outputs for RN <= 0.81
|
|
65
|
+
"createBundle${capitalizedBundledAssetsVariantName}JsAndAssets",
|
|
66
|
+
// outputs for RN >= 0.82
|
|
67
|
+
"react/$bundledAssetsVariantName",
|
|
68
|
+
// expo update resources
|
|
69
|
+
"create${capitalizedBundledAssetsVariantName}UpdatesResources",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
// Add the variant-specific generated asset and resource directories
|
|
73
|
+
val appBuildDir = getAppBuildDir()
|
|
74
|
+
sourceSet.assets.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/assets/$it" })
|
|
75
|
+
sourceSet.res.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/res/$it" })
|
|
76
|
+
sourceSet.jniLibs.srcDirs("libs${variantName.capitalized()}")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private fun getLibraryNameSpace(): String {
|
|
82
|
+
val nameSpace = androidExtension.namespace
|
|
83
|
+
return nameSpace
|
|
84
|
+
?: throw NameSpaceNotFound("namespace must be defined in your android library build.gradle")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private fun patchRNEntryPoint(
|
|
88
|
+
task: Task,
|
|
89
|
+
path: String,
|
|
90
|
+
) {
|
|
91
|
+
val rnEntryPointTaskName = "generateReactNativeEntryPoint"
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* If `generateReactNativeEntryPoint` task does not exist, we early return. It means
|
|
95
|
+
* the consumer library is running on RN version < 0.80
|
|
96
|
+
*/
|
|
97
|
+
val rnEntryPointTask = getAppProject().tasks.findByName(rnEntryPointTaskName) ?: return
|
|
98
|
+
|
|
99
|
+
task.dependsOn(rnEntryPointTask)
|
|
100
|
+
val sourceFile =
|
|
101
|
+
File(
|
|
102
|
+
getModuleBuildDir().toString(),
|
|
103
|
+
"$path/com/facebook/react/ReactNativeApplicationEntryPoint.java",
|
|
104
|
+
)
|
|
105
|
+
task.doLast {
|
|
106
|
+
if (sourceFile.exists()) {
|
|
107
|
+
var content = sourceFile.readText()
|
|
108
|
+
val nameSpace = getLibraryNameSpace()
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* We use look-ahead regex to replace any occurrences with Build.Config referenced via the old(app) package
|
|
112
|
+
*
|
|
113
|
+
* \b[\w.]+ → matches the old package
|
|
114
|
+
* (?=\.BuildConfig) → only if it’s immediately followed by that suffix
|
|
115
|
+
*/
|
|
116
|
+
val regex = Regex("""\b[\w.]+(?=\.BuildConfig)""")
|
|
117
|
+
content = content.replace(regex, nameSpace)
|
|
118
|
+
sourceFile.writeText(content)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private fun configureTasks() {
|
|
124
|
+
project.tasks.register("copyAutolinkingSources", Copy::class.java) {
|
|
125
|
+
val path = "generated/autolinking/src/main/java"
|
|
126
|
+
val appBuildDir = getAppBuildDir()
|
|
127
|
+
it.dependsOn(":${getAppProject().name}:generateAutolinkingPackageList")
|
|
128
|
+
it.from("$appBuildDir/$path")
|
|
129
|
+
it.into("${getModuleBuildDir()}/$path")
|
|
130
|
+
|
|
131
|
+
patchRNEntryPoint(it, path)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
project.tasks.named("preBuild").configure {
|
|
135
|
+
/**
|
|
136
|
+
* Ensure auto-generated sources are available before compilation.
|
|
137
|
+
*
|
|
138
|
+
* This hooks into the global `preBuild` task, so the dependency runs
|
|
139
|
+
* regardless of build variant. Use this only when the generated sources
|
|
140
|
+
* are identical for all variants (debug/release).
|
|
141
|
+
*
|
|
142
|
+
* If variant-specific
|
|
143
|
+
* files are needed, prefer `preDebugBuild` / `preReleaseBuild` under
|
|
144
|
+
* `VariantProcessor.processVariant`
|
|
145
|
+
*/
|
|
146
|
+
it.dependsOn("copyAutolinkingSources")
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.LibraryExtension
|
|
4
|
+
import com.android.build.gradle.api.LibraryVariant
|
|
5
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
6
|
+
import org.gradle.api.Project
|
|
7
|
+
|
|
8
|
+
object AssetTaskProcessor {
|
|
9
|
+
fun process(
|
|
10
|
+
variant: LibraryVariant,
|
|
11
|
+
project: Project,
|
|
12
|
+
aarLibraries: List<AndroidArchiveLibrary>,
|
|
13
|
+
) {
|
|
14
|
+
val assetsTask = variant.mergeAssetsProvider.get()
|
|
15
|
+
|
|
16
|
+
val androidExtension = project.extensions.getByName("android") as LibraryExtension
|
|
17
|
+
assetsTask.doFirst {
|
|
18
|
+
val filteredSourceSets =
|
|
19
|
+
androidExtension.sourceSets.filter { it.name == variant.name }
|
|
20
|
+
|
|
21
|
+
filteredSourceSets.forEach { sourceSet ->
|
|
22
|
+
val filteredAarLibs = aarLibraries.filter { it.getAssetsDir().exists() }
|
|
23
|
+
if (!filteredAarLibs.isEmpty()) {
|
|
24
|
+
sourceSet.assets.srcDirs(filteredAarLibs.map { it.getAssetsDir() })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.api.LibraryVariant
|
|
4
|
+
import com.callstack.react.brownfield.shared.BundleTaskProvider
|
|
5
|
+
import com.callstack.react.brownfield.shared.ExplodeAarTask
|
|
6
|
+
import com.callstack.react.brownfield.shared.UnresolvedArtifactInfo
|
|
7
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
8
|
+
import org.gradle.api.Project
|
|
9
|
+
import org.gradle.api.Task
|
|
10
|
+
import org.gradle.api.tasks.TaskProvider
|
|
11
|
+
import org.gradle.api.tasks.bundling.Zip
|
|
12
|
+
import java.io.File
|
|
13
|
+
|
|
14
|
+
object ExplodeTaskProvider {
|
|
15
|
+
fun getTask(
|
|
16
|
+
variant: LibraryVariant,
|
|
17
|
+
project: Project,
|
|
18
|
+
artifacts: List<UnresolvedArtifactInfo>,
|
|
19
|
+
): TaskProvider<ExplodeAarTask> {
|
|
20
|
+
val variantTaskProvider = VariantTaskProvider(project)
|
|
21
|
+
val bundleProvider = BundleTaskProvider(variantTaskProvider)
|
|
22
|
+
val capitalizedVariantName = variant.name.capitalized()
|
|
23
|
+
|
|
24
|
+
return project.tasks.register(
|
|
25
|
+
"explode${capitalizedVariantName}Aar",
|
|
26
|
+
ExplodeAarTask::class.java,
|
|
27
|
+
) { task ->
|
|
28
|
+
task.variantName.set(variant.name)
|
|
29
|
+
task.minifyEnabled.set(variant.buildType.isMinifyEnabled)
|
|
30
|
+
|
|
31
|
+
val finalArtifacts = mutableListOf<UnresolvedArtifactInfo>()
|
|
32
|
+
artifacts.forEach { art ->
|
|
33
|
+
var artifactPath = art.file
|
|
34
|
+
if (art.isExpoPublishDependency != true) {
|
|
35
|
+
val defaultTaskName = "bundle${capitalizedVariantName}Aar"
|
|
36
|
+
val dependencyProject = project.project(":${art.moduleName}")
|
|
37
|
+
val bundleTaskProvider = bundleProvider.getBundleTask(dependencyProject, variant)
|
|
38
|
+
val taskName = bundleTaskProvider?.name ?: defaultTaskName
|
|
39
|
+
|
|
40
|
+
dependencyProject.tasks.findByName(taskName)?.let { task.dependsOn(it) }
|
|
41
|
+
artifactPath = createArtifactFile(bundleTaskProvider?.get() as Task).absolutePath
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
finalArtifacts.add(
|
|
45
|
+
UnresolvedArtifactInfo(
|
|
46
|
+
art.moduleGroup,
|
|
47
|
+
art.moduleName,
|
|
48
|
+
art.moduleVersion,
|
|
49
|
+
artifactPath,
|
|
50
|
+
isExpoPublishDependency = art.isExpoPublishDependency,
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
task.inputArtifacts.set(finalArtifacts)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private fun createArtifactFile(bundle: Task): File {
|
|
60
|
+
val packageLibraryProvider = bundle as Zip
|
|
61
|
+
return File(packageLibraryProvider.destinationDirectory.get().asFile, packageLibraryProvider.archiveFileName.get())
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.LibraryExtension
|
|
4
|
+
import com.callstack.react.brownfield.exceptions.TaskNotFound
|
|
5
|
+
import com.callstack.react.brownfield.shared.Logging
|
|
6
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
7
|
+
import com.callstack.react.brownfield.utils.Extension
|
|
8
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
9
|
+
import org.gradle.api.Project
|
|
10
|
+
import org.gradle.api.tasks.Copy
|
|
11
|
+
import org.gradle.api.tasks.TaskProvider
|
|
12
|
+
import java.io.File
|
|
13
|
+
|
|
14
|
+
class JNILibsProcessor(val project: Project) {
|
|
15
|
+
fun processJniLibs(
|
|
16
|
+
aarLibraries: Collection<AndroidArchiveLibrary>,
|
|
17
|
+
variantName: String,
|
|
18
|
+
) {
|
|
19
|
+
val capitalizedVariantName = variantName.capitalized()
|
|
20
|
+
val taskName = "merge${capitalizedVariantName}JniLibFolders"
|
|
21
|
+
val mergeJniLibsTask = project.tasks.named(taskName)
|
|
22
|
+
|
|
23
|
+
if (!mergeJniLibsTask.isPresent) {
|
|
24
|
+
throw TaskNotFound("Task $taskName not found")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
val androidExtension = project.extensions.getByName("android") as LibraryExtension
|
|
28
|
+
val copyTask = copySoLibsTask(variantName)
|
|
29
|
+
|
|
30
|
+
mergeJniLibsTask.configure {
|
|
31
|
+
it.dependsOn(copyTask)
|
|
32
|
+
|
|
33
|
+
it.doFirst {
|
|
34
|
+
val projectExt = project.extensions.getByType(Extension::class.java)
|
|
35
|
+
val existingJNILibs =
|
|
36
|
+
listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
|
|
37
|
+
.associateWith { mutableListOf<String>() }
|
|
38
|
+
.toMutableMap()
|
|
39
|
+
for (archiveLibrary in aarLibraries) {
|
|
40
|
+
val jniDir = archiveLibrary.getJniDir()
|
|
41
|
+
processNestedLibs(jniDir.listFiles(), existingJNILibs)
|
|
42
|
+
if (!projectExt.useStrippedSoFiles) {
|
|
43
|
+
if (jniDir.exists()) {
|
|
44
|
+
val filteredSourceSets =
|
|
45
|
+
androidExtension.sourceSets.filter { sourceSet -> sourceSet.name == variantName }
|
|
46
|
+
filteredSourceSets.forEach { sourceSet ->
|
|
47
|
+
sourceSet.jniLibs.srcDir(
|
|
48
|
+
jniDir,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (projectExt.useStrippedSoFiles) {
|
|
55
|
+
copyStrippedSoLibs(variantName, existingJNILibs)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun getStrippedLibsPath(variantName: String): Pair<File, File> {
|
|
62
|
+
val projectExt = project.extensions.getByType(Extension::class.java)
|
|
63
|
+
val appProject = project.rootProject.project(projectExt.appProjectName)
|
|
64
|
+
val appBuildDir = appProject.layout.buildDirectory.get()
|
|
65
|
+
|
|
66
|
+
val capitalizedVariant = variantName.capitalized()
|
|
67
|
+
|
|
68
|
+
val fromDir =
|
|
69
|
+
appBuildDir
|
|
70
|
+
.dir("intermediates/stripped_native_libs/$variantName/strip${capitalizedVariant}DebugSymbols/out/lib")
|
|
71
|
+
.asFile
|
|
72
|
+
|
|
73
|
+
val intoDir = project.rootProject.file("${project.name}/libs$capitalizedVariant")
|
|
74
|
+
|
|
75
|
+
return Pair(fromDir, intoDir)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private fun copySoLibsTask(variantName: String): TaskProvider<Copy> {
|
|
79
|
+
val capitalizedVariant = variantName.capitalized()
|
|
80
|
+
val projectExt = project.extensions.getByType(Extension::class.java)
|
|
81
|
+
val appProject = project.rootProject.project(projectExt.appProjectName)
|
|
82
|
+
|
|
83
|
+
val stripTask = ":${appProject.name}:strip${capitalizedVariant}DebugSymbols"
|
|
84
|
+
val codegenTask = ":${project.name}:generateCodegenSchemaFromJavaScript"
|
|
85
|
+
|
|
86
|
+
val (fromDir, intoDir) = getStrippedLibsPath(variantName)
|
|
87
|
+
|
|
88
|
+
return project.tasks.register("copy${capitalizedVariant}LibSources", Copy::class.java) {
|
|
89
|
+
it.dependsOn(stripTask, codegenTask)
|
|
90
|
+
it.from(fromDir)
|
|
91
|
+
it.into(intoDir)
|
|
92
|
+
|
|
93
|
+
it.include("**/libappmodules.so", "**/libreact_codegen_*.so")
|
|
94
|
+
projectExt.dynamicLibs.forEach { lib -> it.include("**/$lib") }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private fun copyStrippedSoLibs(
|
|
99
|
+
variantName: String,
|
|
100
|
+
existingJNILibs: MutableMap<String, MutableList<String>>,
|
|
101
|
+
) {
|
|
102
|
+
val (fromDir, intoDir) = getStrippedLibsPath(variantName)
|
|
103
|
+
|
|
104
|
+
existingJNILibs.forEach { (arch, libNames) ->
|
|
105
|
+
copyLibsForArchitecture(fromDir, intoDir, arch, libNames)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private fun copyLibsForArchitecture(
|
|
110
|
+
fromDir: File,
|
|
111
|
+
intoDir: File,
|
|
112
|
+
arch: String,
|
|
113
|
+
libNames: List<String>,
|
|
114
|
+
) {
|
|
115
|
+
val sourceArchDir = File(fromDir, arch)
|
|
116
|
+
if (!sourceArchDir.exists()) return
|
|
117
|
+
|
|
118
|
+
val destArchDir = File(intoDir, arch).apply { mkdirs() }
|
|
119
|
+
|
|
120
|
+
libNames.forEach { libName ->
|
|
121
|
+
copyLibFile(sourceArchDir, destArchDir, libName)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private fun copyLibFile(
|
|
126
|
+
sourceArchDir: File,
|
|
127
|
+
destArchDir: File,
|
|
128
|
+
libName: String,
|
|
129
|
+
) {
|
|
130
|
+
val sourceFile = File(sourceArchDir, libName)
|
|
131
|
+
val destFile = File(destArchDir, libName)
|
|
132
|
+
|
|
133
|
+
if (sourceFile.exists()) {
|
|
134
|
+
try {
|
|
135
|
+
sourceFile.copyTo(destFile, overwrite = true)
|
|
136
|
+
} catch (e: java.io.IOException) {
|
|
137
|
+
Logging.log("Failed to copy $libName: ${e.message}")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private fun processNestedLibs(
|
|
143
|
+
files: Array<File>?,
|
|
144
|
+
existingJNILibs: MutableMap<String, MutableList<String>>,
|
|
145
|
+
) {
|
|
146
|
+
files?.forEach { folder ->
|
|
147
|
+
val libFiles = folder.listFiles() ?: return@forEach
|
|
148
|
+
val libList = existingJNILibs[folder.name] ?: return@forEach
|
|
149
|
+
|
|
150
|
+
libFiles.forEach { file ->
|
|
151
|
+
if (file.name in libList) {
|
|
152
|
+
deleteFile(file)
|
|
153
|
+
} else {
|
|
154
|
+
libList.add(file.name)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private fun deleteFile(file: File) {
|
|
161
|
+
if (!file.delete()) {
|
|
162
|
+
Logging.log("Failed to delete: ${file.name}")
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.api.LibraryVariant
|
|
4
|
+
import com.android.manifmerger.ManifestMerger2
|
|
5
|
+
import com.android.manifmerger.ManifestProvider
|
|
6
|
+
import com.android.manifmerger.MergingReport
|
|
7
|
+
import com.android.utils.ILogger
|
|
8
|
+
import com.callstack.react.brownfield.shared.GradleILogger
|
|
9
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
10
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
11
|
+
import org.apache.tools.ant.BuildException
|
|
12
|
+
import org.gradle.api.Project
|
|
13
|
+
import org.gradle.api.logging.Logger
|
|
14
|
+
import java.io.BufferedWriter
|
|
15
|
+
import java.io.File
|
|
16
|
+
import java.io.FileOutputStream
|
|
17
|
+
import java.io.OutputStreamWriter
|
|
18
|
+
|
|
19
|
+
object ManifestTaskProcessor {
|
|
20
|
+
fun process(
|
|
21
|
+
variant: LibraryVariant,
|
|
22
|
+
project: Project,
|
|
23
|
+
aarLibraries: List<AndroidArchiveLibrary>,
|
|
24
|
+
) {
|
|
25
|
+
val processManifestTask = variant.outputs.first().processManifestProvider.get()
|
|
26
|
+
val variantName = variant.name
|
|
27
|
+
processManifestTask.doLast {
|
|
28
|
+
val buildDir = project.layout.buildDirectory.get()
|
|
29
|
+
val manifestOutput =
|
|
30
|
+
project.file(
|
|
31
|
+
"$buildDir/intermediates/merged_manifest/$variantName/process${variantName.capitalized()}Manifest/AndroidManifest.xml",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
val inputManifests = aarLibraries.map { it.getManifestFile() }
|
|
35
|
+
mergeManifests(manifestOutput, inputManifests, manifestOutput, project.logger)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private fun mergeManifests(
|
|
40
|
+
mainManifestFile: File,
|
|
41
|
+
secondaryManifestFiles: List<File>,
|
|
42
|
+
outputFile: File,
|
|
43
|
+
logger: Logger,
|
|
44
|
+
) {
|
|
45
|
+
val iLogger: ILogger = GradleILogger(logger)
|
|
46
|
+
val mergerInvoker = ManifestMerger2.newMerger(mainManifestFile, iLogger, ManifestMerger2.MergeType.LIBRARY)
|
|
47
|
+
val manifestProviders = mutableListOf<ManifestProvider>()
|
|
48
|
+
|
|
49
|
+
val filteredSecondaryManifests = secondaryManifestFiles.filter { it.exists() }
|
|
50
|
+
filteredSecondaryManifests.forEach { file ->
|
|
51
|
+
manifestProviders.add(
|
|
52
|
+
object : ManifestProvider {
|
|
53
|
+
override fun getManifest(): File = file.absoluteFile
|
|
54
|
+
|
|
55
|
+
override fun getName(): String = file.name
|
|
56
|
+
},
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
mergerInvoker.addManifestProviders(manifestProviders)
|
|
61
|
+
val mergingReport: MergingReport = mergerInvoker.merge()
|
|
62
|
+
|
|
63
|
+
if (mergingReport.result.isError) {
|
|
64
|
+
logger.error(mergingReport.reportString)
|
|
65
|
+
mergingReport.log(iLogger)
|
|
66
|
+
throw BuildException(mergingReport.reportString)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
BufferedWriter(OutputStreamWriter(FileOutputStream(outputFile), "UTF-8")).use { writer ->
|
|
70
|
+
writer.append(mergingReport.getMergedDocument(MergingReport.MergedManifestKind.MERGED))
|
|
71
|
+
writer.flush()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
4
|
+
import org.gradle.api.Project
|
|
5
|
+
import java.io.File
|
|
6
|
+
|
|
7
|
+
object MergeProcessor {
|
|
8
|
+
fun mergeClassesJarIntoClasses(
|
|
9
|
+
project: Project,
|
|
10
|
+
androidLibraries: Collection<AndroidArchiveLibrary>,
|
|
11
|
+
folderOut: File,
|
|
12
|
+
) {
|
|
13
|
+
val allJarFiles: MutableCollection<File> = ArrayList()
|
|
14
|
+
val filteredLibs = getFilteredAarLibs(androidLibraries)
|
|
15
|
+
filteredLibs.forEach {
|
|
16
|
+
allJarFiles.add(it.getClassesJarFile())
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
val filteredAllJarFiles = allJarFiles.filter { it.exists() }
|
|
20
|
+
filteredAllJarFiles.forEach { jarFile ->
|
|
21
|
+
project.copy {
|
|
22
|
+
it.from(project.zipTree(jarFile))
|
|
23
|
+
it.into(folderOut)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fun mergeLibsIntoClasses(
|
|
29
|
+
project: Project,
|
|
30
|
+
androidLibraries: Collection<AndroidArchiveLibrary>,
|
|
31
|
+
jarFiles: Collection<File>,
|
|
32
|
+
outputDir: File,
|
|
33
|
+
) {
|
|
34
|
+
val allJarFiles: MutableCollection<File> = ArrayList()
|
|
35
|
+
val filteredLibs = getFilteredAarLibs(androidLibraries)
|
|
36
|
+
filteredLibs.forEach {
|
|
37
|
+
allJarFiles.addAll(it.getLocalJars())
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
val filteredJarFiles = jarFiles.filter { it.exists() }
|
|
41
|
+
filteredJarFiles.forEach { allJarFiles.add(it) }
|
|
42
|
+
|
|
43
|
+
allJarFiles.forEach { jarFile ->
|
|
44
|
+
project.copy {
|
|
45
|
+
it.from(project.zipTree(jarFile))
|
|
46
|
+
it.into(outputDir)
|
|
47
|
+
it.exclude("META-INF/")
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private fun getFilteredAarLibs(androidLibraries: Collection<AndroidArchiveLibrary>): Collection<AndroidArchiveLibrary> {
|
|
53
|
+
return androidLibraries.filter { it.getExplodedAarRootDir().exists() }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.callstack.react.brownfield.exceptions.TaskNotFound
|
|
4
|
+
import com.callstack.react.brownfield.shared.Logging
|
|
5
|
+
import com.callstack.react.brownfield.utils.Utils
|
|
6
|
+
import org.gradle.api.Project
|
|
7
|
+
import org.gradle.api.file.RegularFileProperty
|
|
8
|
+
import org.gradle.api.tasks.TaskProvider
|
|
9
|
+
import java.io.File
|
|
10
|
+
|
|
11
|
+
class ProguardProcessor(val project: Project) {
|
|
12
|
+
fun processConsumerFiles(
|
|
13
|
+
proguardRules: List<File>,
|
|
14
|
+
capitalizedVariantName: String,
|
|
15
|
+
) {
|
|
16
|
+
val mergeTaskName = "merge${capitalizedVariantName}ConsumerProguardFiles"
|
|
17
|
+
val mergeFileTask = project.tasks.named(mergeTaskName)
|
|
18
|
+
|
|
19
|
+
if (!mergeFileTask.isPresent) {
|
|
20
|
+
throw TaskNotFound("Task $mergeTaskName not found")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
mergeFileTask.get().doLast {
|
|
24
|
+
val outputFile = it.outputs.files.singleFile
|
|
25
|
+
doLast(proguardRules, outputFile)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fun processGeneratedFiles(
|
|
30
|
+
proguardRules: List<File>,
|
|
31
|
+
capitalizedVariantName: String,
|
|
32
|
+
) {
|
|
33
|
+
val mergeGenerateProguardTask: TaskProvider<*>?
|
|
34
|
+
val mergeName = "merge${capitalizedVariantName}GeneratedProguardFiles"
|
|
35
|
+
mergeGenerateProguardTask = project.tasks.named(mergeName)
|
|
36
|
+
|
|
37
|
+
mergeGenerateProguardTask.get().doLast {
|
|
38
|
+
val outputFile = it.outputs.files.singleFile
|
|
39
|
+
doLast(proguardRules, outputFile)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun doLast(
|
|
44
|
+
files: List<File>,
|
|
45
|
+
outputFile: File,
|
|
46
|
+
) {
|
|
47
|
+
try {
|
|
48
|
+
val outputFileToMerge =
|
|
49
|
+
@Suppress("USELESS_IS_CHECK")
|
|
50
|
+
if (outputFile is File) {
|
|
51
|
+
outputFile
|
|
52
|
+
} else {
|
|
53
|
+
(outputFile as? RegularFileProperty)?.get()?.asFile
|
|
54
|
+
?: error("Invalid output file")
|
|
55
|
+
}
|
|
56
|
+
Utils.mergeFiles(files, outputFileToMerge)
|
|
57
|
+
} catch (e: NoSuchFileException) {
|
|
58
|
+
Logging.log(e)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.api.LibraryVariant
|
|
4
|
+
import com.callstack.react.brownfield.exceptions.TaskNotFound
|
|
5
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
6
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
7
|
+
import org.gradle.api.Project
|
|
8
|
+
|
|
9
|
+
object ResourceTaskProcessor {
|
|
10
|
+
fun process(
|
|
11
|
+
variant: LibraryVariant,
|
|
12
|
+
project: Project,
|
|
13
|
+
aarLibraries: List<AndroidArchiveLibrary>,
|
|
14
|
+
) {
|
|
15
|
+
val taskPath = "generate${variant.name.capitalized()}Resources"
|
|
16
|
+
val resourceGenTask = project.tasks.named(taskPath)
|
|
17
|
+
|
|
18
|
+
if (!resourceGenTask.isPresent) {
|
|
19
|
+
throw TaskNotFound("Task $taskPath not found")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variant.registerGeneratedResFolders(
|
|
23
|
+
project.files(aarLibraries.map { it.getResDir() }),
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.processors
|
|
2
|
+
|
|
3
|
+
import com.callstack.react.brownfield.shared.BaseProject
|
|
4
|
+
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
|
|
5
|
+
import com.callstack.react.brownfield.utils.DirectoryManager
|
|
6
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
7
|
+
import org.gradle.api.file.ConfigurableFileCollection
|
|
8
|
+
import java.io.File
|
|
9
|
+
import java.nio.file.Files
|
|
10
|
+
import java.nio.file.Path
|
|
11
|
+
import java.nio.file.Paths
|
|
12
|
+
|
|
13
|
+
class VariantHelper : BaseProject() {
|
|
14
|
+
private fun getClassPathDirFiles(variantName: String): ConfigurableFileCollection {
|
|
15
|
+
return project.files(
|
|
16
|
+
"$buildDir/intermediates/javac/$variantName/compile${variantName.capitalized()}JavaWithJavac/classes",
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fun classesMergeTaskDoFirst(
|
|
21
|
+
outputDir: File,
|
|
22
|
+
variantName: String,
|
|
23
|
+
) {
|
|
24
|
+
val pathsToDelete = mutableListOf<Path>()
|
|
25
|
+
val javacDir = getClassPathDirFiles(variantName).first()
|
|
26
|
+
project.fileTree(outputDir).forEach { path ->
|
|
27
|
+
pathsToDelete.add(
|
|
28
|
+
Paths.get(outputDir.absolutePath).relativize(Paths.get(path.absolutePath)),
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
outputDir.deleteRecursively()
|
|
32
|
+
pathsToDelete.forEach { path ->
|
|
33
|
+
Files.deleteIfExists(Paths.get("$javacDir.absolutePath/$path"))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fun classesMergeTaskDoLast(
|
|
38
|
+
outputDir: File,
|
|
39
|
+
aarLibraries: Collection<AndroidArchiveLibrary>,
|
|
40
|
+
jarFiles: MutableList<File>,
|
|
41
|
+
variantName: String,
|
|
42
|
+
isMinifyEnabled: Boolean,
|
|
43
|
+
) {
|
|
44
|
+
MergeProcessor.mergeClassesJarIntoClasses(project, aarLibraries, outputDir)
|
|
45
|
+
if (isMinifyEnabled) {
|
|
46
|
+
MergeProcessor.mergeLibsIntoClasses(project, aarLibraries, jarFiles, outputDir)
|
|
47
|
+
}
|
|
48
|
+
val javacDir = getClassPathDirFiles(variantName).first()
|
|
49
|
+
project.copy { copyTask ->
|
|
50
|
+
copyTask.from(outputDir)
|
|
51
|
+
copyTask.into(javacDir)
|
|
52
|
+
copyTask.exclude("META-INF/")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
project.copy { copyTask ->
|
|
56
|
+
copyTask.from("${outputDir.absolutePath}/META-INF")
|
|
57
|
+
copyTask.into(DirectoryManager.getKotlinMetaDirectory(variantName))
|
|
58
|
+
copyTask.include("*.kotlin_module")
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|