From dd932a8c09c33c45345ab3349938fc2f99f8fcb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Thu, 7 Aug 2025 21:15:35 +0200 Subject: [PATCH 1/6] fix: fix pypi deploy --- .github/workflows/cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index c8f9f7b..e77e8bd 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -58,4 +58,4 @@ jobs: run: uv sync --all-groups - name: Publish documentation - run: uv run mkdocs gh-deploy --force + run: uv run mkdocs gh-deploy --force \ No newline at end of file From dab5fc9b2748717b5b2829b0fbae2ff641ca562a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Thu, 7 Aug 2025 21:28:32 +0200 Subject: [PATCH 2/6] fix: fix pypi badge README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e9675e7..d09392a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Android Device Manager Python Android Device Manager is a Python library for creating, launching, and managing Android emulators (AVDs) programmatically. -[![PyPI](https://img.shields.io/pypi/v/python-android-avd-manager?label=PyPI)](https://pypi.org/project/android-device-manager/) +![PyPI - Version](https://img.shields.io/pypi/v/android-device-manager) [![CI](https://github.com/jwoirhaye/android-device-manager-python/actions/workflows/ci.yml/badge.svg)](https://github.com/jwoirhaye/android-device-manager-python/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/jwoirhaye/android-device-manager-python/branch/main/graph/badge.svg)](https://codecov.io/gh/jwoirhaye/android-device-manager-python) [![Docs](https://img.shields.io/badge/docs-mkdocs-blue?logo=readthedocs)](https://jwoirhaye.github.io/android-device-manager-python/) From 433468284760347644d2e4717ab61bb7bc07c7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Mon, 25 Aug 2025 20:38:56 +0200 Subject: [PATCH 3/6] docs: Fix pip install name and example usage --- README.md | 2 +- docs/examples/apk-management.md | 2 +- docs/getting-started/installation.md | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d09392a..a788f57 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Android Device Manager is a Python library for creating, launching, and managing ### 📦 From PyPI (Recommended) ```bash -pip install python-android-avd-manager +pip install android-device-manager ``` ### 🚧 From Source diff --git a/docs/examples/apk-management.md b/docs/examples/apk-management.md index d84ea0d..607784a 100644 --- a/docs/examples/apk-management.md +++ b/docs/examples/apk-management.md @@ -18,7 +18,7 @@ emulator_config = EmulatorConfiguration( no_window=True ) -with AndroidDevice(avd_config) as device: +with AndroidDevice(avd_config,emulator_config) as device: # Install APK device.install_apk("/path/to/app.apk") diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index e94d1c9..8080473 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -72,16 +72,16 @@ emulator -version sdkmanager --list_installed ``` -## Install python-android-avd-manager +## Install android-device-manager ### 📦 From PyPI (Recommended) ```bash -pip install python-android-avd-manager +pip install android-device-manager ``` ### 🚧 From Source ```bash -git clone https://github.com/jwoirhaye/python-android-avd-manager-python.git -cd python-android-avd-manager +git clone https://github.com/jwoirhaye/android-device-manager-python.git +cd android-device-manager-python pip install -e . ``` \ No newline at end of file From 2236b5d17c51ee9d4ab691c1b5de989bcb582988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Mon, 25 Aug 2025 20:43:50 +0200 Subject: [PATCH 4/6] chore: update pyproject.toml --- pyproject.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d83531e..79e4783 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,24 @@ maintainers = [ requires-python = ">=3.10" dependencies = [] +readme = { file = "README.md", content-type = "text/markdown" } +license = { file = "LICENSE" } +keywords = [ + "android", "adb", "emulator", "android emulator", "device manager", + "automation", "testing", "devtools", "python" +] +classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development", + "Topic :: Utilities", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Typing :: Typed" +] + [project.urls] Homepage = "https://github.com/jwoirhaye/android-device-manager-python" Source = "https://github.com/jwoirhaye/android-device-manager-python" From 3cf17d7841f5064492698b30d00eaab1060bb558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Mon, 25 Aug 2025 20:45:01 +0200 Subject: [PATCH 5/6] chore: update pyproject.toml --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 79e4783..da613cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ classifiers = [ "Topic :: Software Development", "Topic :: Utilities", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", From bdd67be6b7a3b3fe18f8465a4533a0a713a2882a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Woirhaye?= Date: Mon, 25 Aug 2025 21:02:29 +0200 Subject: [PATCH 6/6] feat: Add install_multi_package in android_device and adb client --- examples/install_apks.py | 27 ++++++++++++++++++++ src/android_device_manager/adb/client.py | 21 +++++++++++++++ src/android_device_manager/android_device.py | 15 +++++++++++ 3 files changed, 63 insertions(+) create mode 100644 examples/install_apks.py diff --git a/examples/install_apks.py b/examples/install_apks.py new file mode 100644 index 0000000..ffe6cc2 --- /dev/null +++ b/examples/install_apks.py @@ -0,0 +1,27 @@ +from android_device_manager import AndroidDevice +from android_device_manager.avd import AVDConfiguration +from android_device_manager.emulator import EmulatorConfiguration + +# Configure your AVD +avd_config = AVDConfiguration( + name="example_avd", + package="system-images;android-36;google_apis;x86_64" +) + +# Configure your Emulator +emulator_config = EmulatorConfiguration( + no_window=False +) + +with AndroidDevice(avd_config,emulator_config) as device: + # Install APK + device.install_multi_package([ + "/home/jwoirhay/Bureau/temp/apk_download/apks/safetravelsmain.apk", + "/home/jwoirhay/Bureau/temp/apk_download/apks/sitiosarequipa.apk" + ]) + + # List installed packages + packages = device.list_installed_packages() + print("Installed packages:") + for p in packages: + print(f"\t- {p}") diff --git a/src/android_device_manager/adb/client.py b/src/android_device_manager/adb/client.py index 5035ba7..ba632d7 100644 --- a/src/android_device_manager/adb/client.py +++ b/src/android_device_manager/adb/client.py @@ -178,6 +178,27 @@ def install_apk(self, apk_path: str, timeout: int = 60): except ADBError as e: raise ADBError(f"Failed to install APK {apk_path}: {str(e)}") + def install_multi_package(self, apk_paths: list[str], timeout: int = 120): + """ + Install multiple APKs in a single transaction using 'adb install-multi-package'. + + Args: + apk_paths (list[str]): List of APK file paths on the host. + timeout (int): Timeout in seconds for the installation. + + Raises: + ADBError: If the installation fails. + """ + if not apk_paths: + raise ADBError("No APKs provided for installation.") + + try: + args = ["install-multi-package", *apk_paths] + self._run_adb_command(args, check=True, timeout=timeout) + logger.info(f"Successfully installed APKs {apk_paths} on {self._serial}") + except ADBError as e: + raise ADBError(f"Failed to install APKs {apk_paths}: {str(e)}") + def uninstall_package( self, package_name: str, keep_data: bool = False, timeout: int = 60 ) -> None: diff --git a/src/android_device_manager/android_device.py b/src/android_device_manager/android_device.py index 67ade56..a56287e 100644 --- a/src/android_device_manager/android_device.py +++ b/src/android_device_manager/android_device.py @@ -278,6 +278,21 @@ def install_apk(self, apk_path: str, timeout: int = 30) -> None: self._ensure_running() self._adb_client.install_apk(apk_path, timeout=timeout) + def install_multi_package(self, apk_paths: list[str], timeout: int = 60) -> None: + """ + Install multiple APKs on the device in a single transaction. + + Args: + apk_paths (list[str]): A list of file paths to the APKs. + timeout (int): Timeout in seconds for the installation process (default: 60). + + Raises: + AndroidDeviceError: If the device is not running or the ADB client is not initialized. + ADBError: If the command fails. + """ + self._ensure_running() + self._adb_client.install_multi_package(apk_paths, timeout=timeout) + def uninstall_package(self, package_name: str, keep_data: bool = False) -> None: """ Uninstall a package from the device.