Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3816288
feat: first approach - fails at not calling bundleRelaseAar for TPL
hurali97 Jan 13, 2026
93f742d
feat: second approach by exposing custom tasks - WIP
hurali97 Jan 19, 2026
b44fea1
feat: migrate manifest-merger and move others to explode-aar task
hurali97 Jan 21, 2026
3fd0526
feat: migrate processResources and processAssets
hurali97 Jan 27, 2026
fe2bbc1
feat: migrate jni libs processor
hurali97 Jan 28, 2026
25fb981
feat: migrate proguard processor
hurali97 Jan 28, 2026
22f7e93
feat: migrate data binding and cleanup
hurali97 Jan 28, 2026
f1b5497
refactor: cleanup
hurali97 Jan 28, 2026
925e8ee
refactor: cleanup
hurali97 Jan 28, 2026
c8fa281
fix: library namespace resolution
hurali97 Feb 2, 2026
9cd0328
perf: optimize explodeAarTask
hurali97 Feb 3, 2026
dbdde63
feat: improvements
hurali97 Feb 3, 2026
9b4e476
fix: add task dependency for JSBundle
hurali97 Apr 24, 2026
d75ceb7
refactor: cleanup
hurali97 Apr 24, 2026
c9027ef
refactor: remove duplicates
hurali97 Apr 24, 2026
ad03e5d
refactor: early return
hurali97 Apr 24, 2026
3626a34
Merge branch 'main' of github.com:callstack/react-native-brownfield i…
hurali97 Apr 24, 2026
c46e96c
fix: add explode as task dependency on preBuild
hurali97 Apr 24, 2026
196f381
feat: remove resolve during config phase OR needing another task
hurali97 Apr 27, 2026
7d0f302
fix: right place for evaluation dependency
hurali97 Apr 27, 2026
7689721
fix: expo published projects are now added in exploded aar
hurali97 Apr 28, 2026
9f81e85
fix: reduce duplication and fixed namespace resolution
hurali97 Apr 28, 2026
edbc789
refactor: cleanup
hurali97 Apr 28, 2026
1d6c47b
refactor: cleanup
hurali97 Apr 28, 2026
71a422c
refactor: cleanup
hurali97 Apr 28, 2026
4fd1297
perf: add gradle-profiler benchmarks and docs
hurali97 Apr 29, 2026
10b20d9
chore: bump BGP to alpha
hurali97 May 11, 2026
b290d56
chore: changeset
hurali97 May 11, 2026
f8ec3a7
refactor: remove unused plugin
hurali97 May 11, 2026
aef0f81
refactor: throw error
hurali97 May 11, 2026
809cc95
refactor: code review
hurali97 May 11, 2026
4b68b2c
refactor: guard artifact file
hurali97 May 11, 2026
88d07ba
refactor: code review
hurali97 May 11, 2026
f48113a
refactor: code review
hurali97 May 11, 2026
2b18b76
Merge branch 'main' of github.com:callstack/react-native-brownfield i…
hurali97 Jun 10, 2026
e88ea33
fix: errors after merge conflict
hurali97 Jun 10, 2026
edb363a
Merge branch 'main' of github.com:callstack/react-native-brownfield i…
hurali97 Jun 10, 2026
cf5c860
fix: resolve after merge conflicts
hurali97 Jun 10, 2026
617719f
fix: update after merge resolve
hurali97 Jun 11, 2026
ac34f34
refactor: drop old LibraryVariant
hurali97 Jun 11, 2026
b470c8e
refactor: use new library variant API for explode and bundle task
hurali97 Jun 12, 2026
2cd9bbf
refactor: fix JNI libs
hurali97 Jun 15, 2026
a3f2251
refactor: remove deprecated APIs
hurali97 Jun 19, 2026
d4a03d7
refactor: update proguard tasks
hurali97 Jun 22, 2026
d6633c1
refactor: update JNI tasks
hurali97 Jun 22, 2026
c6be621
refactor: remove deprecated API
hurali97 Jun 30, 2026
41393c4
refactor: make manifest merge reliable with AGP 9
hurali97 Jul 1, 2026
ce8327a
refactor: remove deprecated APIs
hurali97 Jul 1, 2026
725981f
Merge branch 'main' of github.com:callstack/react-native-brownfield i…
hurali97 Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/red-plants-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@callstack/react-native-brownfield': minor
---

Bump brownfield-gradle-plugin
4 changes: 0 additions & 4 deletions apps/RNApp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ yarn-error.log
!.yarn/sdks
!.yarn/versions

# Brownfield
android/BrownfieldLib/libs*Debug/
android/BrownfieldLib/libs*Release/

# Benchmarks
android/gradle-user-home/
android/profile-out/
4 changes: 3 additions & 1 deletion apps/RNApp/android/BrownfieldLib/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

-dontwarn com.rnapp.brownfieldlib.R$anim
56 changes: 28 additions & 28 deletions gradle-plugins/react/brownfield/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
plugins {
alias(libs.plugins.kotlinJvm)
`java-gradle-plugin`
alias(libs.plugins.ktlint)
alias(libs.plugins.detekt)
// alias(libs.plugins.ktlint)
// alias(libs.plugins.detekt)
`maven-publish`
signing
}

ktlint {
debug.set(false)
verbose.set(true)
android.set(false)
outputToConsole.set(true)
ignoreFailures.set(false)
enableExperimentalRules.set(true)

filter {
exclude("**/generated/**")
include("**/kotlin/**")
}
}

detekt {
toolVersion = libs.versions.detekt.get()
config.setFrom(file("config/detekt/detekt.yml"))
buildUponDefaultConfig = true
}
//ktlint {
// debug.set(false)
// verbose.set(true)
// android.set(false)
// outputToConsole.set(true)
// ignoreFailures.set(false)
// enableExperimentalRules.set(true)
//
// filter {
// exclude("**/generated/**")
// include("**/kotlin/**")
// }
//}
//
//detekt {
// toolVersion = libs.versions.detekt.get()
// config.setFrom(file("config/detekt/detekt.yml"))
// buildUponDefaultConfig = true
//}

group = property("GROUP").toString()
version = property("VERSION").toString()
Expand Down Expand Up @@ -110,13 +110,13 @@ dependencies {
implementation(libs.versioncompare)
}

tasks.named("detekt").configure {
dependsOn(":ktlintFormat")
}

tasks.register("lint") {
dependsOn(":ktlintFormat")
}
//tasks.named("detekt").configure {
// dependsOn(":ktlintFormat")
//}
//
//tasks.register("lint") {
// dependsOn(":ktlintFormat")
//}
Comment on lines +113 to +119

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is to remain?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no 😄 Self review of this PR is pending, will do it Monday!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright :D


java {
withJavadocJar()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.callstack.react.brownfield.expo.utils

import com.android.build.gradle.LibraryExtension
import com.android.build.api.dsl.LibraryExtension
import org.gradle.api.Project
import java.io.File

Expand Down Expand Up @@ -68,10 +68,7 @@ object LocalMavenUtils {
BrownfieldPublishingInfo(
groupId = groupId,
artifactId = artifactId,
version = (
targetProjectAndroidLibExt.defaultConfig.versionName
?: targetProject.version.toString()
),
version = targetProject.version.toString(),
)
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.callstack.react.brownfield.plugin

import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.api.dsl.LibraryExtension
import com.callstack.react.brownfield.shared.Logging
import com.callstack.react.brownfield.utils.capitalized
import org.gradle.api.Project
Expand Down Expand Up @@ -70,7 +70,6 @@ class ProjectConfigurations(private val project: Project) {
val configuration = project.configurations.create(configName)

configuration.extendsFrom(project.configurations.getByName("implementation"))
configuration.isVisible = false
configuration.isTransitive = false

val androidComponents = project.extensions.getByType(LibraryAndroidComponentsExtension::class.java)
Expand All @@ -96,9 +95,8 @@ class ProjectConfigurations(private val project: Project) {
from: AttributeContainer,
into: AttributeContainer,
) {
val value: T? = from.getAttribute(key)
if (value != null) {
into.attribute(key, value)
from.getAttribute(key)?.let {
into.attribute(key, it)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.callstack.react.brownfield.plugin

import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.LibraryVariant
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.api.variant.LibraryVariant
import com.callstack.react.brownfield.artifacts.ArtifactsResolver
import com.callstack.react.brownfield.expo.ExpoPublishingHelper
import com.callstack.react.brownfield.expo.utils.ExpoGradleProjectProjection
Expand All @@ -21,6 +21,7 @@ import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
import com.callstack.react.brownfield.utils.DirectoryManager
import com.callstack.react.brownfield.utils.Extension
import com.callstack.react.brownfield.utils.Utils
import com.callstack.react.brownfield.utils.capitalized
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.ProjectConfigurationException
Expand Down Expand Up @@ -65,11 +66,14 @@ class RNBrownfieldPlugin : Plugin<Project> {

val variantTaskProvider = VariantTaskProvider(project)

/**
* Configure Tasks
*/
project.extensions.getByType(LibraryExtension::class.java).libraryVariants.all { variant ->
val androidComponents = project.extensions.getByType(LibraryAndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
configureTasks(variant, artifacts, variantTaskProvider)

val aarLibraries = getAarLibraries(artifacts, variant.name)
ManifestTaskProcessor.process(variant, project, aarLibraries)
AssetTaskProcessor.process(variant, aarLibraries)
ResourceTaskProcessor.process(variant, aarLibraries)
}
}

Expand Down Expand Up @@ -124,16 +128,13 @@ class RNBrownfieldPlugin : Plugin<Project> {
variantTaskProvider: VariantTaskProvider,
) {
val variantName = variant.name
val capitalizedVariantName = variantName.replaceFirstChar(Char::titlecase)

/** ======= EXPLODE AAR =========*/
val explodeTask = ExplodeTaskProvider.getTask(variant, project, artifacts)

/** ======= Pre<Variant>Build =========*/
variantTaskProvider.preBuildTaskByVariant(
variantName,
variant.buildType.name,
variant.buildType.isDebuggable,
variant,
explodeTask,
)

Expand All @@ -145,27 +146,13 @@ class RNBrownfieldPlugin : Plugin<Project> {
val packageIDs = aarLibraries.map { it.getPackageName() }
VariantPackagesProperty.getVariantPackagesProperty().put(variantName, packageIDs)

/** ======= MANIFEST MERGER =========*/
ManifestTaskProcessor.process(variant, project, aarLibraries)

/** ======= GENERATE RESOURCES =========*/
ResourceTaskProcessor.process(variant, project, aarLibraries)

/** ======= GENERATE ASSETS ========= */
AssetTaskProcessor.process(variant, project, aarLibraries)

/** ===== jniLibsProcessor ===== */
val jniLibsProcessor = JNILibsProcessor(project)
jniLibsProcessor.processJniLibs(aarLibraries, variantName)
jniLibsProcessor.processJniLibs(aarLibraries, variant, explodeTask)

/** ===== proguardProcessor ===== */
val proguardProcessor = ProguardProcessor(project)
val proguardRules = aarLibraries.map { it.getProguardRules() }
proguardProcessor.processConsumerFiles(proguardRules, capitalizedVariantName)
proguardProcessor.processGeneratedFiles(proguardRules, capitalizedVariantName)

/** ===== processDataBinding ===== */
val bundleTask = variantTaskProvider.bundleTaskProvider(project, variantName)
variantTaskProvider.processDataBinding(bundleTask, aarLibraries, variantName)
proguardProcessor.processFiles(proguardRules, variantName.capitalized(), explodeTask)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.callstack.react.brownfield.plugin

import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.api.dsl.LibraryExtension
import com.callstack.react.brownfield.exceptions.NameSpaceNotFound
import com.callstack.react.brownfield.utils.Extension
import com.callstack.react.brownfield.utils.Utils
Expand Down Expand Up @@ -42,10 +42,10 @@ object RNSourceSets {
// Move the non-variant-specific configuration out of the loop
androidExtension.sourceSets.named("main") { sourceSet ->
// This path is not variant-specific, so it's added once here.
sourceSet.java.srcDir("${getModuleBuildDir()}/generated/autolinking/src/main/java")
sourceSet.java.directories.add("${getModuleBuildDir()}/generated/autolinking/src/main/java")
}

// 2. Use the onVariants block to configure each variant
// 2. Use the onVariants block to wire RN bundle outputs via the Variant Sources API
componentsExtension.onVariants { variant ->
val variantName = variant.name
val bundledAssetsVariantName =
Expand All @@ -57,30 +57,24 @@ object RNSourceSets {
val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized()
val appProject = getAppProject()

// 3. Lazily configure the 'variant-specific' source set using .named()
androidExtension.sourceSets.named(variantName) { sourceSet ->
val bundlePathSegments =
listOf(
// outputs for RN <= 0.81
"createBundle${capitalizedBundledAssetsVariantName}JsAndAssets",
// outputs for RN >= 0.82
"react/$bundledAssetsVariantName",
)
val updateResourcesPathSegment = Utils.getExpoUpdatesResourcesTaskName(variant.name)

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()}")
if (Utils.hasExpoUpdates(appProject, variant.name)) {
val updateResourcesTask = appProject.tasks.named(updateResourcesPathSegment)
sourceSet.assets.srcDir(
project.files("$appBuildDir/generated/assets/$updateResourcesPathSegment").builtBy(updateResourcesTask),
)
sourceSet.res.srcDir(
project.files("$appBuildDir/generated/res/$updateResourcesPathSegment").builtBy(updateResourcesTask),
)
}
val bundlePathSegments =
listOf(
// outputs for RN <= 0.81
"createBundle${capitalizedBundledAssetsVariantName}JsAndAssets",
// outputs for RN >= 0.82
"react/$bundledAssetsVariantName",
)

val appBuildDir = getAppBuildDir()
bundlePathSegments.forEach { segment ->
variant.sources.assets?.addStaticSourceDirectory("$appBuildDir/generated/assets/$segment")
variant.sources.res?.addStaticSourceDirectory("$appBuildDir/generated/res/$segment")
}

if (Utils.hasExpoUpdates(appProject, variantName)) {
val updateResourcesPathSegment = Utils.getExpoUpdatesResourcesTaskName(variantName)
variant.sources.assets?.addStaticSourceDirectory("$appBuildDir/generated/assets/$updateResourcesPathSegment")
variant.sources.res?.addStaticSourceDirectory("$appBuildDir/generated/res/$updateResourcesPathSegment")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
package com.callstack.react.brownfield.processors

import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.LibraryVariant
import com.android.build.api.variant.LibraryVariant
import com.callstack.react.brownfield.utils.AndroidArchiveLibrary
import org.gradle.api.Project

object AssetTaskProcessor {
fun process(
variant: LibraryVariant,
project: Project,
aarLibraries: List<AndroidArchiveLibrary>,
) {
val assetsTask = variant.mergeAssetsProvider.get()
val assetDirectories = aarLibraries.map { it.getAssetsDir() }.filter { it.exists() }

val androidExtension = project.extensions.getByName("android") as LibraryExtension
assetsTask.doFirst {
val filteredSourceSets =
androidExtension.sourceSets.filter { it.name == variant.name }

filteredSourceSets.forEach { sourceSet ->
val filteredAarLibs = aarLibraries.filter { it.getAssetsDir().exists() }
if (!filteredAarLibs.isEmpty()) {
sourceSet.assets.srcDirs(filteredAarLibs.map { it.getAssetsDir() })
}
}
assetDirectories.forEach { assetDirectory ->
variant.sources.assets?.addStaticSourceDirectory(assetDirectory.path)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.callstack.react.brownfield.processors

import com.android.build.gradle.api.LibraryVariant
import com.android.build.api.variant.LibraryVariant
import com.callstack.react.brownfield.shared.BundleTaskProvider
import com.callstack.react.brownfield.shared.ExplodeAarTask
import com.callstack.react.brownfield.shared.UnresolvedArtifactInfo
Expand All @@ -26,19 +26,17 @@ object ExplodeTaskProvider {
ExplodeAarTask::class.java,
) { task ->
task.variantName.set(variant.name)
task.minifyEnabled.set(variant.buildType.isMinifyEnabled)
task.minifyEnabled.set(variant.isMinifyEnabled)

val finalArtifacts = mutableListOf<UnresolvedArtifactInfo>()
artifacts.forEach { art ->
var artifactPath = art.file
if (art.isExpoPublishDependency != true) {
val defaultTaskName = "bundle${capitalizedVariantName}Aar"
val dependencyProject = project.project(":${art.moduleName}")
val bundleTaskProvider = bundleProvider.getBundleTask(dependencyProject, variant)
val taskName = bundleTaskProvider?.name ?: defaultTaskName

val taskName = bundleTaskProvider.name
dependencyProject.tasks.findByName(taskName)?.let { task.dependsOn(it) }
artifactPath = createArtifactFile(bundleTaskProvider?.get() as Task).absolutePath
artifactPath = createArtifactFile(bundleTaskProvider.get()).absolutePath
}

finalArtifacts.add(
Expand Down
Loading
Loading