@callstack/react-native-brownfield 6.0.1 → 6.1.1

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 (66) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/android/src/main/java/com/callstack/reactnativebrownfield/ReactNativeBrownfield.kt +12 -12
  3. package/android/src/main/java/com/callstack/reactnativebrownfield/RetryableOnce.kt +27 -0
  4. package/android/src/test/java/com/callstack/reactnativebrownfield/RetryableOnceTest.kt +37 -0
  5. package/gradle-plugin/brownfield/build.gradle.kts +4 -0
  6. package/gradle-plugin/brownfield/gradle/libs.versions.toml +2 -0
  7. package/gradle-plugin/brownfield/gradle.properties +1 -1
  8. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNBrownfieldPlugin.kt +24 -7
  9. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +4 -37
  10. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/JNILibsProcessor.kt +206 -104
  11. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ResourceTaskProcessor.kt +201 -4
  12. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantHelper.kt +7 -0
  13. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantTaskProvider.kt +4 -0
  14. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/GradleExclude.kt +31 -0
  15. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/MergeClassesTask.kt +2 -0
  16. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/PublishingMetadataInjector.kt +28 -3
  17. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Extension.kt +14 -1
  18. package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/TaskOutputs.kt +40 -0
  19. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/plugin/AgpCompatibilityMatrixTest.kt +14 -6
  20. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/plugin/HardExcludePredicateTest.kt +28 -0
  21. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/ConfigureProcessJniTaskTest.kt +60 -0
  22. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/CopyExplodedResTaskTest.kt +368 -0
  23. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/JniLibsPlanTest.kt +252 -0
  24. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/MergeClassesLocalJarsTest.kt +73 -0
  25. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/MetroResDirWiringTest.kt +39 -0
  26. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/processors/ProcessAndCopyJniLibsTaskTest.kt +136 -0
  27. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/shared/GradleExcludesTest.kt +81 -0
  28. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/shared/PublishingMetadataInjectorTest.kt +56 -0
  29. package/gradle-plugin/brownfield/src/test/kotlin/com/callstack/react/brownfield/utils/ExtensionTest.kt +5 -0
  30. package/ios/ReactNativeBrownfield.swift +3 -1
  31. package/ios/ReactNativeBrownfieldModule.mm +35 -7
  32. package/lib/commonjs/expo-config-plugin/android/utils/constants.js +1 -1
  33. package/lib/commonjs/expo-config-plugin/android/withAndroidModuleFiles.js +1 -1
  34. package/lib/commonjs/expo-config-plugin/android/withAndroidModuleFiles.js.map +1 -1
  35. package/lib/commonjs/expo-config-plugin/template/android/build.gradle.kts +1 -1
  36. package/lib/commonjs/index.js +1 -1
  37. package/lib/commonjs/index.js.map +1 -1
  38. package/lib/commonjs/scaffold/index.js +1 -1
  39. package/lib/commonjs/scaffold/index.js.map +1 -1
  40. package/lib/module/expo-config-plugin/android/utils/constants.js +1 -1
  41. package/lib/module/expo-config-plugin/android/withAndroidModuleFiles.js +1 -1
  42. package/lib/module/expo-config-plugin/android/withAndroidModuleFiles.js.map +1 -1
  43. package/lib/module/expo-config-plugin/template/android/build.gradle.kts +1 -1
  44. package/lib/module/index.js +1 -1
  45. package/lib/module/index.js.map +1 -1
  46. package/lib/module/scaffold/index.js +1 -1
  47. package/lib/module/scaffold/index.js.map +1 -1
  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/withAndroidModuleFiles.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts +6 -0
  51. package/lib/typescript/commonjs/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/src/scaffold/index.d.ts.map +1 -1
  54. package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
  55. package/lib/typescript/module/src/expo-config-plugin/android/withAndroidModuleFiles.d.ts.map +1 -1
  56. package/lib/typescript/module/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts +6 -0
  57. package/lib/typescript/module/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.d.ts.map +1 -1
  58. package/lib/typescript/module/src/index.d.ts.map +1 -1
  59. package/lib/typescript/module/src/scaffold/index.d.ts.map +1 -1
  60. package/package.json +2 -2
  61. package/src/expo-config-plugin/android/utils/constants.ts +1 -1
  62. package/src/expo-config-plugin/android/withAndroidModuleFiles.ts +42 -0
  63. package/src/expo-config-plugin/template/android/build.gradle.kts +1 -1
  64. package/src/expo-config-plugin/types/android/BrownfieldPluginAndroidConfig.ts +7 -0
  65. package/src/index.ts +4 -2
  66. package/src/scaffold/index.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @callstack/react-native-brownfield
2
2
 
3
+ ## 6.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#516](https://github.com/callstack/react-native-brownfield/pull/516) [`66ac701`](https://github.com/callstack/react-native-brownfield/commit/66ac701d71cb3990732e701a0ab1abd40a7bd271) Thanks [@malopezr7](https://github.com/malopezr7)! - Android: `ReactNativeBrownfield.initialize` can now be called again after it throws. Before, a failure while loading native libraries or creating the `ReactHost` left it marked as initialized, so the next call returned without error and `ReactNativeBrownfield.shared` was never set.
8
+
9
+ - [#517](https://github.com/callstack/react-native-brownfield/pull/517) [`5884ce9`](https://github.com/callstack/react-native-brownfield/commit/5884ce96bcccf73de33835e7db2785aa3ab8c2a9) Thanks [@tlq5l](https://github.com/tlq5l)! - Fix an iOS crash (`std::bad_function_call`) when native code posts a message to JS while the Brownfield module's JS emitter is still being set up. If the Brownfield module exists but its JS emitter is not ready when delivery happens, the message is dropped and a log line is written. If the module does not exist yet, the message is dropped without a log line.
10
+ - Updated dependencies [[`a9726c1`](https://github.com/callstack/react-native-brownfield/commit/a9726c137c61fe2e59c039555a955632a5d86aec)]:
11
+ - @callstack/brownfield-cli@6.1.1
12
+
13
+ ## 6.1.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#520](https://github.com/callstack/react-native-brownfield/pull/520) [`b87cdff`](https://github.com/callstack/react-native-brownfield/commit/b87cdff0de1cb147289a7497973b6f191dc74134) Thanks [@KisaneNeko](https://github.com/KisaneNeko)! - fix: pick the right `.so` files for the Android AAR. With `useStrippedSoFiles = false`, the AAR now has `libappmodules.so` and `libreact_codegen_*.so`. Before this fix, those libs were missing and host apps crashed. The AAR also stops embedding the `.so` files of Maven dependencies. The host already gets those through the POM, so its build no longer fails with `2 files found with path 'lib/<abi>/<name>.so'`. If your app module builds or ships a `.so` of its own, list it in `reactBrownfield.dynamicLibs`, which is back. The build lists the `.so` files it left out in `<brownfield module>/build/reports/brownfield/<variant>/skipped-so.txt`. After upgrading, check that file: it lists the `.so` files that used to be in the AAR and now aren't.
18
+
19
+ - [#522](https://github.com/callstack/react-native-brownfield/pull/522) [`20776bb`](https://github.com/callstack/react-native-brownfield/commit/20776bb714c2de1e962515aa7c88235b60c7dabf) Thanks [@KisaneNeko](https://github.com/KisaneNeko)! - feat: the published POM and `module.json` now follow the brownfield module's Gradle exclude rules (`configurations.all { exclude(...) }`). Before, the plugin re-added an excluded dependency when it injected the embedded libraries' dependencies, so the host app still resolved it. The excludes are also written onto every dependency the plugin injects, so the excluded library can't arrive through one of them. On Expo, list them in `android.excludeDependencies` (as `group:module` or `group`), which the config plugin writes into the generated module.
20
+
21
+ ### Patch Changes
22
+
23
+ - [#512](https://github.com/callstack/react-native-brownfield/pull/512) [`520811c`](https://github.com/callstack/react-native-brownfield/commit/520811c47a122cacd1ec15f1b064ad08d699eebb) Thanks [@KisaneNeko](https://github.com/KisaneNeko)! - fix: package classes from libraries' local jars (`libs/*.jar`) into the Android AAR; previously host apps crashed with NoClassDefFoundError. If your app also has those classes, because it added the jar itself as a workaround or depends on a library that the jar bundles, the build now fails with duplicate classes: remove the app's copy
24
+
25
+ - [#513](https://github.com/callstack/react-native-brownfield/pull/513) [`f3dbbd1`](https://github.com/callstack/react-native-brownfield/commit/f3dbbd1c2579f905a358faac0ad1677b3740cebc) Thanks [@KisaneNeko](https://github.com/KisaneNeko)! - fix: keep the resources of every library embedded in the Android AAR; previously only one library's `res/values` survived and host apps failed at resource linking. As in a regular app, the module's own `res` and `resValue`s win over a library's, and when two libraries define the same resource the first one wins (previously the last one won for files such as drawables)
26
+
27
+ - [#521](https://github.com/callstack/react-native-brownfield/pull/521) [`58aedad`](https://github.com/callstack/react-native-brownfield/commit/58aedad94f38098424937533f2ce0b0c3df62067) Thanks [@KisaneNeko](https://github.com/KisaneNeko)! - fix: the AAR build no longer fails with duplicate resources when an embedded library ships the same drawables Metro generates for the app's bundle. Metro's copy wins.
28
+
29
+ - [#503](https://github.com/callstack/react-native-brownfield/pull/503) [`6a258da`](https://github.com/callstack/react-native-brownfield/commit/6a258da42f2bd2cbb112f56948108323aeba74d9) Thanks [@RaphaelFakhri](https://github.com/RaphaelFakhri)! - `ReactNativeBrownfield.onMessage` no longer calls the callback a second time, with the raw message text, when the callback throws. The error now propagates instead of being swallowed.
30
+ - Updated dependencies [[`20776bb`](https://github.com/callstack/react-native-brownfield/commit/20776bb714c2de1e962515aa7c88235b60c7dabf)]:
31
+ - @callstack/brownfield-cli@6.1.0
32
+
3
33
  ## 6.0.1
4
34
 
5
35
  ### Patch Changes
@@ -18,7 +18,6 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
18
18
  import com.facebook.react.soloader.OpenSourceMergedSoMapping
19
19
  import com.facebook.soloader.SoLoader
20
20
  import java.util.concurrent.CopyOnWriteArrayList
21
- import java.util.concurrent.atomic.AtomicBoolean
22
21
 
23
22
  fun interface OnJSBundleLoaded {
24
23
  operator fun invoke(timings: JSBundleTimings)
@@ -33,17 +32,15 @@ class ReactNativeBrownfield private constructor(val reactHost: ReactHost) {
33
32
 
34
33
  companion object {
35
34
  private lateinit var instance: ReactNativeBrownfield
36
- private val initialized = AtomicBoolean()
37
- private val nativeLibsLoaded = AtomicBoolean()
35
+ private val initialization = RetryableOnce()
36
+ private val nativeLibsLoading = RetryableOnce()
38
37
  private lateinit var applicationContext: Application
39
38
 
40
39
  @JvmStatic
41
40
  val shared: ReactNativeBrownfield get() = instance
42
41
 
43
42
  private fun loadNativeLibs(application: Application) {
44
- if (!nativeLibsLoaded.getAndSet(true)) {
45
- loadNativeLibsInternal(application)
46
- }
43
+ nativeLibsLoading.run { loadNativeLibsInternal(application) }
47
44
  }
48
45
 
49
46
  private fun loadNativeLibsInternal(application: Application) {
@@ -65,11 +62,12 @@ class ReactNativeBrownfield private constructor(val reactHost: ReactHost) {
65
62
  onJSBundleLoaded: OnJSBundleLoaded? = null
66
63
  ) {
67
64
  applicationContext = application
68
- if (!initialized.getAndSet(true)) {
65
+ val ranNow = initialization.run {
69
66
  AndroidJSBundleTimingObserver.install()
70
67
  loadNativeLibs(application)
71
68
  installAndPreload(reactHost, onJSBundleLoaded)
72
- } else {
69
+ }
70
+ if (!ranNow) {
73
71
  invokeWhenJSBundleLoaded(onJSBundleLoaded)
74
72
  }
75
73
  }
@@ -81,11 +79,12 @@ class ReactNativeBrownfield private constructor(val reactHost: ReactHost) {
81
79
  reactHostFactory: () -> ReactHost
82
80
  ) {
83
81
  applicationContext = application
84
- if (!initialized.getAndSet(true)) {
82
+ val ranNow = initialization.run {
85
83
  AndroidJSBundleTimingObserver.install()
86
84
  loadNativeLibs(application)
87
85
  installAndPreload(reactHostFactory(), onJSBundleLoaded)
88
- } else {
86
+ }
87
+ if (!ranNow) {
89
88
  invokeWhenJSBundleLoaded(onJSBundleLoaded)
90
89
  }
91
90
  }
@@ -98,7 +97,7 @@ class ReactNativeBrownfield private constructor(val reactHost: ReactHost) {
98
97
  onJSBundleLoaded: OnJSBundleLoaded? = null
99
98
  ) {
100
99
  applicationContext = application
101
- if (!initialized.getAndSet(true)) {
100
+ val ranNow = initialization.run {
102
101
  AndroidJSBundleTimingObserver.install()
103
102
  loadNativeLibs(application)
104
103
  val reactHost = getDefaultReactHost(
@@ -114,7 +113,8 @@ class ReactNativeBrownfield private constructor(val reactHost: ReactHost) {
114
113
  jsRuntimeFactory = null
115
114
  )
116
115
  installAndPreload(reactHost, onJSBundleLoaded)
117
- } else {
116
+ }
117
+ if (!ranNow) {
118
118
  invokeWhenJSBundleLoaded(onJSBundleLoaded)
119
119
  }
120
120
  }
@@ -0,0 +1,27 @@
1
+ package com.callstack.reactnativebrownfield
2
+
3
+ import java.util.concurrent.atomic.AtomicBoolean
4
+
5
+ /**
6
+ * Runs a block at most once, counting only a run that completes.
7
+ *
8
+ * If the block throws, the next [run] call runs it again instead of treating
9
+ * the work as done. Calls made while a run is in progress are skipped.
10
+ */
11
+ internal class RetryableOnce {
12
+ private val claimed = AtomicBoolean()
13
+
14
+ /** Returns `true` when [block] ran and completed during this call. */
15
+ fun run(block: () -> Unit): Boolean {
16
+ if (claimed.getAndSet(true)) {
17
+ return false
18
+ }
19
+ try {
20
+ block()
21
+ } catch (error: Throwable) {
22
+ claimed.set(false)
23
+ throw error
24
+ }
25
+ return true
26
+ }
27
+ }
@@ -0,0 +1,37 @@
1
+ package com.callstack.reactnativebrownfield
2
+
3
+ import org.junit.Assert.assertEquals
4
+ import org.junit.Assert.assertFalse
5
+ import org.junit.Assert.assertTrue
6
+ import org.junit.Assert.fail
7
+ import org.junit.Test
8
+
9
+ class RetryableOnceTest {
10
+ @Test fun `runs the block once after it completes`() {
11
+ val once = RetryableOnce()
12
+ var runs = 0
13
+
14
+ assertTrue(once.run { runs++ })
15
+ assertFalse(once.run { runs++ })
16
+ assertEquals(1, runs)
17
+ }
18
+
19
+ @Test fun `runs the block again after it throws`() {
20
+ val once = RetryableOnce()
21
+ var runs = 0
22
+
23
+ try {
24
+ once.run {
25
+ runs++
26
+ throw UnsatisfiedLinkError("dlopen failed")
27
+ }
28
+ fail("expected the error to propagate")
29
+ } catch (expected: UnsatisfiedLinkError) {
30
+ assertEquals("dlopen failed", expected.message)
31
+ }
32
+
33
+ assertTrue(once.run { runs++ })
34
+ assertFalse(once.run { runs++ })
35
+ assertEquals(2, runs)
36
+ }
37
+ }
@@ -113,10 +113,14 @@ dependencies {
113
113
  // minimum Gradle version) for every app that applies this plugin.
114
114
  compileOnly(libs.agp)
115
115
  compileOnly(libs.common)
116
+ compileOnly(libs.sdk.common)
117
+ compileOnly(libs.layoutlib.api)
116
118
  implementation(libs.asm.commons)
117
119
  implementation(libs.versioncompare)
118
120
  testImplementation(libs.agp)
119
121
  testImplementation(libs.common)
122
+ testImplementation(libs.sdk.common)
123
+ testImplementation(libs.layoutlib.api)
120
124
  testImplementation(libs.junit.jupiter)
121
125
  testImplementation(gradleTestKit())
122
126
  testImplementation(kotlin("test"))
@@ -19,6 +19,8 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
19
19
  [libraries]
20
20
  agp = { module = "com.android.tools.build:gradle", name = "agp", version.ref = "agp" }
21
21
  common = { module = "com.android.tools:common", version.ref = "common" }
22
+ sdk-common = { module = "com.android.tools:sdk-common", version.ref = "common" }
23
+ layoutlib-api = { module = "com.android.tools.layoutlib:layoutlib-api", version.ref = "common" }
22
24
  asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm-commons" }
23
25
  versioncompare = { module = "io.github.g00fy2:versioncompare", version.ref = "versioncompare" }
24
26
  junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
@@ -1,6 +1,6 @@
1
1
  PROJECT_ID=com.callstack.react.brownfield
2
2
  ARTIFACT_ID=brownfield-gradle-plugin
3
- VERSION=2.0.0-alpha11
3
+ VERSION=2.0.0-alpha14
4
4
  GROUP=com.callstack.react
5
5
  IMPLEMENTATION_CLASS=com.callstack.react.brownfield.plugin.RNBrownfieldPlugin
6
6
 
@@ -19,11 +19,13 @@ import com.callstack.react.brownfield.processors.VariantTaskProvider
19
19
  import com.callstack.react.brownfield.shared.BaseProject
20
20
  import com.callstack.react.brownfield.shared.Constants
21
21
  import com.callstack.react.brownfield.shared.Constants.PROJECT_ID
22
+ import com.callstack.react.brownfield.shared.GradleExclude
22
23
  import com.callstack.react.brownfield.shared.Logging
23
24
  import com.callstack.react.brownfield.shared.PublishingMetadataInjector
24
25
  import com.callstack.react.brownfield.shared.UnresolvedArtifactInfo
25
26
  import com.callstack.react.brownfield.shared.VersionMediatingDependencySet
26
27
  import com.callstack.react.brownfield.shared.dropHardExcludedDependencies
28
+ import com.callstack.react.brownfield.shared.gradleExcludes
27
29
  import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
28
30
  import com.callstack.react.brownfield.utils.DirectoryManager
29
31
  import com.callstack.react.brownfield.utils.Extension
@@ -33,6 +35,24 @@ import org.gradle.api.Plugin
33
35
  import org.gradle.api.Project
34
36
  import org.gradle.api.ProjectConfigurationException
35
37
 
38
+ /**
39
+ * Coordinates that must never be published: embedded in the AAR (not resolvable from Maven), or
40
+ * excluded by the brownfield module's own Gradle rules.
41
+ */
42
+ internal fun hardExcludePredicate(
43
+ project: Project,
44
+ expoPublishingHelper: ExpoPublishingHelper?,
45
+ artifacts: List<UnresolvedArtifactInfo>,
46
+ expoProjects: List<ExpoGradleProjectProjection>,
47
+ excludes: List<GradleExclude>,
48
+ ): (String, String) -> Boolean =
49
+ { groupId, artifactId ->
50
+ (expoPublishingHelper?.shouldExcludeDependency(groupId, artifactId) ?: (groupId == project.rootProject.name)) ||
51
+ artifacts.any { it.moduleGroup == groupId && it.moduleName == artifactId } ||
52
+ expoProjects.any { it.publication?.groupId == groupId && it.publication?.artifactId == artifactId } ||
53
+ excludes.any { it.matches(groupId, artifactId) }
54
+ }
55
+
36
56
  class RNBrownfieldPlugin : Plugin<Project> {
37
57
  private lateinit var extension: Extension
38
58
  private lateinit var project: Project
@@ -140,11 +160,8 @@ class RNBrownfieldPlugin : Plugin<Project> {
140
160
  // Coordinates that must never be published: they're embedded in the AAR, not
141
161
  // resolvable from Maven. Distinct from "superseded" coordinates, which ARE re-injected
142
162
  // (replacing a stale entry) and so must not be dropped here.
143
- val hardExcludePredicate: (String, String) -> Boolean = { groupId, artifactId ->
144
- (expoPublishingHelper?.shouldExcludeDependency(groupId, artifactId) ?: (groupId == project.rootProject.name)) ||
145
- artifacts.any { it.moduleGroup == groupId && it.moduleName == artifactId } ||
146
- expoProjects.any { it.publication?.groupId == groupId && it.publication?.artifactId == artifactId }
147
- }
163
+ val excludes = gradleExcludes(project)
164
+ val hardExcludePredicate = hardExcludePredicate(project, expoPublishingHelper, artifacts, expoProjects, excludes)
148
165
  dropHardExcludedDependencies(transitiveDeps, hardExcludePredicate)
149
166
 
150
167
  Logging.log(
@@ -155,7 +172,7 @@ class RNBrownfieldPlugin : Plugin<Project> {
155
172
  hardExcludePredicate(groupId, artifactId) || rncSupersededCoordinates.contains(groupId to artifactId)
156
173
  }
157
174
 
158
- injector.configure(transitiveDeps, removalPredicate)
175
+ injector.configure(transitiveDeps, removalPredicate, excludes)
159
176
  Logging.log("PublishingMetadataInjector ran: injected merged transitive dependencies into POM and Gradle Module Metadata")
160
177
 
161
178
  // Informational only — throwing would recreate the upgrade break that the namespaced
@@ -277,7 +294,7 @@ class RNBrownfieldPlugin : Plugin<Project> {
277
294
 
278
295
  /** ===== jniLibsProcessor ===== */
279
296
  val jniLibsProcessor = JNILibsProcessor(project)
280
- jniLibsProcessor.processJniLibs(aarLibraries, variant)
297
+ jniLibsProcessor.processJniLibs(aarLibraries, variant, explodeTask)
281
298
 
282
299
  /** ===== proguardProcessor ===== */
283
300
  val proguardProcessor = ProguardProcessor(project)
@@ -8,8 +8,7 @@ import com.callstack.react.brownfield.exceptions.NameSpaceNotFound
8
8
  import com.callstack.react.brownfield.processors.VariantHelper
9
9
  import com.callstack.react.brownfield.utils.Extension
10
10
  import com.callstack.react.brownfield.utils.Utils
11
- import com.callstack.react.brownfield.utils.capitalized
12
- import org.gradle.api.GradleException
11
+ import com.callstack.react.brownfield.utils.directoryGetter
13
12
  import org.gradle.api.Project
14
13
  import org.gradle.api.Task
15
14
  import org.gradle.api.file.DirectoryProperty
@@ -57,16 +56,9 @@ object RNSourceSets {
57
56
  // 2. Use the onVariants block to wire RN bundle outputs via the Variant Sources API
58
57
  componentsExtension.onVariants { variant ->
59
58
  val variantName = variant.name
60
- val bundledAssetsVariantName =
61
- VariantHelper.getBundledAssetsVariantName(
62
- variantName = variantName,
63
- buildTypeName = variant.buildType,
64
- isDebuggable = variant.debuggable,
65
- )
66
- val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized()
67
59
  val appProject = getAppProject()
68
60
 
69
- val jsBundleTaskName = "createBundle${capitalizedBundledAssetsVariantName}JsAndAssets"
61
+ val jsBundleTaskName = VariantHelper.getMetroBundleTaskName(variant)
70
62
 
71
63
  /**
72
64
  * Wire the bundle task's own `jsBundleDir`/`resourcesDir` outputs as *generated*
@@ -89,12 +81,7 @@ object RNSourceSets {
89
81
 
90
82
  /**
91
83
  * Wires `taskName`'s `getterName` output (expected to be a `DirectoryProperty`) as a
92
- * generated source directory for `sources`.
93
- *
94
- * Resolving the task by name (rather than importing its class) keeps this plugin from
95
- * depending on RNGP's/expo-updates' internal task types. If the task, or its expected output
96
- * property, isn't there, this fails the build immediately with a clear message instead of
97
- * silently producing an empty/stale source directory.
84
+ * generated source directory for `sources`. See [directoryGetter] for the checks.
98
85
  */
99
86
  private fun wireGeneratedSourceDirectory(
100
87
  appProject: Project,
@@ -104,27 +91,7 @@ object RNSourceSets {
104
91
  ) {
105
92
  if (sources == null) return
106
93
 
107
- val task =
108
- appProject.tasks.findByName(taskName)
109
- ?: throw GradleException(
110
- "brownfield: expected task '$taskName' was not found in project " +
111
- "'${appProject.path}'. Check that the plugin producing it is applied there.",
112
- )
113
-
114
- val getter =
115
- runCatching { task.javaClass.getMethod(getterName) }.getOrElse {
116
- throw GradleException(
117
- "brownfield: task '$taskName' (${task.javaClass.name}) does not expose " +
118
- "'$getterName()'. The plugin that registers it most likely changed its " +
119
- "API; the brownfield Gradle plugin needs updating to match.",
120
- it,
121
- )
122
- }
123
-
124
- check(DirectoryProperty::class.java.isAssignableFrom(getter.returnType)) {
125
- "brownfield: '$taskName.$getterName()' no longer returns a DirectoryProperty."
126
- }
127
-
94
+ val getter = directoryGetter(appProject, taskName, getterName)
128
95
  val taskProvider = appProject.tasks.named(taskName)
129
96
  sources.addGeneratedSourceDirectory(taskProvider) { t -> getter.invoke(t) as DirectoryProperty }
130
97
  }