rules_android for Bazel

repository·main·Indexed 41 days ago

https://github.com/bazelbuild/rules_android

Starlark implementation of Android rules for Bazel, enabling the build of Android applications and libraries. It provides support for android_binary and android_application targets, R8 optimization for code shrinking and obfuscation, and integration with the Android SDK via Bzlmod or WORKSPACE.

Tokens
5.2K
Snippets
20
Records
25
Agent score
51%

What's inside rules_android

  1. Configure R8 optimization in Bazel

    main

    R8 provides code shrinking, optimization, obfuscation, and dexing. To enable these features in your Android targets, you must configure the following in your BUILD file:

    • proguard_specs: A list of ProGuard/R8 rule files used to define which classes or members should be kept (e.g., MainActivity) and which should be optimized.
    • shrink_resources = True: When enabled, this removes unused Android resources that are no longer referenced after the code shrinking phase is complete.
  2. Generate and use the R8 Configuration Analyzer report

    main

    The R8 Configuration Analyzer provides an interactive HTML report to audit your keep rules and optimize your shrinking/obfuscation scores.

    To generate the report, build your target using the optimization_config_analyzer output group.

    # Build the target with the analyzer output group
    bazel build //path/to:r8-optimized-app --output_groups=optimization_config_analyzer
    
    # The report will be located at:
    # bazel-bin/path/to/r8-optimized-app_optimization_report.html
  3. Build the basic Android app example

    main

    To build the basic Android application example, ensure you have set the ANDROID_HOME environment variable to point to a valid Android SDK. From the example directory, use the Bazel CLI to build the target.

    # Set your Android SDK path
    export ANDROID_HOME=/path/to/your/android/sdk
    
    # Build the app
    bazel build //java/com/basicapp:basic_app
  4. Install rules_android using WORKSPACE

    main

    If you are using WORKSPACE instead of Bzlmod, add the following configuration to your WORKSPACE file. This includes the rules_android archive, prerequisite setup for Java and Protobuf, rules_jvm_external setup, and the Android SDK repository registration.

    Prerequisites:

    • Set ANDROID_HOME to your Android SDK path.
    • A recent version of Bazel (7.4+, 8.0+, HEAD, or Bazel 9 pre-release) is required.
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    http_archive(
        name = "rules_android",
        sha256 = "c4cd258d3761eff08ee044c0252179bb6ee8af8ab24f7dafb73b280eeda98243",
        strip_prefix = "rules_android-0.7.3",
        url = "https://github.com/bazelbuild/rules_android/releases/download/v0.7.3/rules_android-v0.7.3.tar.gz",
    )
    
    # Android rules dependencies
    load("@rules_android//:prereqs.bzl", "rules_android_prereqs")
    rules_android_prereqs()
    
    ##### rules_java setup for rules_android #####
    load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies")
    rules_java_dependencies()
    # note that the following line is what is minimally required from protobuf for the java rules
    # consider using the protobuf_deps() public API from @com_google_protobuf//:protobuf_deps.bzl
    load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features")  # buildifier: disable=bzl-visibility
    proto_bazel_features(name = "proto_bazel_features")
    # register toolchains
    load("@rules_java//java:repositories.bzl", "rules_java_toolchains")
    rules_java_toolchains()
    
    ##### rules_jvm_external setup for rules_android #####
    load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
    rules_jvm_external_deps()
    load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
    rules_jvm_external_setup()
    
    ##### rules_android setup #####
    load("@rules_android//:defs.bzl", "rules_android_workspace")
    rules_android_workspace()
    
    # Android SDK setup
    load("@rules_android//rules:rules.bzl", "android_sdk_repository")
    android_sdk_repository(
        name = "androidsdk",
    )
    
    register_toolchains(
        "@rules_android//toolchains/android:android_default_toolchain",
        "@rules_android//toolchains/android_sdk:android_sdk_tools",
    )
  5. Recommended target structure for R8 builds

    main

    Because R8 optimization increases build times, it is a best practice to maintain two separate targets: an unoptimized target for fast local development/testing, and an optimized target for release builds and performance testing.

    load("@rules_android//rules:rules.bzl", "android_binary")
    
    # Unoptimized target for faster local build time and testing
    android_binary(
        name = "app",
        manifest = "//src/main/java/com/example/bazel:AndroidManifest.xml",
        deps = ["//src/main/java/com/example/bazel:greeter_activity"],
    )
    
    # Optimized target for release and performance testing
    android_binary(
        name = "r8-optimized-app",
        manifest = "//src/main/java/com/example/bazel:AndroidManifest.xml",
        proguard_generate_mapping = True,
        proguard_specs = [
            "proguard-android-optimize.txt",
            "proguard-rules.pro",
        ],
        shrink_resources = True,
        deps = ["//src/main/java/com/example/bazel:greeter_activity"],
    )
  6. Configure R8 optimization in android_binary and android_application

    main

    R8 is used to reduce application size, decrease runtime memory usage, and improve performance through code shrinking, resource shrinking, bytecode optimization, and obfuscation.

    In rules_android, R8 is configured using attributes on the android_binary (for APKs) or android_application (for AABs) rules. Note that although R8 is the underlying tool, the attributes retain the proguard_ prefix for historical compatibility.

    android_binary(
        name = "r8-optimized-app",
        manifest = "//src/main/java/com/example/bazel:AndroidManifest.xml",
        proguard_generate_mapping = True,
        proguard_specs = [
            "proguard-android-optimize.txt",
            "proguard-rules.pro",
        ],
        shrink_resources = True,
        deps = ["//src/main/java/com/example/bazel:greeter_activity"],
    )
  7. Install rules_android using Bzlmod

    main

    Bzlmod is the recommended way to depend on rules_android. Add the following to your MODULE.bazel file to configure the rules, the remote Android tools extension, and the Android SDK repository. Note that 0.7.3 is the latest release on the Bazel Central Registry; pin a newer version if available.

    Ensure you have ANDROID_HOME set to your Android SDK path.

    bazel_dep(name = "rules_java", version = "9.0.3")
    bazel_dep(name = "bazel_skylib", version = "1.8.1")
    
    bazel_dep(name = "rules_android", version = "0.7.3")
    
    remote_android_extensions = use_extension(
        "@rules_android//bzlmod_extensions:android_extensions.bzl",
        "remote_android_tools_extensions")
    use_repo(remote_android_extensions, "android_tools")
    
    android_sdk_repository_extension = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension")
    use_repo(android_sdk_repository_extension, "androidsdk")
    
    register_toolchains("@androidsdk//:sdk-toolchain", "@androidsdk//:all")
  8. Configure rules_android for Bzlmod

    main
    The basic app example supports both WORKSPACE and Bzlmod. If you are using Bzlmod and copying the MODULE.bazel file from this example into your own repository, you must remove the local_path_override directive. Instead, depend on a released version of rules_android from the Bazel Central Registry (BCR).
  9. How bucketize partitions resources

    main

    The bucketize tool works by scanning provided resource paths and extracting resource values and attributes. It uses a Partitioner to collect these resources and distribute them into shards based on the typed_outputs configuration.

    1. Scanning: It walks the provided res_paths to find all resource files.
    2. Partitioning: It creates file writers for each <res_type> specified in typed_outputs.
    3. Extraction: It parses XML resource files to extract ValuesResource (the actual resource data) and ResourcesAttribute (XML attributes associated with resource tags).
    4. Collection: The Archiver collects these extracted items and passes them to the Partitioner, which writes them to the appropriate sharded output files.