Skip to content

[Uber] Add fat_aar rule for bundling Android libraries into a distrib…#521

Open
oliviernotteghem wants to merge 3 commits into
bazelbuild:mainfrom
oliviernotteghem:origin_far_aar
Open

[Uber] Add fat_aar rule for bundling Android libraries into a distrib…#521
oliviernotteghem wants to merge 3 commits into
bazelbuild:mainfrom
oliviernotteghem:origin_far_aar

Conversation

@oliviernotteghem
Copy link
Copy Markdown
Contributor

@oliviernotteghem oliviernotteghem commented Jun 5, 2026

…utable SDK

Introduces a new fat_aar rule that consolidates multiple android_library targets and their transitive dependencies into a single self-contained AAR file, complete with a companion fat_aar_pom rule for Maven POM generation.

Motivation
At Uber, shipping SDK artifacts to external partners (e.g., logistics,
delivery, mapping capabilities distributed to third-party apps) requires
packaging internal Android modules as a single distributable unit. Building
those SDKs directly from the Bazel monorepo avoids the maintenance cost of
maintaining a separate SDK project: the SDK AAR is produced as a build
output of the same android_library graph that ships inside Uber's own apps,
keeping the SDK and the app in lock-step with no extra integration layer.

Dependency graph traversal via aspect
A fat_aar_aspect walks the full transitive dependency graph and collects
Android providers — resources (AndroidResourcesInfo / StarlarkAndroidResourcesInfo),
assets (AndroidAssetsInfo), native libraries (AndroidNativeLibsInfo),
manifests, and ProGuard specs (ProguardSpecInfo) — as (label, provider)
tuples. Tracking labels alongside providers is what enables the filtering
step that separates Uber's internal modules from external Maven dependencies.

Selective bundling via exclude patterns
The exclude attribute accepts label prefix patterns (e.g., "@maven//",
"@@com_github_jetbrains_kotlin"). Any dependency whose label or file path
matches a pattern is omitted from the bundled AAR. External dependencies
excluded this way are tracked in a FatAarDependenciesInfo provider and
written to an excluded_deps output group, which fat_aar_pom consumes to
generate correct entries in the POM. Partners are expected to
provide those external dependencies themselves via the generated POM.

Classes.jar
All transitive runtime JARs from included android_library targets are
merged into a single classes.jar using singlejar with --normalize for
deterministic output. External Maven JARs are excluded from the merge
via the same label-pattern filtering applied to resources.

Resources and manifests
Transitive resource files, R.txt files, and assets are collected from
all included android_library providers, filtered by the exclude patterns,
and passed to the AAPT2 resource bundler. Multiple AndroidManifest.xml
files are merged using the Android manifest merger tool (APPLICATION merge
type, dependency order) with a synthetic primary manifest pinning the
minimum SDK version.

Native libraries
Native .so files from AndroidNativeLibsInfo are extracted from ZIP archives
and converted from lib/ARCH/.so layout (Bazel convention) to jni/ARCH/.so
layout (AAR spec) via add_native_libs.sh before being inserted into the
final AAR.

ProGuard rules
Transitive ProGuard specs are merged and embedded in the AAR's
proguard.txt, ensuring consumers applying R8 or ProGuard at the app level
receive the correct keep rules for the bundled SDK.

Optional R8 optimization
An optional r8_config attribute accepts a .pro file. When provided, R8
runs in --classfile mode (outputting .class files rather than .dex,
as required for AAR distribution) with --release optimization, using the
user-provided config combined with all transitive ProGuard specs. This
enables shrinking and obfuscation of the SDK surface before distribution.

POM generation
fat_aar_pom maps the excluded Bazel labels back to their Maven coordinates
(group:artifact:version, with proper type handling for both 3-part and
4-part coordinate formats) and generates a well-formed POM file suitable
for publishing the AAR to Maven/Artifactory. Special internal Bazel targets
(jarinfer_, proguard_ prefixes) are filtered out during POM generation.

In the Uber Android monorepo, these rules are wrapped by the uber_fat_aar macro in android/defs.bzl, which pairs the fat AAR with an aar_import for internal consumption and a publish target for Artifactory delivery.

…utable SDK

Introduces a new fat_aar rule that consolidates multiple android_library
targets and their transitive dependencies into a single self-contained AAR
file, complete with a companion fat_aar_pom rule for Maven POM generation.

Motivation
  At Uber, shipping SDK artifacts to external partners (e.g., logistics,
  delivery, mapping capabilities distributed to third-party apps) requires
  packaging internal Android modules as a single distributable unit. Building
  those SDKs directly from the Bazel monorepo avoids the maintenance cost of
  maintaining a separate SDK project: the SDK AAR is produced as a build
  output of the same android_library graph that ships inside Uber's own apps,
  keeping the SDK and the app in lock-step with no extra integration layer.

Dependency graph traversal via aspect
  A fat_aar_aspect walks the full transitive dependency graph and collects
  Android providers — resources (AndroidResourcesInfo / StarlarkAndroidResourcesInfo),
  assets (AndroidAssetsInfo), native libraries (AndroidNativeLibsInfo),
  manifests, and ProGuard specs (ProguardSpecInfo) — as (label, provider)
  tuples. Tracking labels alongside providers is what enables the filtering
  step that separates Uber's internal modules from external Maven dependencies.

Selective bundling via exclude patterns
  The exclude attribute accepts label prefix patterns (e.g., "@maven//",
  "@@com_github_jetbrains_kotlin"). Any dependency whose label or file path
  matches a pattern is omitted from the bundled AAR. External dependencies
  excluded this way are tracked in a FatAarDependenciesInfo provider and
  written to an excluded_deps output group, which fat_aar_pom consumes to
  generate correct <dependency> entries in the POM. Partners are expected to
  provide those external dependencies themselves via the generated POM.

Classes.jar
  All transitive runtime JARs from included android_library targets are
  merged into a single classes.jar using singlejar with --normalize for
  deterministic output. External Maven JARs are excluded from the merge
  via the same label-pattern filtering applied to resources.

Resources and manifests
  Transitive resource files, R.txt files, and assets are collected from
  all included android_library providers, filtered by the exclude patterns,
  and passed to the AAPT2 resource bundler. Multiple AndroidManifest.xml
  files are merged using the Android manifest merger tool (APPLICATION merge
  type, dependency order) with a synthetic primary manifest pinning the
  minimum SDK version.

Native libraries
  Native .so files from AndroidNativeLibsInfo are extracted from ZIP archives
  and converted from lib/ARCH/*.so layout (Bazel convention) to jni/ARCH/*.so
  layout (AAR spec) via add_native_libs.sh before being inserted into the
  final AAR.

ProGuard rules
  Transitive ProGuard specs are merged and embedded in the AAR's
  proguard.txt, ensuring consumers applying R8 or ProGuard at the app level
  receive the correct keep rules for the bundled SDK.

Optional R8 optimization
  An optional r8_config attribute accepts a .pro file. When provided, R8
  runs in --classfile mode (outputting .class files rather than .dex,
  as required for AAR distribution) with --release optimization, using the
  user-provided config combined with all transitive ProGuard specs. This
  enables shrinking and obfuscation of the SDK surface before distribution.

POM generation
  fat_aar_pom maps the excluded Bazel labels back to their Maven coordinates
  (group:artifact:version, with proper type handling for both 3-part and
  4-part coordinate formats) and generates a well-formed POM file suitable
  for publishing the AAR to Maven/Artifactory. Special internal Bazel targets
  (jarinfer_, proguard_ prefixes) are filtered out during POM generation.

In the Uber Android monorepo, these rules are wrapped by the uber_fat_aar
macro in android/defs.bzl, which pairs the fat AAR with an aar_import for
internal consumption and a publish target for Artifactory delivery.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant