diff --git a/examples/bundle/.DS_Store b/examples/bundle/.DS_Store
new file mode 100644
index 000000000..82e28c3b8
Binary files /dev/null and b/examples/bundle/.DS_Store differ
diff --git a/examples/bundle/.bazelrc b/examples/bundle/.bazelrc
new file mode 100644
index 000000000..a28203e1e
--- /dev/null
+++ b/examples/bundle/.bazelrc
@@ -0,0 +1,10 @@
+# Flags needed while the Android rules are being migrated to Starlark.
+common --experimental_google_legacy_api
+common --experimental_enable_android_migration_apis
+common --android_sdk=@androidsdk//:sdk
+common:core_library_desugaring --desugar_java8_libs
+
+# Flags to enable mobile-install v3
+mobile-install --mode=skylark --mobile_install_aspect=@rules_android//mobile_install:mi.bzl --mobile_install_supported_rules=android_binary
+# Required to invoke the Studio deployer jar
+mobile-install --tool_java_runtime_version=17
diff --git a/examples/bundle/.gitignore b/examples/bundle/.gitignore
new file mode 100644
index 000000000..63f1fef0e
--- /dev/null
+++ b/examples/bundle/.gitignore
@@ -0,0 +1 @@
+*.lock
diff --git a/examples/bundle/BUILD b/examples/bundle/BUILD
new file mode 100644
index 000000000..a09fce916
--- /dev/null
+++ b/examples/bundle/BUILD
@@ -0,0 +1 @@
+# Empty build file to satisfy gazelle for rules_go.
\ No newline at end of file
diff --git a/examples/bundle/MODULE.bazel b/examples/bundle/MODULE.bazel
new file mode 100644
index 000000000..ef2860cd8
--- /dev/null
+++ b/examples/bundle/MODULE.bazel
@@ -0,0 +1,55 @@
+module(
+ name = "bundle",
+)
+
+bazel_dep(name = "rules_java", version = "7.4.0")
+bazel_dep(name = "bazel_skylib", version = "1.3.0")
+
+bazel_dep(
+ name = "rules_android",
+ version = "0.5.1",
+)
+
+local_path_override(
+ module_name = "rules_android",
+ path = "../../",
+)
+
+remote_android_extensions = use_extension(
+ "@rules_android//bzlmod_extensions:android_extensions.bzl",
+ "remote_android_tools_extensions")
+use_repo(remote_android_extensions, "android_gmaven_r8", "android_tools")
+
+register_toolchains(
+ "@rules_android//toolchains/android:android_default_toolchain",
+ "@rules_android//toolchains/android_sdk:android_sdk_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")
+
+bazel_dep(name = "rules_jvm_external", version = "5.3")
+
+# Load the maven extension from rules_jvm_external
+maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
+
+maven.install(
+ name = "maven",
+ aar_import_bzl_label = "@rules_android//rules:rules.bzl",
+ artifacts = [
+ "com.google.guava:guava:32.1.2-android",
+ "com.arthenica:ffmpeg-kit-https:4.4.LTS",
+ ],
+ repositories = [
+ "https://maven.google.com",
+ "https://repo1.maven.org/maven2",
+ ],
+ use_starlark_android_rules = True,
+)
+use_repo(maven, "maven")
+
+
+
+
diff --git a/examples/bundle/README.md b/examples/bundle/README.md
new file mode 100644
index 000000000..0d923e32d
--- /dev/null
+++ b/examples/bundle/README.md
@@ -0,0 +1,12 @@
+To build, ensure that the `ANDROID_HOME` environment variable is set to the path
+to an Android SDK, and run:
+
+```
+bazel build app:assets
+```
+
+This will build application bundle containing a dynamic feature containing assets (named assets.txt). Verify with :
+
+```
+jar -tf bazel-bin/app/assets_unsigned.aab | grep assets.txt
+```
diff --git a/examples/bundle/WORKSPACE b/examples/bundle/WORKSPACE
new file mode 100644
index 000000000..a23815374
--- /dev/null
+++ b/examples/bundle/WORKSPACE
@@ -0,0 +1,58 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+
+maybe(
+ http_archive,
+ name = "rules_jvm_external",
+ strip_prefix = "rules_jvm_external-fa73b1a8e4846cee88240d0019b8f80d39feb1c3",
+ sha256 = "7e13e48b50f9505e8a99cc5a16c557cbe826e9b68d733050cd1e318d69f94bb5",
+ url = "https://github.com/bazelbuild/rules_jvm_external/archive/fa73b1a8e4846cee88240d0019b8f80d39feb1c3.zip",
+)
+
+maybe(
+ http_archive,
+ name = "bazel_skylib",
+ urls = [
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
+ ],
+ sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
+)
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+bazel_skylib_workspace()
+
+local_repository(
+ name = "rules_android",
+ path = "../..", # rules_android's WORKSPACE relative to this inner workspace
+)
+
+load("@rules_android//:prereqs.bzl", "rules_android_prereqs")
+rules_android_prereqs()
+load("@rules_android//:defs.bzl", "rules_android_workspace")
+rules_android_workspace()
+
+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",
+)
+
+load("@rules_jvm_external//:defs.bzl", "maven_install")
+
+maven_install(
+ name = "maven",
+ aar_import_bzl_label = "@rules_android//rules:rules.bzl",
+ artifacts = [
+ "com.google.guava:guava:32.1.2-android",
+ "com.arthenica:ffmpeg-kit-https:4.4.LTS",
+ ],
+ repositories = [
+ "https://maven.google.com",
+ "https://repo1.maven.org/maven2",
+ ],
+ use_starlark_android_rules = True,
+)
diff --git a/examples/bundle/WORKSPACE.bzlmod b/examples/bundle/WORKSPACE.bzlmod
new file mode 100644
index 000000000..df9ed0ec9
--- /dev/null
+++ b/examples/bundle/WORKSPACE.bzlmod
@@ -0,0 +1 @@
+workspace(name = "bundle")
diff --git a/examples/bundle/app/.DS_Store b/examples/bundle/app/.DS_Store
new file mode 100644
index 000000000..b15ab6319
Binary files /dev/null and b/examples/bundle/app/.DS_Store differ
diff --git a/examples/bundle/app/AndroidManifest.xml b/examples/bundle/app/AndroidManifest.xml
new file mode 100644
index 000000000..1a4a7a99d
--- /dev/null
+++ b/examples/bundle/app/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/bundle/app/BUILD b/examples/bundle/app/BUILD
new file mode 100644
index 000000000..aff62ba6a
--- /dev/null
+++ b/examples/bundle/app/BUILD
@@ -0,0 +1,31 @@
+load("@rules_android//android:rules.bzl", "android_application", "android_library")
+
+android_application(
+ name = "assets",
+ manifest_values = {
+ "applicationId" : "com.examples.bundle.app",
+ "versionCode": "0",
+ },
+ feature_modules = ["//features/assets:feature_module"],
+ manifest = "AndroidManifest.xml",
+ deps = [":lib"],
+)
+
+android_application(
+ name = "native",
+ manifest_values = {
+ "applicationId" : "com.examples.bundle.app",
+ "versionCode": "0",
+ },
+ feature_modules = ["//features/native:feature_module"],
+ manifest = "AndroidManifest.xml",
+ deps = [":lib"],
+)
+
+android_library(
+ name = "lib",
+ srcs = ["BasicActivity.java"],
+ manifest = "AndroidManifest.xml",
+ resource_files = glob(["res/**"]),
+ deps = ["@maven//:com_google_guava_guava",]
+)
diff --git a/examples/bundle/app/BasicActivity.java b/examples/bundle/app/BasicActivity.java
new file mode 100644
index 000000000..f051263ba
--- /dev/null
+++ b/examples/bundle/app/BasicActivity.java
@@ -0,0 +1,59 @@
+// Copyright 2022 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.examples.bundle.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * The main activity of the Basic Sample App.
+ */
+public class BasicActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.basic_activity);
+
+ final Button buttons[] = {
+ findViewById(R.id.button_id_fizz), findViewById(R.id.button_id_buzz),
+ };
+
+ for (Button b : buttons) {
+ b.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ TextView tv = findViewById(R.id.text_hello);
+ if (v.getId() == R.id.button_id_fizz) {
+ tv.setText("fizz");
+ } else if (v.getId() == R.id.button_id_buzz) {
+ tv.setText("buzz ");
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.menu, menu);
+ return true;
+ }
+}
diff --git a/examples/bundle/app/res/drawable-hdpi/ic_launcher.png b/examples/bundle/app/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..6ab2adde2
Binary files /dev/null and b/examples/bundle/app/res/drawable-hdpi/ic_launcher.png differ
diff --git a/examples/bundle/app/res/drawable-mdpi/ic_launcher.png b/examples/bundle/app/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c0a73c33d
Binary files /dev/null and b/examples/bundle/app/res/drawable-mdpi/ic_launcher.png differ
diff --git a/examples/bundle/app/res/drawable-xhdpi/ic_launcher.png b/examples/bundle/app/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..014b0f106
Binary files /dev/null and b/examples/bundle/app/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/examples/bundle/app/res/drawable-xxhdpi/ic_launcher.png b/examples/bundle/app/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..20703a15c
Binary files /dev/null and b/examples/bundle/app/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/examples/bundle/app/res/layout/basic_activity.xml b/examples/bundle/app/res/layout/basic_activity.xml
new file mode 100644
index 000000000..f84199cb5
--- /dev/null
+++ b/examples/bundle/app/res/layout/basic_activity.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/examples/bundle/app/res/menu/menu.xml b/examples/bundle/app/res/menu/menu.xml
new file mode 100644
index 000000000..478f557fa
--- /dev/null
+++ b/examples/bundle/app/res/menu/menu.xml
@@ -0,0 +1,8 @@
+
diff --git a/examples/bundle/app/res/values/dimens.xml b/examples/bundle/app/res/values/dimens.xml
new file mode 100644
index 000000000..47c822467
--- /dev/null
+++ b/examples/bundle/app/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 16dp
+ 16dp
+
diff --git a/examples/bundle/app/res/values/strings.xml b/examples/bundle/app/res/values/strings.xml
new file mode 100644
index 000000000..451d3739f
--- /dev/null
+++ b/examples/bundle/app/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+
+
+ basicbundle
+ Hello world!
+ Settings
+
+
diff --git a/examples/bundle/features/assets/BUILD b/examples/bundle/features/assets/BUILD
new file mode 100644
index 000000000..245a904ee
--- /dev/null
+++ b/examples/bundle/features/assets/BUILD
@@ -0,0 +1,18 @@
+load("@rules_android//android:rules.bzl", "android_library")
+load("@rules_android//rules:rules.bzl", "android_feature_module")
+
+android_library(
+ name = "lib",
+ manifest = "src/AndroidManifest.xml",
+ assets = ["src/assets.txt"],
+)
+
+android_feature_module(
+ name = "feature_module",
+ custom_package = "com.example.bundle.features.assets",
+ manifest = "src/AndroidManifest.xml",
+ title = "asset_feature",
+ library = ":lib",
+ feature_name = "asset_feature",
+ visibility = ["//visibility:public"],
+)
\ No newline at end of file
diff --git a/examples/bundle/features/assets/src/.DS_Store b/examples/bundle/features/assets/src/.DS_Store
new file mode 100644
index 000000000..5008ddfcf
Binary files /dev/null and b/examples/bundle/features/assets/src/.DS_Store differ
diff --git a/examples/bundle/features/assets/src/AndroidManifest.xml b/examples/bundle/features/assets/src/AndroidManifest.xml
new file mode 100644
index 000000000..c9556abd1
--- /dev/null
+++ b/examples/bundle/features/assets/src/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
diff --git a/examples/bundle/features/assets/src/assets.txt b/examples/bundle/features/assets/src/assets.txt
new file mode 100644
index 000000000..08c4a31e7
--- /dev/null
+++ b/examples/bundle/features/assets/src/assets.txt
@@ -0,0 +1 @@
+This text originates from a dynamically loaded feature.
\ No newline at end of file
diff --git a/rules/android_application/BUILD b/rules/android_application/BUILD
index bca820377..ddf3f930a 100644
--- a/rules/android_application/BUILD
+++ b/rules/android_application/BUILD
@@ -41,10 +41,3 @@ py_binary(
"@py_absl//absl/flags",
],
)
-
-filegroup(
- name = "merge_feature_manifests.par",
- srcs = [":merge_feature_manifests"],
- output_group = "python_zip_file",
- visibility = ["//visibility:public"],
-)
diff --git a/rules/android_application/android_feature_module_rule.bzl b/rules/android_application/android_feature_module_rule.bzl
index 4ee0a32e2..c55242fe9 100644
--- a/rules/android_application/android_feature_module_rule.bzl
+++ b/rules/android_application/android_feature_module_rule.bzl
@@ -94,10 +94,10 @@ def get_feature_module_paths(fqn):
# Given a fqn to an android_feature_module, returns the absolute paths to
# all implicitly generated targets
return struct(
- binary = Label("%s_bin" % fqn),
- manifest_lib = Label("%s_AndroidManifest" % fqn),
- title_strings_xml = Label("%s_title_strings_xml" % fqn),
- title_lib = Label("%s_title_lib" % fqn),
+ binary = native.package_relative_label("%s_bin" % fqn),
+ manifest_lib = native.package_relative_label("%s_AndroidManifest" % fqn),
+ title_strings_xml = native.package_relative_label("%s_title_strings_xml" % fqn),
+ title_lib = native.package_relative_label("%s_title_lib" % fqn),
)
def android_feature_module_macro(_android_binary, _android_library, **attrs):
diff --git a/rules/android_application/attrs.bzl b/rules/android_application/attrs.bzl
index 51d71700c..a8b3737fa 100644
--- a/rules/android_application/attrs.bzl
+++ b/rules/android_application/attrs.bzl
@@ -67,7 +67,7 @@ ANDROID_APPLICATION_ATTRS = _attrs.add(
),
_bundle_keystore_properties = attr.label(
allow_single_file = True,
- default = "//rules:bundle_keystore_properties.tmpl",
+ default = None,
),
_feature_manifest_script = attr.label(
allow_single_file = True,
@@ -79,8 +79,7 @@ ANDROID_APPLICATION_ATTRS = _attrs.add(
default = Label("//tools/jdk:toolchain_android_only"),
),
_merge_manifests = attr.label(
- default = ":merge_feature_manifests.par",
- allow_single_file = True,
+ default = ":merge_feature_manifests",
cfg = "exec",
executable = True,
),
@@ -114,6 +113,7 @@ ANDROID_FEATURE_MODULE_ATTRS = dict(
manifest = attr.label(allow_single_file = True),
title_id = attr.string(),
title_lib = attr.string(),
+ fused = attr.bool(),
_feature_module_validation_script = attr.label(
allow_single_file = True,
cfg = "exec",
diff --git a/rules/android_application/feature_module_validation.sh b/rules/android_application/feature_module_validation.sh
old mode 100644
new mode 100755
diff --git a/rules/android_application/gen_priority_android_feature_manifest.sh b/rules/android_application/gen_priority_android_feature_manifest.sh
old mode 100644
new mode 100755
diff --git a/rules/rules.bzl b/rules/rules.bzl
index 4e225d008..79c8bd1f8 100644
--- a/rules/rules.bzl
+++ b/rules/rules.bzl
@@ -53,6 +53,10 @@ load(
"//rules/android_library:rule.bzl",
_android_library = "android_library_macro",
)
+load(
+ "//rules/android_application:android_feature_module.bzl",
+ _android_feature_module = "android_feature_module",
+)
load(
"//rules/android_local_test:rule.bzl",
_android_local_test = "android_local_test",
@@ -81,6 +85,7 @@ aar_import = _aar_import
android_application = _android_application
android_binary = _android_binary
android_library = _android_library
+android_feature_module = _android_feature_module
android_local_test = _android_local_test
android_ndk_repository = _android_ndk_repository
android_sandboxed_sdk = _android_sandboxed_sdk
diff --git a/toolchains/android/BUILD b/toolchains/android/BUILD
index 941fbe17f..68e805a2f 100644
--- a/toolchains/android/BUILD
+++ b/toolchains/android/BUILD
@@ -56,3 +56,19 @@ sh_binary(
srcs = [":unzip.sh"],
visibility = ["//visibility:public"],
)
+
+genrule(
+ name = "gen_xmllint",
+ outs = ["xmllint.sh"],
+ cmd = """cat > $@ <