From e6f93a30d60771ab13946eb820a4f2ecd45e4188 Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Thu, 18 Jun 2026 16:53:36 +0500 Subject: [PATCH 1/7] feat: add dimension and flavor to RNApp --- apps/RNApp/android/BrownfieldLib/build.gradle.kts | 12 ++++++++++++ apps/RNApp/android/app/build.gradle | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/apps/RNApp/android/BrownfieldLib/build.gradle.kts b/apps/RNApp/android/BrownfieldLib/build.gradle.kts index 019236ec..7d773be1 100644 --- a/apps/RNApp/android/BrownfieldLib/build.gradle.kts +++ b/apps/RNApp/android/BrownfieldLib/build.gradle.kts @@ -101,6 +101,18 @@ android { ) } } + + flavorDimensions += "env" + + productFlavors { + create("prod") { + dimension = "env" + } + create("dev") { + dimension = "env" + } + } + compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 diff --git a/apps/RNApp/android/app/build.gradle b/apps/RNApp/android/app/build.gradle index 3d43d51f..6b10aa8d 100644 --- a/apps/RNApp/android/app/build.gradle +++ b/apps/RNApp/android/app/build.gradle @@ -105,6 +105,15 @@ android { proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } + flavorDimensions "env" + productFlavors { + prod { + dimension "env" + } + dev { + dimension "env" + } + } } dependencies { From a0e3df5c5655af6d39b3765f0581bb03d6570273 Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Thu, 18 Jun 2026 16:54:11 +0500 Subject: [PATCH 2/7] feat: add missing dimension on Android App --- apps/AndroidApp/app/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/AndroidApp/app/build.gradle.kts b/apps/AndroidApp/app/build.gradle.kts index d32b6717..ce3fd9b8 100644 --- a/apps/AndroidApp/app/build.gradle.kts +++ b/apps/AndroidApp/app/build.gradle.kts @@ -25,6 +25,7 @@ android { versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + missingDimensionStrategy("env", "dev") } flavorDimensions += "app" From 87b37143e192b3961cff89bfb2ae96c31d8b46a7 Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Thu, 18 Jun 2026 16:54:34 +0500 Subject: [PATCH 3/7] feat: correctly reference JNI libs --- .../react/brownfield/plugin/RNSourceSets.kt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt b/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt index 7a60c5eb..b6303a92 100644 --- a/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +++ b/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt @@ -47,16 +47,17 @@ object RNSourceSets { // 2. Use the onVariants block to configure each variant componentsExtension.onVariants { variant -> + val variantName = variant.name val bundledAssetsVariantName = Utils.getBundledAssetsVariantName( - variantName = variant.name, + variantName = variantName, buildTypeName = variant.buildType, isDebuggable = variant.debuggable, ) val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized() // 3. Lazily configure the 'main' source set using .named() - androidExtension.sourceSets.named(variant.name) { sourceSet -> + androidExtension.sourceSets.named(variantName) { sourceSet -> // Paths are collected and added, similar to your improved version val bundlePathSegments = listOf( @@ -72,17 +73,9 @@ object RNSourceSets { val appBuildDir = getAppBuildDir() sourceSet.assets.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/assets/$it" }) sourceSet.res.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/res/$it" }) + sourceSet.jniLibs.srcDirs("libs${variantName.capitalized()}") } } - - // These remain the same, but using .named() is the modern, lazy approach - androidExtension.sourceSets.named("release") { - it.jniLibs.srcDirs("libsRelease") - } - - androidExtension.sourceSets.named("debug") { - it.jniLibs.srcDirs("libsDebug") - } } private fun getLibraryNameSpace(): String { From 08b840485090ec6549e6d1b9a16d0261cb0bde6d Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Thu, 18 Jun 2026 16:54:56 +0500 Subject: [PATCH 4/7] chore: update gitignore and android script --- apps/RNApp/.gitignore | 4 ++-- apps/RNApp/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/RNApp/.gitignore b/apps/RNApp/.gitignore index f6ca3efb..cc37f5e0 100644 --- a/apps/RNApp/.gitignore +++ b/apps/RNApp/.gitignore @@ -75,8 +75,8 @@ yarn-error.log !.yarn/versions # Brownfield -android/BrownfieldLib/libsDebug/ -android/BrownfieldLib/libsRelease/ +android/BrownfieldLib/libs*Debug/ +android/BrownfieldLib/libs*Release/ # Benchmarks android/gradle-user-home/ diff --git a/apps/RNApp/package.json b/apps/RNApp/package.json index ee760f79..32af2cc3 100644 --- a/apps/RNApp/package.json +++ b/apps/RNApp/package.json @@ -7,7 +7,7 @@ "ios": "react-native run-ios", "build:example:android-rn": "react-native build-android", "build:example:ios-rn": "react-native build-ios", - "brownfield:package:android": "brownfield package:android --module-name :BrownfieldLib --variant release --verbose", + "brownfield:package:android": "brownfield package:android --module-name :BrownfieldLib --variant devRelease --verbose", "brownfield:publish:android": "brownfield publish:android --module-name :BrownfieldLib --verbose", "brownfield:package:ios": "brownfield package:ios --scheme BrownfieldLib --configuration Release --verbose", "lint": "eslint .", From 7be1964ccfefa46ee451581c733c52e422b5f477 Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Thu, 18 Jun 2026 17:13:53 +0500 Subject: [PATCH 5/7] docs: update Readme --- gradle-plugins/react/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gradle-plugins/react/README.md b/gradle-plugins/react/README.md index c1211273..301bb1d0 100644 --- a/gradle-plugins/react/README.md +++ b/gradle-plugins/react/README.md @@ -153,6 +153,27 @@ reactBrownfield {
+**Flavored Android Builds** + +To use product flavors and dimensions in your brownfield module, define them as usual: + +```kts + flavorDimensions += "env" + + productFlavors { + create("prod") { + dimension = "env" + } + create("dev") { + dimension = "env" + } + } +``` + +This lets you run tasks like `gradle :brownfieldlib:assembleDevRelease`. However, once you add a flavor and dimension to the brownfield module, you must ensure the same flavor and dimension are defined in the `:app` module (your React Native app). This is required so the `brownfield-gradle-plugin` can correctly look up tasks for JavaScript bundling, Expo resources, and native binaries. + +If there is a flavor mismatch, the build will fail. If your `:app` module defines multiple flavors, that is fine. You only need to ensure that every flavor used in the brownfield module also exists in the app module. + ## Tooling - We are using `ktlint` and `detekt` for formatting and linting From e37ebc30b55f00a5f4f118ecf3cf6db625c7670a Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Fri, 19 Jun 2026 11:23:14 +0500 Subject: [PATCH 6/7] fix: code review --- apps/RNApp/android/BrownfieldLib/build.gradle.kts | 1 - .../com/callstack/react/brownfield/plugin/RNSourceSets.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/RNApp/android/BrownfieldLib/build.gradle.kts b/apps/RNApp/android/BrownfieldLib/build.gradle.kts index 7d773be1..aadad58d 100644 --- a/apps/RNApp/android/BrownfieldLib/build.gradle.kts +++ b/apps/RNApp/android/BrownfieldLib/build.gradle.kts @@ -103,7 +103,6 @@ android { } flavorDimensions += "env" - productFlavors { create("prod") { dimension = "env" diff --git a/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt b/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt index b6303a92..74378118 100644 --- a/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +++ b/gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt @@ -56,7 +56,7 @@ object RNSourceSets { ) val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized() - // 3. Lazily configure the 'main' source set using .named() + // 3. Lazily configure the 'variant-specific' source set using .named() androidExtension.sourceSets.named(variantName) { sourceSet -> // Paths are collected and added, similar to your improved version val bundlePathSegments = From e6ed8f4b7b982ffcb032187927aaf6cf56d3081c Mon Sep 17 00:00:00 2001 From: Hur Ali Date: Fri, 19 Jun 2026 11:23:34 +0500 Subject: [PATCH 7/7] chore: fix CI --- .github/actions/androidapp-road-test/action.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/actions/androidapp-road-test/action.yml b/.github/actions/androidapp-road-test/action.yml index 82e89764..3124ff05 100644 --- a/.github/actions/androidapp-road-test/action.yml +++ b/.github/actions/androidapp-road-test/action.yml @@ -67,12 +67,24 @@ runs: yarn run brownfield:publish:android shell: bash + - name: Resolve AAR variants + id: aar-variants + run: | + if [[ "${{ inputs.flavor }}" == "vanilla" ]]; then + echo "debug=devDebug" >> "$GITHUB_OUTPUT" + echo "release=devRelease" >> "$GITHUB_OUTPUT" + else + echo "debug=debug" >> "$GITHUB_OUTPUT" + echo "release=release" >> "$GITHUB_OUTPUT" + fi + shell: bash + - name: Verify debug AAR exists in Maven Local - run: stat ~/.m2/repository/${{ inputs.rn-project-maven-path }}/0.0.1-SNAPSHOT/brownfieldlib-0.0.1-SNAPSHOT-debug.aar + run: stat ~/.m2/repository/${{ inputs.rn-project-maven-path }}/0.0.1-SNAPSHOT/brownfieldlib-0.0.1-SNAPSHOT-${{ steps.aar-variants.outputs.debug }}.aar shell: bash - name: Verify release AAR exists in Maven Local - run: stat ~/.m2/repository/${{ inputs.rn-project-maven-path }}/0.0.1-SNAPSHOT/brownfieldlib-0.0.1-SNAPSHOT-release.aar + run: stat ~/.m2/repository/${{ inputs.rn-project-maven-path }}/0.0.1-SNAPSHOT/brownfieldlib-0.0.1-SNAPSHOT-${{ steps.aar-variants.outputs.release }}.aar shell: bash # == AndroidApp ==