From bc28afb5afdafc45d5ab22298d1c0be6c92aa896 Mon Sep 17 00:00:00 2001 From: Jamie <2119834+jamieQ@users.noreply.github.com> Date: Tue, 18 Aug 2026 03:46:37 -0500 Subject: [PATCH 1/2] perf(android): Target bundletool builds to device Pass the device specification during build-apks so bundletool avoids generating irrelevant split variants before extraction. --- src/launchpad/utils/android/bundletool.py | 12 ++++-- tests/unit/utils/test_bundletool.py | 45 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/unit/utils/test_bundletool.py diff --git a/src/launchpad/utils/android/bundletool.py b/src/launchpad/utils/android/bundletool.py index f709c9b1..bb419bff 100644 --- a/src/launchpad/utils/android/bundletool.py +++ b/src/launchpad/utils/android/bundletool.py @@ -170,6 +170,10 @@ def build_apks( with tempfile.TemporaryDirectory(prefix="bundletool-") as temp_dir: temp_dir_path = Path(temp_dir) temp_apks_path = temp_dir_path / "apks.apks" + device_spec_path = temp_dir_path / "device-spec.json" + with open(device_spec_path, "w", encoding="utf-8") as device_spec_file: + json.dump(device_spec.model_dump(by_alias=True), device_spec_file) + build_apks_command = [ "build-apks", f"--bundle={bundle_path}", @@ -178,6 +182,10 @@ def build_apks( if universal_apk: build_apks_command.append("--mode=universal") + else: + # Restrict bundletool to APKs matching the target device instead + # of generating every possible split before extract-apks filters them. + build_apks_command.append(f"--device-spec={device_spec_path}") # Generate keystore and sign APKs if requested if sign_apks: @@ -195,10 +203,6 @@ def build_apks( logger.debug("APKs will be signed with generated keystore") - device_spec_path = temp_dir_path / "device-spec.json" - with open(device_spec_path, "w", encoding="utf-8") as device_spec_file: - json.dump(device_spec.model_dump(by_alias=True), device_spec_file) - self._run_command(build_apks_command) # Extract APKs for the specified device diff --git a/tests/unit/utils/test_bundletool.py b/tests/unit/utils/test_bundletool.py new file mode 100644 index 00000000..5afd2f02 --- /dev/null +++ b/tests/unit/utils/test_bundletool.py @@ -0,0 +1,45 @@ +from pathlib import Path + +import pytest + +from launchpad.utils.android.bundletool import Bundletool, DeviceSpec + + +@pytest.fixture +def bundletool(mocker) -> Bundletool: + mocker.patch("launchpad.utils.android.bundletool.shutil.which", return_value="/usr/local/bin/bundletool") + tool = Bundletool() + mocker.patch.object(tool, "_generate_keystore", return_value=("password", "alias")) + mocker.patch.object(tool, "_run_command") + return tool + + +def test_build_apks_targets_device_during_build(bundletool: Bundletool, tmp_path: Path) -> None: + bundletool.build_apks( + bundle_path=tmp_path / "app.aab", + output_dir=tmp_path / "output", + device_spec=DeviceSpec(), + ) + + build_command = bundletool._run_command.call_args_list[0].args[0] + extract_command = bundletool._run_command.call_args_list[1].args[0] + + assert "--mode=universal" not in build_command + device_spec_arg = next(argument for argument in build_command if argument.startswith("--device-spec=")) + assert device_spec_arg in extract_command + + +def test_build_universal_apk_does_not_target_device_during_build(bundletool: Bundletool, tmp_path: Path) -> None: + bundletool.build_apks( + bundle_path=tmp_path / "app.aab", + output_dir=tmp_path / "output", + device_spec=DeviceSpec(), + universal_apk=True, + ) + + build_command = bundletool._run_command.call_args_list[0].args[0] + extract_command = bundletool._run_command.call_args_list[1].args[0] + + assert "--mode=universal" in build_command + assert not any(argument.startswith("--device-spec=") for argument in build_command) + assert any(argument.startswith("--device-spec=") for argument in extract_command) From dd255a231f2b350bf75f22a007dd83447b37660b Mon Sep 17 00:00:00 2001 From: Jamie <2119834+jamieQ@users.noreply.github.com> Date: Tue, 18 Aug 2026 07:08:10 -0500 Subject: [PATCH 2/2] test(android): Move bundletool tests under Android utils --- tests/unit/utils/{ => android}/test_bundletool.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unit/utils/{ => android}/test_bundletool.py (100%) diff --git a/tests/unit/utils/test_bundletool.py b/tests/unit/utils/android/test_bundletool.py similarity index 100% rename from tests/unit/utils/test_bundletool.py rename to tests/unit/utils/android/test_bundletool.py