文章目录
概述
在 Android 设备上,应用程序的桌面图标通常存储在应用的 APK 文件中。我们可以通过反编译 APK 文件并解析 AndroidManifest.xml 文件,找到桌面图标的路径,并批量提取出这些图标。本文将详细介绍如何编写 Python 工具,结合 ADB、Apktool 等工具,实现批量获取安卓设备所有应用的桌面图标。
一、准备工作
1.1 安装 ADB
ADB(Android Debug Bridge)是与安卓设备进行交互的重要工具。首先需要确保你的电脑已经安装 ADB,并且设备开启了 USB 调试模式。
安装 ADB:
macOS:
brew install android-platform-tools
Windows:
下载ADB工具
1.2 获取设备上的应用包名
我们可以通过 ADB 工具获取 Android 设备上所有已安装应用的包名:
adb shell pm list packages
输出类似如下内容:
package:com.sina.weibo
package:com.tencent.mm
package:com.android.chrome
包名表示设备上的每一个应用,接下来我们将通过这些包名批量获取对应的 APK 文件。
1.3 使用 ADB 导出 APK 文件
通过以下命令可以导出每个应用的 APK 文件:
adb shell pm path <package_name>
adb pull <APK 路径> <本地存储路径>
例如:
adb shell pm path com.sina.weibo
adb pull /data/app/com.sina.weibo/base.apk ~/Downloads/apkList/com.sina.weibo.apk
将 APK 文件存储到 apkList 目录中。
二、提取桌面图标流程
2.1 反编译 APK 文件
为了解析 APK 文件的资源,我们需要使用 Apktool 进行反编译。
安装 Apktool:
macOS:
brew install apktool
反编译 APK:
apktool d <APK 文件路径> -o <输出目录>
例如:
apktool d ~/Downloads/apkList/com.sina.weibo.apk -o ~/Downloads/apkList/com.sina.weibo_decompiled
这样就可以得到应用的所有资源文件和 XML 文件。
2.2 解析 AndroidManifest.xml
每个应用的 AndroidManifest.xml 文件中会包含应用的图标路径,通过 android:icon 属性可以找到对应图标:
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
我们提取 android:icon 属性中的值,并通过该值定位到 res/drawable 或 res/mipmap 文件夹中的图标资源。
2.3 搜索图标资源文件
APK 文件的资源文件一般会存放在 res 文件夹下,分为 drawable 和 mipmap 两大类,根据设备的分辨率还会有 hdpi、xxhdpi 等不同目录。我们可以根据 AndroidManifest.xml 提取到的图标名,在 res 目录中搜索对应的图片文件。
三、 编写 Python 自动化工具
为了简化这一流程,我们编写一个 Python 工具,批量提取所有应用的桌面图标。
3.1 代码结构
我们将代码分为几步,分别进行 APK 反编译、图标解析、文件查找和图标导出。
import os
import shutil
import xml.etree.ElementTree as ET
# 定义 APK 目录和目标图标目录
apk_dir = "/Users/zhengkewen/Downloads/apkList"
icon_output_dir = "/Users/zhengkewen/Downloads/apkList/apkGetIcon"
# 创建目标图标目录
if not os.path.exists(icon_output_dir):
os.makedirs(icon_output_dir)
# 提取 AndroidManifest.xml 中的 icon 值
def extract_icon_value(manifest_path):
try:
tree = ET.parse(manifest_path)
root = tree.getroot()
namespace = {'android': 'http://schemas.android.com/apk/res/android'}
icon_value = root.attrib.get('{http://schemas.android.com/apk/res/android}icon')
if icon_value:
return icon_value.split('/')[-1]
return None
except Exception as e:
print(f"Error parsing {manifest_path}: {e}")
return None
# 搜索图标文件(查找 res 目录)
def find_icon_file(res_dir, icon_name):
potential_folders = ['drawable', 'mipmap']
for root, dirs, files in os.walk(res_dir):
if any(folder in root for folder in potential_folders):
for file in files:
if icon_name in file:
return os.path.join(root, file)
return None
# 批量处理 APK
def batch_process(apk_dir, icon_output_dir):
failed_packages = []
for apk_folder in os.listdir(apk_dir):
apk_path = os.path.join(apk_dir, apk_folder)
if os.path.isdir(apk_path):
manifest_path = os.path.join(apk_path, "AndroidManifest.xml")
if os.path.exists(manifest_path):
icon_name = extract_icon_value(manifest_path)
if icon_name:
res_dir = os.path.join(apk_path, "res")
icon_file = find_icon_file(res_dir, icon_name)
if icon_file:
output_dir = os.path.join(icon_output_dir, apk_folder)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
try:
shutil.copy(icon_file, output_dir)
print(f"Icon for {apk_folder} copied to {output_dir}")
except Exception as e:
print(f"Failed to copy icon for {apk_folder}: {e}")
failed_packages.append(apk_folder)
else:
print(f"Icon file not found for {apk_folder}")
failed_packages.append(apk_folder)
else:
print(f"No android:icon property found in manifest for {apk_folder}")
failed_packages.append(apk_folder)
else:
print(f"Manifest not found for {apk_folder}")
failed_packages.append(apk_folder)
# 记录失败的包
if failed_packages:
with open(os.path.join(icon_output_dir, 'failed_packages.txt'), 'w') as f:
for package in failed_packages:
f.write(f"{package}\n")
print(f"Failed packages written to: {os.path.join(icon_output_dir, 'failed_packages.txt')}")
# 运行批量处理
batch_process(apk_dir, icon_output_dir)
3.2 运行脚本
将上述脚本保存为 find_icons.py,并执行:
python3 find_icons.py
四、错误处理与优化
1. 没有 android:icon 的情况:部分应用可能没有定义 android:icon,我们增加了判断逻辑,如果没有这个属性,则记录到失败的包名列表中。
2. 图标文件不存在的情况:对于提取出的图标名称,我们通过全局搜索 drawable 和 mipmap 目录进行查找,确保找到图标文件。
3. 自动创建输出目录:如果没有目标目录,脚本会自动创建。
4. 失败包名记录:将处理失败的包名记录到 failed_packages.txt 文件中,便于后续分析。
五、总结
通过这篇文章,我们实现了一个完整的工具,能够批量获取安卓设备上所有应用的桌面图标。文章从基础准备、ADB 使用、APK 反编译、资源解析到 Python 自动化工具编写进行了全面讲解。希望对想要批量处理 APK 图标的开发者有所帮助。