@callstack/react-native-brownfield 4.0.0 → 4.2.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.
Files changed (74) hide show
  1. package/gradle-plugin/brownfield/config/detekt/detekt.yml +1 -1
  2. package/gradle-plugin/brownfield/gradle.properties +1 -1
  3. package/gradle-plugin/brownfield/gradlew +0 -0
  4. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/LocalMavenUtils.kt +2 -5
  5. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/ProjectConfigurations.kt +3 -5
  6. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNBrownfieldPlugin.kt +20 -26
  7. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +23 -35
  8. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/AssetTaskProcessor.kt +51 -16
  9. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ExplodeTaskProvider.kt +6 -7
  10. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/JNILibsProcessor.kt +133 -108
  11. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ManifestTaskProcessor.kt +26 -62
  12. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/MergeProcessor.kt +7 -29
  13. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ProguardProcessor.kt +9 -46
  14. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ResourceTaskProcessor.kt +49 -11
  15. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantHelper.kt +52 -47
  16. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantTaskProvider.kt +31 -63
  17. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/BundleTaskProvider.kt +72 -27
  18. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Constants.kt +0 -1
  19. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/ExplodeAarTask.kt +2 -20
  20. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Logging.kt +1 -1
  21. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/MergeClassesTask.kt +70 -0
  22. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/MergeLibraryManifestTask.kt +178 -0
  23. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/AndroidArchiveLibrary.kt +0 -4
  24. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/DirectoryManager.kt +0 -5
  25. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Extension.kt +8 -9
  26. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Utils.kt +2 -34
  27. package/lib/commonjs/expo-config-plugin/android/utils/constants.js +1 -1
  28. package/lib/commonjs/expo-config-plugin/android/utils/formatHelpers.js +2 -0
  29. package/lib/commonjs/expo-config-plugin/android/utils/formatHelpers.js.map +1 -0
  30. package/lib/commonjs/expo-config-plugin/android/utils/gradleHelpers.js +1 -1
  31. package/lib/commonjs/expo-config-plugin/android/utils/gradleHelpers.js.map +1 -1
  32. package/lib/commonjs/expo-config-plugin/android/withAndroidModuleFiles.js +1 -1
  33. package/lib/commonjs/expo-config-plugin/android/withAndroidModuleFiles.js.map +1 -1
  34. package/lib/commonjs/expo-config-plugin/android/withBrownfieldAndroid.js +1 -1
  35. package/lib/commonjs/expo-config-plugin/android/withBrownfieldAndroid.js.map +1 -1
  36. package/lib/commonjs/expo-config-plugin/template/android/build.gradle.kts +6 -0
  37. package/lib/commonjs/scripts/brownfield.js +0 -0
  38. package/lib/module/expo-config-plugin/android/utils/constants.js +1 -1
  39. package/lib/module/expo-config-plugin/android/utils/formatHelpers.js +2 -0
  40. package/lib/module/expo-config-plugin/android/utils/formatHelpers.js.map +1 -0
  41. package/lib/module/expo-config-plugin/android/utils/gradleHelpers.js +1 -1
  42. package/lib/module/expo-config-plugin/android/utils/gradleHelpers.js.map +1 -1
  43. package/lib/module/expo-config-plugin/android/withAndroidModuleFiles.js +1 -1
  44. package/lib/module/expo-config-plugin/android/withAndroidModuleFiles.js.map +1 -1
  45. package/lib/module/expo-config-plugin/android/withBrownfieldAndroid.js +1 -1
  46. package/lib/module/expo-config-plugin/android/withBrownfieldAndroid.js.map +1 -1
  47. package/lib/module/expo-config-plugin/template/android/build.gradle.kts +6 -0
  48. package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
  49. package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/formatHelpers.d.ts +2 -0
  50. package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/formatHelpers.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/gradleHelpers.d.ts +9 -1
  52. package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/gradleHelpers.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/src/expo-config-plugin/android/withAndroidModuleFiles.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/src/expo-config-plugin/android/withBrownfieldAndroid.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts +10 -0
  56. package/lib/typescript/commonjs/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts.map +1 -1
  57. package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
  58. package/lib/typescript/module/src/expo-config-plugin/android/utils/formatHelpers.d.ts +2 -0
  59. package/lib/typescript/module/src/expo-config-plugin/android/utils/formatHelpers.d.ts.map +1 -0
  60. package/lib/typescript/module/src/expo-config-plugin/android/utils/gradleHelpers.d.ts +9 -1
  61. package/lib/typescript/module/src/expo-config-plugin/android/utils/gradleHelpers.d.ts.map +1 -1
  62. package/lib/typescript/module/src/expo-config-plugin/android/withAndroidModuleFiles.d.ts.map +1 -1
  63. package/lib/typescript/module/src/expo-config-plugin/android/withBrownfieldAndroid.d.ts.map +1 -1
  64. package/lib/typescript/module/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts +10 -0
  65. package/lib/typescript/module/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts.map +1 -1
  66. package/package.json +3 -3
  67. package/src/expo-config-plugin/android/utils/constants.ts +1 -1
  68. package/src/expo-config-plugin/android/utils/formatHelpers.ts +7 -0
  69. package/src/expo-config-plugin/android/utils/gradleHelpers.ts +114 -8
  70. package/src/expo-config-plugin/android/withAndroidModuleFiles.ts +20 -0
  71. package/src/expo-config-plugin/android/withBrownfieldAndroid.ts +20 -4
  72. package/src/expo-config-plugin/template/android/build.gradle.kts +6 -0
  73. package/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.ts +12 -0
  74. package/CHANGELOG.md +0 -300
@@ -1,142 +1,134 @@
1
1
  package com.callstack.react.brownfield.processors
2
2
 
3
- import com.android.build.gradle.LibraryExtension
4
- import com.callstack.react.brownfield.exceptions.TaskNotFound
3
+ import com.android.build.api.variant.LibraryVariant
5
4
  import com.callstack.react.brownfield.shared.Logging
6
5
  import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
7
6
  import com.callstack.react.brownfield.utils.Extension
8
7
  import com.callstack.react.brownfield.utils.capitalized
8
+ import org.gradle.api.DefaultTask
9
9
  import org.gradle.api.Project
10
- import org.gradle.api.tasks.Copy
11
- import org.gradle.api.tasks.TaskProvider
10
+ import org.gradle.api.file.ConfigurableFileCollection
11
+ import org.gradle.api.file.DirectoryProperty
12
+ import org.gradle.api.provider.Property
13
+ import org.gradle.api.tasks.CacheableTask
14
+ import org.gradle.api.tasks.Input
15
+ import org.gradle.api.tasks.InputDirectory
16
+ import org.gradle.api.tasks.InputFiles
17
+ import org.gradle.api.tasks.Optional
18
+ import org.gradle.api.tasks.OutputDirectory
19
+ import org.gradle.api.tasks.PathSensitive
20
+ import org.gradle.api.tasks.PathSensitivity
21
+ import org.gradle.api.tasks.TaskAction
12
22
  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
- copySoLibsTask(variantName)
29
-
30
- mergeJniLibsTask.configure {
31
- it.doFirst {
32
- val projectExt = project.extensions.getByType(Extension::class.java)
33
- val existingJNILibs =
34
- listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
35
- .associateWith { mutableListOf<String>() }
36
- .toMutableMap()
37
- for (archiveLibrary in aarLibraries) {
38
- val jniDir = archiveLibrary.getJniDir()
39
- processNestedLibs(jniDir.listFiles(), existingJNILibs)
40
- if (!projectExt.useStrippedSoFiles) {
41
- if (jniDir.exists()) {
42
- val filteredSourceSets =
43
- androidExtension.sourceSets.filter { sourceSet -> sourceSet.name == variantName }
44
- filteredSourceSets.forEach { sourceSet ->
45
- sourceSet.jniLibs.srcDir(
46
- jniDir,
47
- )
48
- }
49
- }
50
- }
51
- }
52
- if (projectExt.useStrippedSoFiles) {
53
- copyStrippedSoLibs(variantName, existingJNILibs)
23
+ import kotlin.collections.component1
24
+ import kotlin.collections.component2
25
+
26
+ /**
27
+ * Below contains a list of dynamic libs which we should not embed
28
+ * with the AAR as they are provided by the Gradle when AAR is
29
+ * consumed by the host App.
30
+ */
31
+ val IGNORE_EMBEDDED_LIBS =
32
+ listOf(
33
+ "libc++_shared.so", "libfbjni.so", "libhermestooling.so",
34
+ "libhermesvm.so", "libimagepipeline.so", "libjsi.so",
35
+ "libnative-filters.so", "libnative-imagetranscoder.so",
36
+ "libreactnative.so",
37
+ )
38
+
39
+ @CacheableTask
40
+ abstract class ProcessAndCopyJniLibsTask : DefaultTask() {
41
+ @get:InputFiles
42
+ @get:PathSensitive(PathSensitivity.RELATIVE)
43
+ abstract val aarJniDirs: ConfigurableFileCollection
44
+
45
+ @get:InputDirectory
46
+ @get:Optional
47
+ @get:PathSensitive(PathSensitivity.RELATIVE)
48
+ abstract val strippedLibsDir: DirectoryProperty
49
+
50
+ @get:Input
51
+ abstract val useStrippedSoFiles: Property<Boolean>
52
+
53
+ @get:OutputDirectory
54
+ abstract val outputDirectory: DirectoryProperty
55
+
56
+ @TaskAction
57
+ fun execute() {
58
+ val outDir = outputDirectory.get().asFile
59
+ // Clear out old data to ensure clean, reproducible builds
60
+ outDir.deleteRecursively()
61
+ outDir.mkdirs()
62
+
63
+ val existingJNILibs =
64
+ listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
65
+ .associateWith { mutableListOf<String>() }
66
+ .toMutableMap()
67
+
68
+ // 1. Scan and process duplicate libs from AAR paths
69
+ aarJniDirs.forEach { jniDir ->
70
+ if (jniDir.exists()) {
71
+ processNestedLibs(jniDir.listFiles(), existingJNILibs)
72
+
73
+ // If not using stripped files, copy the unstripped ones directly to our output
74
+ if (!useStrippedSoFiles.get()) {
75
+ jniDir.copyRecursively(outDir, overwrite = true)
54
76
  }
55
77
  }
56
78
  }
57
- }
58
-
59
- private fun getStrippedLibsPath(variantName: String): Pair<File, File> {
60
- val projectExt = project.extensions.getByType(Extension::class.java)
61
- val appProject = project.rootProject.project(projectExt.appProjectName)
62
- val appBuildDir = appProject.layout.buildDirectory.get()
63
-
64
- val capitalizedVariant = variantName.capitalized()
65
-
66
- val fromDir =
67
- appBuildDir
68
- .dir("intermediates/stripped_native_libs/$variantName/strip${capitalizedVariant}DebugSymbols/out/lib")
69
- .asFile
70
-
71
- val intoDir = project.rootProject.file("${project.name}/libs$capitalizedVariant")
72
-
73
- return Pair(fromDir, intoDir)
74
- }
75
-
76
- private fun copySoLibsTask(variantName: String): TaskProvider<Copy> {
77
- val capitalizedVariant = variantName.capitalized()
78
- val projectExt = project.extensions.getByType(Extension::class.java)
79
- val appProject = project.rootProject.project(projectExt.appProjectName)
80
-
81
- val stripTask = ":${appProject.name}:strip${capitalizedVariant}DebugSymbols"
82
- val codegenTask = ":${project.name}:generateCodegenSchemaFromJavaScript"
83
79
 
84
- val (fromDir, intoDir) = getStrippedLibsPath(variantName)
85
-
86
- return project.tasks.register("copy${capitalizedVariant}LibSources", Copy::class.java) {
87
- it.dependsOn(stripTask, codegenTask)
88
- it.from(fromDir)
89
- it.into(intoDir)
90
-
91
- it.include("**/libappmodules.so", "**/libreact_codegen_*.so")
92
- projectExt.dynamicLibs.forEach { lib -> it.include("**/$lib") }
80
+ // 2. If using stripped files, copy targeted files from the stripped directory
81
+ if (useStrippedSoFiles.get() && strippedLibsDir.isPresent) {
82
+ copyStrippedSoLibs(outDir, existingJNILibs)
93
83
  }
94
84
  }
95
85
 
96
86
  private fun copyStrippedSoLibs(
97
- variantName: String,
87
+ outDir: File,
98
88
  existingJNILibs: MutableMap<String, MutableList<String>>,
99
89
  ) {
100
- val (fromDir, intoDir) = getStrippedLibsPath(variantName)
90
+ val fromDir = strippedLibsDir.get().asFile
91
+ if (!fromDir.exists()) return
101
92
 
102
- existingJNILibs.forEach { (arch, libNames) ->
103
- copyLibsForArchitecture(fromDir, intoDir, arch, libNames)
93
+ existingJNILibs.keys.forEach { arch ->
94
+ copyArchStrippedSoLibs(fromDir, outDir, arch)
104
95
  }
105
96
  }
106
97
 
107
- private fun copyLibsForArchitecture(
98
+ private fun copyArchStrippedSoLibs(
108
99
  fromDir: File,
109
- intoDir: File,
100
+ outDir: File,
110
101
  arch: String,
111
- libNames: List<String>,
112
102
  ) {
113
103
  val sourceArchDir = File(fromDir, arch)
114
104
  if (!sourceArchDir.exists()) return
115
105
 
116
- val destArchDir = File(intoDir, arch).apply { mkdirs() }
117
-
118
- libNames.forEach { libName ->
119
- copyLibFile(sourceArchDir, destArchDir, libName)
106
+ val destArchDir = File(outDir, arch).apply { mkdirs() }
107
+ sourceArchDir.listFiles()?.forEach { file ->
108
+ copyIfAllowed(file, destArchDir)
120
109
  }
121
110
  }
122
111
 
123
- private fun copyLibFile(
124
- sourceArchDir: File,
112
+ private fun copyIfAllowed(
113
+ file: File,
125
114
  destArchDir: File,
126
- libName: String,
127
115
  ) {
128
- val sourceFile = File(sourceArchDir, libName)
129
- val destFile = File(destArchDir, libName)
130
-
131
- if (sourceFile.exists()) {
132
- try {
133
- sourceFile.copyTo(destFile, overwrite = true)
134
- } catch (e: java.io.IOException) {
135
- Logging.log("Failed to copy $libName: ${e.message}")
136
- }
116
+ val name = file.name
117
+ if (!matchesAllowedLib(name)) return
118
+
119
+ try {
120
+ file.copyTo(File(destArchDir, name), overwrite = true)
121
+ } catch (e: java.io.IOException) {
122
+ Logging.error("Failed to copy $name: ${e.message}", e.cause)
137
123
  }
138
124
  }
139
125
 
126
+ private fun matchesAllowedLib(name: String): Boolean {
127
+ val isCodegenLib = name.startsWith("libreact_codegen_") && name.endsWith(".so")
128
+ val isIgnoredLib = IGNORE_EMBEDDED_LIBS.any { lib -> name == lib || name.contains(lib) }
129
+ return name == "libappmodules.so" || isCodegenLib || !isIgnoredLib
130
+ }
131
+
140
132
  private fun processNestedLibs(
141
133
  files: Array<File>?,
142
134
  existingJNILibs: MutableMap<String, MutableList<String>>,
@@ -147,17 +139,50 @@ class JNILibsProcessor(val project: Project) {
147
139
 
148
140
  libFiles.forEach { file ->
149
141
  if (file.name in libList) {
150
- deleteFile(file)
142
+ file.delete()
151
143
  } else {
152
144
  libList.add(file.name)
153
145
  }
154
146
  }
155
147
  }
156
148
  }
149
+ }
157
150
 
158
- private fun deleteFile(file: File) {
159
- if (!file.delete()) {
160
- Logging.log("Failed to delete: ${file.name}")
161
- }
151
+ class JNILibsProcessor(val project: Project) {
152
+ fun processJniLibs(
153
+ aarLibraries: Collection<AndroidArchiveLibrary>,
154
+ variant: LibraryVariant,
155
+ ) {
156
+ val variantName = variant.name
157
+ val capitalizedVariantName = variantName.capitalized()
158
+ val projectExt = project.extensions.getByType(Extension::class.java)
159
+ val appProject = project.rootProject.project(projectExt.appProjectName)
160
+
161
+ val processJniTask =
162
+ project.tasks.register("processCustomJniLibsFor$capitalizedVariantName", ProcessAndCopyJniLibsTask::class.java) {
163
+ it.useStrippedSoFiles.set(projectExt.useStrippedSoFiles)
164
+
165
+ val jniDirs =
166
+ aarLibraries.map { aarLib ->
167
+ aarLib.getJniDir()
168
+ }
169
+
170
+ it.aarJniDirs.setFrom(jniDirs)
171
+
172
+ val fromDirProvider =
173
+ appProject.layout.buildDirectory.dir(
174
+ "intermediates/stripped_native_libs/$variantName/strip${capitalizedVariantName}DebugSymbols/out/lib",
175
+ )
176
+ it.strippedLibsDir.set(fromDirProvider)
177
+
178
+ val stripTaskPath = ":${appProject.name}:strip${capitalizedVariantName}DebugSymbols"
179
+ val codegenTaskPath = ":${project.name}:generateCodegenSchemaFromJavaScript"
180
+ it.dependsOn(stripTaskPath, codegenTaskPath)
181
+ }
182
+
183
+ variant.sources.jniLibs?.addGeneratedSourceDirectory(
184
+ taskProvider = processJniTask,
185
+ wiredWith = { it.outputDirectory },
186
+ )
162
187
  }
163
188
  }
@@ -1,74 +1,38 @@
1
1
  package com.callstack.react.brownfield.processors
2
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
3
+ import com.android.build.api.artifact.SingleArtifact
4
+ import com.android.build.api.variant.LibraryVariant
5
+ import com.callstack.react.brownfield.shared.MergeLibraryManifestTask
9
6
  import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
10
- import com.callstack.react.brownfield.utils.capitalized
11
- import org.apache.tools.ant.BuildException
12
7
  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
8
 
19
9
  object ManifestTaskProcessor {
20
10
  fun process(
21
- variant: LibraryVariant,
22
11
  project: Project,
12
+ variant: LibraryVariant,
23
13
  aarLibraries: List<AndroidArchiveLibrary>,
24
14
  ) {
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
- }
15
+ val capitalizedVariantName = variant.name.replaceFirstChar(Char::titlecase)
16
+ val taskProvider =
17
+ project.tasks.register(
18
+ "transform${capitalizedVariantName}BrownfieldMergedManifest",
19
+ MergeLibraryManifestTask::class.java,
20
+ ) { task ->
21
+ task.variantName.set(variant.name)
22
+ task.namespace.set(variant.namespace)
23
+ task.manifestPlaceholders.set(variant.manifestPlaceholders)
24
+ task.aarManifestFiles.from(aarLibraries.map { it.getManifestFile() })
25
+
26
+ // The exploded AAR manifests are generated out of band, so keep the transform
27
+ // ordered after the variant-specific explode task without reaching for old APIs.
28
+ task.dependsOn("explode${capitalizedVariantName}Aar")
29
+ }
30
+
31
+ variant.artifacts
32
+ .use(taskProvider)
33
+ .wiredWithFiles(
34
+ MergeLibraryManifestTask::inputManifest,
35
+ MergeLibraryManifestTask::outputManifest,
36
+ ).toTransform(SingleArtifact.MERGED_MANIFEST)
73
37
  }
74
38
  }
@@ -5,19 +5,12 @@ import org.gradle.api.Project
5
5
  import java.io.File
6
6
 
7
7
  object MergeProcessor {
8
- fun mergeClassesJarIntoClasses(
8
+ fun mergeClassesJarFilesIntoClasses(
9
9
  project: Project,
10
- androidLibraries: Collection<AndroidArchiveLibrary>,
10
+ classJarFiles: Collection<File>,
11
11
  folderOut: File,
12
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 ->
13
+ classJarFiles.filter { it.exists() }.forEach { jarFile ->
21
14
  project.copy {
22
15
  it.from(project.zipTree(jarFile))
23
16
  it.into(folderOut)
@@ -25,28 +18,13 @@ object MergeProcessor {
25
18
  }
26
19
  }
27
20
 
28
- fun mergeLibsIntoClasses(
21
+ fun mergeClassesJarIntoClasses(
29
22
  project: Project,
30
23
  androidLibraries: Collection<AndroidArchiveLibrary>,
31
- jarFiles: Collection<File>,
32
- outputDir: File,
24
+ folderOut: File,
33
25
  ) {
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
- }
26
+ val classesJarFiles = getFilteredAarLibs(androidLibraries).map { it.getClassesJarFile() }
27
+ mergeClassesJarFilesIntoClasses(project, classesJarFiles, folderOut)
50
28
  }
51
29
 
52
30
  private fun getFilteredAarLibs(androidLibraries: Collection<AndroidArchiveLibrary>): Collection<AndroidArchiveLibrary> {
@@ -1,61 +1,24 @@
1
1
  package com.callstack.react.brownfield.processors
2
2
 
3
- import com.callstack.react.brownfield.exceptions.TaskNotFound
4
- import com.callstack.react.brownfield.shared.Logging
3
+ import com.callstack.react.brownfield.shared.ExplodeAarTask
5
4
  import com.callstack.react.brownfield.utils.Utils
6
5
  import org.gradle.api.Project
7
- import org.gradle.api.file.RegularFileProperty
8
6
  import org.gradle.api.tasks.TaskProvider
9
7
  import java.io.File
10
8
 
11
9
  class ProguardProcessor(val project: Project) {
12
- fun processConsumerFiles(
10
+ fun processFiles(
13
11
  proguardRules: List<File>,
14
12
  capitalizedVariantName: String,
13
+ explodeTask: TaskProvider<ExplodeAarTask>,
15
14
  ) {
16
15
  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)
16
+ project.tasks.matching { it.name == mergeTaskName }.configureEach { task ->
17
+ task.dependsOn(explodeTask)
18
+ task.doLast {
19
+ val outputFile = task.outputs.files.singleFile
20
+ Utils.mergeFiles(proguardRules, outputFile)
21
+ }
59
22
  }
60
23
  }
61
24
  }
@@ -1,26 +1,64 @@
1
1
  package com.callstack.react.brownfield.processors
2
2
 
3
- import com.android.build.gradle.api.LibraryVariant
4
- import com.callstack.react.brownfield.exceptions.TaskNotFound
3
+ import com.android.build.api.variant.LibraryVariant
4
+ import com.callstack.react.brownfield.shared.ExplodeAarTask
5
5
  import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
6
6
  import com.callstack.react.brownfield.utils.capitalized
7
+ import org.gradle.api.DefaultTask
7
8
  import org.gradle.api.Project
9
+ import org.gradle.api.file.ConfigurableFileCollection
10
+ import org.gradle.api.file.DirectoryProperty
11
+ import org.gradle.api.tasks.CacheableTask
12
+ import org.gradle.api.tasks.InputFiles
13
+ import org.gradle.api.tasks.OutputDirectory
14
+ import org.gradle.api.tasks.PathSensitive
15
+ import org.gradle.api.tasks.PathSensitivity
16
+ import org.gradle.api.tasks.TaskAction
17
+ import org.gradle.api.tasks.TaskProvider
18
+
19
+ @CacheableTask
20
+ abstract class CopyExplodedResTask : DefaultTask() {
21
+ @get:InputFiles
22
+ @get:PathSensitive(PathSensitivity.RELATIVE)
23
+ abstract val inputResDirs: ConfigurableFileCollection
24
+
25
+ @get:OutputDirectory
26
+ abstract val outputDirectory: DirectoryProperty
27
+
28
+ @TaskAction
29
+ fun run() {
30
+ val out = outputDirectory.get().asFile
31
+ out.deleteRecursively()
32
+ out.mkdirs()
33
+ inputResDirs.forEach { resDir ->
34
+ if (resDir.exists()) {
35
+ resDir.copyRecursively(out, overwrite = true)
36
+ }
37
+ }
38
+ }
39
+ }
8
40
 
9
41
  object ResourceTaskProcessor {
10
42
  fun process(
11
- variant: LibraryVariant,
12
43
  project: Project,
44
+ variant: LibraryVariant,
13
45
  aarLibraries: List<AndroidArchiveLibrary>,
46
+ explodeTask: TaskProvider<ExplodeAarTask>,
14
47
  ) {
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
- }
48
+ val capitalized = variant.name.capitalized()
49
+ val resDirs = aarLibraries.map { it.getResDir() }
50
+ val copyResTask =
51
+ project.tasks.register(
52
+ "copyExplodedResFor$capitalized",
53
+ CopyExplodedResTask::class.java,
54
+ ) { task ->
55
+ task.inputResDirs.setFrom(resDirs)
56
+ task.dependsOn(explodeTask)
57
+ }
21
58
 
22
- variant.registerGeneratedResFolders(
23
- project.files(aarLibraries.map { it.getResDir() }),
59
+ variant.sources.res?.addGeneratedSourceDirectory(
60
+ copyResTask,
61
+ CopyExplodedResTask::outputDirectory,
24
62
  )
25
63
  }
26
64
  }