本文内容大多基于官方文档和网上前辈经验总结,经过个人实践加以整理积累,仅供参考。
Java 代码调用 aapt 工具解析 Apk,获取诸如“应用程序名称”、“版本号”、“图标”等 Apk 详情
1 保存 Apk 信息的 Bean:ApkInfo
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApkInfo {
public static final String APPLICATION_ICON_120 = "application-icon-120";
public static final String APPLICATION_ICON_160 = "application-icon-160";
public static final String APPLICATION_ICON_240 = "application-icon-240";
public static final String APPLICATION_ICON_320 = "application-icon-320";
// 所需设备属性
private List<String> features;
// 图标
private String icon;
// 各分辨率下图标路径
private Map<String, String> icons;
// 应用程序名
private String label;
// 入口Activity
private String launchableActivity;
// 支持的Android平台最低版本号
private String minSdkVersion;
// 主包名
private String packageName;
// 支持的SDK版本
private String sdkVersion;
// Apk文件大小(字节)
private long size;
// 目标SDK版本
private String targetSdkVersion;
// 所需权限
private List<String> usesPermissions;
// 内部版本号
private String versionCode;
// 外部版本号
private String versionName;
public ApkInfo() {
this.features = new ArrayList<>();
this.icons = new HashMap<>();
this.usesPermissions = new ArrayList<>();
}
public List<String> getFeatures() {
return features;
}
public void setFeatures(List<String> features) {
this.features = features;
}
public void addToFeatures(String feature) {
this.features.add(feature);
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public Map<String, String> getIcons() {
return icons;
}
public void setIcons(Map<String, String> icons) {
this.icons = icons;
}
public void addToIcons(String key, String value) {
this.icons.put(key, value);
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getLaunchableActivity() {
return launchableActivity;
}
public void setLaunchableActivity(String launchableActivity) {
this.launchableActivity = launchableActivity;
}
public String getMinSdkVersion() {
return minSdkVersion;
}
public void setMinSdkVersion(String minSdkVersion) {
this.minSdkVersion = minSdkVersion;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getSdkVersion() {
return sdkVersion;
}
public void setSdkVersion(String sdkVersion) {
this.sdkVersion = sdkVersion;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getTargetSdkVersion() {
return targetSdkVersion;
}
public void setTargetSdkVersion(String targetSdkVersion) {
this.targetSdkVersion = targetSdkVersion;
}
public List<String> getUsesPermissions() {
return usesPermissions;
}
public void setUsesPermissions(List<String> usesPermissions) {
this.usesPermissions = usesPermissions;
}
public void addToUsesPermissions(String usesPermission) {
this.usesPermissions.add(usesPermission);
}
public String getVersionCode() {
return versionCode;
}
public void setVersionCode(String versionCode) {
this.versionCode = versionCode;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
@Override
public String toString() {
return "ApkInfo [features=" + features + ", icon=" + icon + ", icons=" + icons + ", label=" + label
+ ", launchableActivity=" + launchableActivity + ", minSdkVersion=" + minSdkVersion + ", packageName="
+ packageName + ", sdkVersion=" + sdkVersion + ", size=" + size + ", targetSdkVersion="
+ targetSdkVersion + ", usesPermissions=" + usesPermissions + ", versionCode=" + versionCode
+ ", versionName=" + versionName + "]";
}
}
2 解析 Apk 的工具类
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ApkUtil {
public static final String APPLICATION = "application:";
public static final String APPLICATION_ICON = "application-icon";
public static final String APPLICATION_LABEL = "application-label";
public static final String APPLICATION_LABEL_N = "application: label";
public static final String DENSITIES = "densities";
public static final String LAUNCHABLE_ACTIVITY = "launchable";
public static final String PACKAGE = "package";
public static final String SDK_VERSION = "sdkVersion";
public static final String SUPPORTS_ANY_DENSITY = "support-any-density";
public static final String SUPPORTS_SCREENS = "support-screens";
public static final String TARGET_SDK_VERSION = "targetSdkVersion";
public static final String VERSION_CODE = "versionCode";
public static final String VERSION_NAME = "versionName";
public static final String USES_FEATURE = "uses-feature";
public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";
public static final String USES_PERMISSION = "uses-permission";
private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";
private ProcessBuilder builder;
// aapt 所在目录
private String aaptToolPath = "src/main/resources/";
public ApkUtil() {
builder = new ProcessBuilder();
builder.redirectErrorStream(true);
}
public String getAaptToolPath() {
return aaptToolPath;
}
public void setAaptToolPath(String aaptToolPath) {
this.aaptToolPath = aaptToolPath;
}
public ApkInfo parseApk(String apkPath) {
String aaptTool = aaptToolPath + getAaptToolName();
Process process = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
process = builder.command(aaptTool, "d", "badging", apkPath).start();
inputStream = process.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
ApkInfo apkInfo = new ApkInfo();
apkInfo.setSize(new File(apkPath).length());
String temp = null;
while ((temp = bufferedReader.readLine()) != null) {
setApkInfoProperty(apkInfo, temp);
}
return apkInfo;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (process != null) {
process.destroy();
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String getAaptToolName() {
String aaptToolName = "aapt";
if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
aaptToolName += ".exe";
}
return aaptToolName;
}
private void setApkInfoProperty(ApkInfo apkInfo, String source) {
System.out.println("*******************************");
if (source.startsWith(APPLICATION)) {
System.out.println(APPLICATION + " : ");
String[] rs = source.split("( icon=')|'");
apkInfo.setIcon(rs[rs.length - 1]);
} else if (source.startsWith(APPLICATION_ICON)) {
System.out.println(APPLICATION_ICON + " : ");
apkInfo.addToIcons(getKeyBeforeColon(source), getPropertyInQuote(source));
} else if (source.startsWith(APPLICATION_LABEL)) {
System.out.println(APPLICATION_LABEL + " : ");
apkInfo.setLabel(getPropertyInQuote(source));
} else if (source.startsWith(LAUNCHABLE_ACTIVITY)) {
System.out.println(LAUNCHABLE_ACTIVITY + " : ");
apkInfo.setLaunchableActivity(getPropertyInQuote(source));
} else if (source.startsWith(PACKAGE)) {
System.out.println(PACKAGE + " : ");
String[] packageInfo = source.split(SPLIT_REGEX);
apkInfo.setPackageName(packageInfo[2]);
apkInfo.setVersionCode(packageInfo[4]);
apkInfo.setVersionName(packageInfo[6]);
} else if (source.startsWith(SDK_VERSION)) {
System.out.println(SDK_VERSION + " : ");
apkInfo.setSdkVersion(getPropertyInQuote(source));
} else if (source.startsWith(TARGET_SDK_VERSION)) {
System.out.println(TARGET_SDK_VERSION + " : ");
apkInfo.setTargetSdkVersion(getPropertyInQuote(source));
} else if (source.startsWith(USES_PERMISSION)) {
System.out.println(USES_PERMISSION + " : ");
apkInfo.addToUsesPermissions(getPropertyInQuote(source));
} else if (source.startsWith(USES_FEATURE)) {
System.out.println(USES_FEATURE + " : ");
apkInfo.addToFeatures(getPropertyInQuote(source));
} else {
System.out.println("Others : ");
}
System.out.println(source);
}
private String getKeyBeforeColon(String source) {
return source.substring(0, source.indexOf(':'));
}
private String getPropertyInQuote(String source) {
int index = source.indexOf("'") + 1;
return source.substring(index, source.indexOf('\'', index));
}
}
3 单元测试代码
import org.junit.Test;
public class ParseApkTest {
@Test
public void test() {
ApkUtil apkUtil = new ApkUtil();
ApkInfo apkInfo = apkUtil.parseApk("src/test/resources/example.apk");
System.out.println("-------------------------------------");
System.out.println("APK INFO : ");
System.out.println(apkInfo);
System.out.println("-------------------------------------");
}
}
4 测试打印结果
*******************************
package :
package: name='com.xunlei.downloadprovider' versionCode='10810' versionName='5.32.2.4620' platformBuildVersionName='6.0-2704002'
*******************************
Others :
install-location:'auto'
*******************************
sdkVersion :
sdkVersion:'14'
*******************************
targetSdkVersion :
targetSdkVersion:'23'
*******************************
uses-permission :
uses-permission: name='com.xiaomi.permission.AUTH_SERVICE'
*******************************
uses-permission :
uses-permission: name='android.permission.GET_ACCOUNTS'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_DOWNLOAD_MANAGER'
*******************************
uses-permission :
uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
*******************************
uses-permission :
uses-permission: name='com.android.browser.permission.READ_HISTORY_BOOKMARKS'
*******************************
uses-permission :
uses-permission: name='android.permission.INTERNET'
*******************************
uses-permission :
uses-permission: name='android.permission.WAKE_LOCK'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_WIFI_STATE'
*******************************
uses-permission :
uses-permission: name='android.permission.READ_PHONE_STATE'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
*******************************
uses-permission :
uses-permission: name='android.permission.CHANGE_WIFI_MULTICAST_STATE'
*******************************
uses-permission :
uses-permission: name='com.android.launcher.permission.INSTALL_SHORTCUT'
*******************************
uses-permission :
uses-permission: name='com.android.launcher.permission.READ_SETTINGS'
*******************************
uses-permission :
uses-permission: name='com.android.launcher.permission.WRITE_SETTINGS'
*******************************
uses-permission :
uses-permission: name='com.android.launcher.permission.UNINSTALL_SHORTCUT'
*******************************
uses-permission :
uses-permission: name='android.permission.VIBRATE'
*******************************
uses-permission :
uses-permission: name='android.permission.WRITE_SETTINGS'
*******************************
uses-permission :
uses-permission: name='android.permission.READ_SETTINGS'
*******************************
uses-permission :
uses-permission: name='android.permission.SYSTEM_ALERT_WINDOW'
*******************************
uses-permission :
uses-permission: name='android.permission.CAMERA'
*******************************
uses-permission :
uses-permission: name='android.permission.RESTART_PACKAGES'
*******************************
uses-permission :
uses-permission: name='android.permission.GET_TASKS'
*******************************
uses-permission :
uses-permission: name='android.permission.READ_LOGS'
*******************************
uses-permission :
uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_COARSE_LOCATION'
*******************************
uses-permission :
uses-permission: name='android.permission.INTERACT_ACROSS_USERS_FULL'
*******************************
uses-permission :
uses-permission: name='android.permission.READ_SMS'
*******************************
uses-permission :
uses-permission: name='com.xunlei.downloadprovider.permission.MIPUSH_RECEIVE'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_COARSE_UPDATES'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_FINE_LOCATION'
*******************************
uses-permission :
uses-permission: name='android.permission.DISABLE_KEYGUARD'
*******************************
uses-permission :
uses-permission: name='android.permission.DOWNLOAD_WITHOUT_NOTIFICATION'
*******************************
uses-permission :
uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
*******************************
uses-permission :
uses-permission: name='android.permission.EXPAND_STATUS_BAR'
*******************************
uses-permission :
uses-permission: name='com.xunlei.downloadprovider.permission.JPUSH_MESSAGE'
*******************************
uses-permission :
uses-permission: name='android.permission.RECEIVE_USER_PRESENT'
*******************************
uses-permission :
uses-permission: name='android.permission.CHANGE_WIFI_STATE'
*******************************
uses-permission :
uses-permission: name='android.permission.ACCESS_LOCATION_EXTRA_COMMANDS'
*******************************
uses-permission :
uses-permission: name='android.permission.CHANGE_NETWORK_STATE'
*******************************
uses-permission :
uses-permission: name='android.permission.BROADCAST_PACKAGE_ADDED'
*******************************
uses-permission :
uses-permission: name='android.permission.BROADCAST_PACKAGE_CHANGED'
*******************************
uses-permission :
uses-permission: name='android.permission.BROADCAST_PACKAGE_INSTALL'
*******************************
uses-permission :
uses-permission: name='android.permission.BROADCAST_PACKAGE_REPLACED'
*******************************
uses-permission :
uses-permission: name='android.permission.RECORD_AUDIO'
*******************************
uses-permission :
uses-permission: name='android.permission.RECORD_AUDIO'
*******************************
uses-permission :
uses-permission: name='android.permission.FLASHLIGHT'
*******************************
uses-permission :
uses-permission: name='android.permission.SET_DEBUG_APP'
*******************************
uses-permission :
uses-permission: name='android.permission.USE_CREDENTIALS'
*******************************
uses-permission :
uses-permission: name='android.permission.MANAGE_ACCOUNTS'
*******************************
uses-permission :
uses-permission: name='android.permission.MODIFY_AUDIO_SETTINGS'
*******************************
application-label :
application-label-af:'迅雷'
*******************************
application-label :
application-label-am:'迅雷'
*******************************
application-label :
application-label-ar:'迅雷'
*******************************
application-label :
application-label-az-AZ:'迅雷'
*******************************
application-label :
application-label-bg:'迅雷'
*******************************
application-label :
application-label-bn-BD:'迅雷'
*******************************
application-label :
application-label-ca:'迅雷'
*******************************
application-label :
application-label-cs:'迅雷'
*******************************
application-label :
application-label-da:'迅雷'
*******************************
application-label :
application-label-de:'迅雷'
*******************************
application-label :
application-label-el:'迅雷'
*******************************
application-label :
application-label-en-AU:'迅雷'
*******************************
application-label :
application-label-en-GB:'迅雷'
*******************************
application-label :
application-label-en-IN:'迅雷'
*******************************
application-label :
application-label-es:'迅雷'
*******************************
application-label :
application-label-es-US:'迅雷'
*******************************
application-label :
application-label-et-EE:'迅雷'
*******************************
application-label :
application-label-eu-ES:'迅雷'
*******************************
application-label :
application-label-fa:'迅雷'
*******************************
application-label :
application-label-fi:'迅雷'
*******************************
application-label :
application-label-fr:'迅雷'
*******************************
application-label :
application-label-fr-CA:'迅雷'
*******************************
application-label :
application-label-gl-ES:'迅雷'
*******************************
application-label :
application-label-gu-IN:'迅雷'
*******************************
application-label :
application-label-hi:'迅雷'
*******************************
application-label :
application-label-hr:'迅雷'
*******************************
application-label :
application-label-hu:'迅雷'
*******************************
application-label :
application-label-hy-AM:'迅雷'
*******************************
application-label :
application-label-in:'迅雷'
*******************************
application-label :
application-label-is-IS:'迅雷'
*******************************
application-label :
application-label-it:'迅雷'
*******************************
application-label :
application-label-iw:'迅雷'
*******************************
application-label :
application-label-ja:'迅雷'
*******************************
application-label :
application-label-ka-GE:'迅雷'
*******************************
application-label :
application-label-kk-KZ:'迅雷'
*******************************
application-label :
application-label-km-KH:'迅雷'
*******************************
application-label :
application-label-kn-IN:'迅雷'
*******************************
application-label :
application-label-ko:'迅雷'
*******************************
application-label :
application-label-ky-KG:'迅雷'
*******************************
application-label :
application-label-lo-LA:'迅雷'
*******************************
application-label :
application-label-lt:'迅雷'
*******************************
application-label :
application-label-lv:'迅雷'
*******************************
application-label :
application-label-mk-MK:'迅雷'
*******************************
application-label :
application-label-ml-IN:'迅雷'
*******************************
application-label :
application-label-mn-MN:'迅雷'
*******************************
application-label :
application-label-mr-IN:'迅雷'
*******************************
application-label :
application-label-ms-MY:'迅雷'
*******************************
application-label :
application-label-my-MM:'迅雷'
*******************************
application-label :
application-label-nb:'迅雷'
*******************************
application-label :
application-label-ne-NP:'迅雷'
*******************************
application-label :
application-label-nl:'迅雷'
*******************************
application-label :
application-label-pa-IN:'迅雷'
*******************************
application-label :
application-label-pl:'迅雷'
*******************************
application-label :
application-label-pt:'迅雷'
*******************************
application-label :
application-label-pt-BR:'迅雷'
*******************************
application-label :
application-label-pt-PT:'迅雷'
*******************************
application-label :
application-label-ro:'迅雷'
*******************************
application-label :
application-label-ru:'迅雷'
*******************************
application-label :
application-label-si-LK:'迅雷'
*******************************
application-label :
application-label-sk:'迅雷'
*******************************
application-label :
application-label-sl:'迅雷'
*******************************
application-label :
application-label-sq-AL:'迅雷'
*******************************
application-label :
application-label-sr:'迅雷'
*******************************
application-label :
application-label-sv:'迅雷'
*******************************
application-label :
application-label-sw:'迅雷'
*******************************
application-label :
application-label-ta-IN:'迅雷'
*******************************
application-label :
application-label-te-IN:'迅雷'
*******************************
application-label :
application-label-th:'迅雷'
*******************************
application-label :
application-label-tl:'迅雷'
*******************************
application-label :
application-label-tr:'迅雷'
*******************************
application-label :
application-label-uk:'迅雷'
*******************************
application-label :
application-label-ur-PK:'迅雷'
*******************************
application-label :
application-label-uz-UZ:'迅雷'
*******************************
application-label :
application-label-vi:'迅雷'
*******************************
application-label :
application-label-zh-CN:'迅雷'
*******************************
application-label :
application-label-zh-HK:'迅雷'
*******************************
application-label :
application-label-zh-TW:'迅雷'
*******************************
application-label :
application-label-zu:'迅雷'
*******************************
application-icon :
application-icon-160:'res/mipmap-mdpi-v4/ic_launcher.png'
*******************************
application-icon :
application-icon-240:'res/mipmap-hdpi-v4/ic_launcher.png'
*******************************
application-icon :
application-icon-320:'res/mipmap-xhdpi-v4/ic_launcher.png'
*******************************
application-icon :
application-icon-480:'res/mipmap-xxhdpi-v4/ic_launcher.png'
*******************************
application-icon :
application-icon-640:'res/mipmap-xxhdpi-v4/ic_launcher.png'
*******************************
application: :
application: label='迅雷' icon='res/mipmap-mdpi-v4/ic_launcher.png'
*******************************
launchable :
launchable-activity: name='com.xunlei.downloadprovider.launch.LaunchActivity' label='迅雷' icon=''
*******************************
Others :
feature-group: label=''
*******************************
Others :
uses-feature: name='android.hardware.camera'
*******************************
Others :
uses-feature: name='android.hardware.camera.autofocus'
*******************************
Others :
uses-feature: name='android.hardware.faketouch'
*******************************
Others :
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
*******************************
Others :
uses-feature: name='android.hardware.location'
*******************************
Others :
uses-implied-feature: name='android.hardware.location' reason='requested android.permission.ACCESS_COARSE_LOCATION permission, requested android.permission.ACCESS_FINE_LOCATION permission, and requested android.permission.ACCESS_LOCATION_EXTRA_COMMANDS permission'
*******************************
Others :
uses-feature: name='android.hardware.microphone'
*******************************
Others :
uses-implied-feature: name='android.hardware.microphone' reason='requested android.permission.RECORD_AUDIO permission'
*******************************
Others :
uses-feature: name='android.hardware.screen.landscape'
*******************************
Others :
uses-implied-feature: name='android.hardware.screen.landscape' reason='one or more activities have specified a landscape orientation'
*******************************
Others :
uses-feature: name='android.hardware.screen.portrait'
*******************************
Others :
uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
*******************************
Others :
uses-feature: name='android.hardware.telephony'
*******************************
Others :
uses-implied-feature: name='android.hardware.telephony' reason='requested a telephony permission'
*******************************
Others :
uses-feature: name='android.hardware.wifi'
*******************************
Others :
uses-implied-feature: name='android.hardware.wifi' reason='requested android.permission.ACCESS_WIFI_STATE permission, requested android.permission.CHANGE_WIFI_MULTICAST_STATE permission, and requested android.permission.CHANGE_WIFI_STATE permission'
*******************************
Others :
main
*******************************
Others :
other-activities
*******************************
Others :
other-receivers
*******************************
Others :
other-services
*******************************
Others :
supports-screens: 'small' 'normal' 'large' 'xlarge'
*******************************
Others :
supports-any-density: 'true'
*******************************
Others :
locales: 'af' 'am' 'ar' 'az-AZ' 'bg' 'bn-BD' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-GB' 'en-IN' 'es' 'es-US' 'et-EE' 'eu-ES' 'fa' 'fi' 'fr' 'fr-CA' 'gl-ES' 'gu-IN' 'hi' 'hr' 'hu' 'hy-AM' 'in' 'is-IS' 'it' 'iw' 'ja' 'ka-GE' 'kk-KZ' 'km-KH' 'kn-IN' 'ko' 'ky-KG' 'lo-LA' 'lt' 'lv' 'mk-MK' 'ml-IN' 'mn-MN' 'mr-IN' 'ms-MY' 'my-MM' 'nb' 'ne-NP' 'nl' 'pa-IN' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'si-LK' 'sk' 'sl' 'sq-AL' 'sr' 'sv' 'sw' 'ta-IN' 'te-IN' 'th' 'tl' 'tr' 'uk' 'ur-PK' 'uz-UZ' 'vi' 'zh-CN' 'zh-HK' 'zh-TW' 'zu'
*******************************
Others :
densities: '160' '240' '320' '480' '640'
*******************************
Others :
native-code: 'armeabi-v7a'
-------------------------------------
APK INFO :
ApkInfo [features=[], icon=res/mipmap-mdpi-v4/ic_launcher.png, icons={application-icon-320=res/mipmap-xhdpi-v4/ic_launcher.png, application-icon-640=res/mipmap-xxhdpi-v4/ic_launcher.png, application-icon-240=res/mipmap-hdpi-v4/ic_launcher.png, application-icon-160=res/mipmap-mdpi-v4/ic_launcher.png, application-icon-480=res/mipmap-xxhdpi-v4/ic_launcher.png}, label=迅雷, launchableActivity=com.xunlei.downloadprovider.launch.LaunchActivity, minSdkVersion=null, packageName=com.xunlei.downloadprovider, sdkVersion=14, size=27251987, targetSdkVersion=23, usesPermissions=[com.xiaomi.permission.AUTH_SERVICE, android.permission.GET_ACCOUNTS, android.permission.ACCESS_DOWNLOAD_MANAGER, android.permission.WRITE_EXTERNAL_STORAGE, com.android.browser.permission.READ_HISTORY_BOOKMARKS, android.permission.INTERNET, android.permission.WAKE_LOCK, android.permission.ACCESS_WIFI_STATE, android.permission.READ_PHONE_STATE, android.permission.ACCESS_NETWORK_STATE, android.permission.CHANGE_WIFI_MULTICAST_STATE, com.android.launcher.permission.INSTALL_SHORTCUT, com.android.launcher.permission.READ_SETTINGS, com.android.launcher.permission.WRITE_SETTINGS, com.android.launcher.permission.UNINSTALL_SHORTCUT, android.permission.VIBRATE, android.permission.WRITE_SETTINGS, android.permission.READ_SETTINGS, android.permission.SYSTEM_ALERT_WINDOW, android.permission.CAMERA, android.permission.RESTART_PACKAGES, android.permission.GET_TASKS, android.permission.READ_LOGS, android.permission.RECEIVE_BOOT_COMPLETED, android.permission.ACCESS_COARSE_LOCATION, android.permission.INTERACT_ACROSS_USERS_FULL, android.permission.READ_SMS, com.xunlei.downloadprovider.permission.MIPUSH_RECEIVE, android.permission.ACCESS_COARSE_UPDATES, android.permission.ACCESS_FINE_LOCATION, android.permission.DISABLE_KEYGUARD, android.permission.DOWNLOAD_WITHOUT_NOTIFICATION, android.permission.READ_EXTERNAL_STORAGE, android.permission.EXPAND_STATUS_BAR, com.xunlei.downloadprovider.permission.JPUSH_MESSAGE, android.permission.RECEIVE_USER_PRESENT, android.permission.CHANGE_WIFI_STATE, android.permission.ACCESS_LOCATION_EXTRA_COMMANDS, android.permission.CHANGE_NETWORK_STATE, android.permission.BROADCAST_PACKAGE_ADDED, android.permission.BROADCAST_PACKAGE_CHANGED, android.permission.BROADCAST_PACKAGE_INSTALL, android.permission.BROADCAST_PACKAGE_REPLACED, android.permission.RECORD_AUDIO, android.permission.RECORD_AUDIO, android.permission.FLASHLIGHT, android.permission.SET_DEBUG_APP, android.permission.USE_CREDENTIALS, android.permission.MANAGE_ACCOUNTS, android.permission.MODIFY_AUDIO_SETTINGS], versionCode=10810, versionName=5.32.2.4620]
-------------------------------------
5 保存解析的 APK 图标文件
.apk 实际上是一种特殊格式的压缩文件,可以将其解压缩后通过解析得到的图标文件名称找到对应的图标文件保存下来
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ApkIconUtil {
public static void extractFileFromApk(String apkPath, String fileName, String outputPath) throws IOException {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(apkPath);
ZipEntry entry = zipFile.getEntry(fileName);
InputStream inputStream = zipFile.getInputStream(entry);
File file = new File(outputPath);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024);
byte[] b = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(inputStream, 1024);
while(bis.read(b) != -1){
bos.write(b);
}
bos.flush();
bos.close();
bis.close();
inputStream.close();
zipFile.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6 保存 APK 图标的单元测试代码
import java.io.IOException;
import org.junit.Test;
public class ParseApkTest {
@Test
public void test() throws IOException {
String apkPath = "src/test/resources/example.apk";
ApkUtil apkUtil = new ApkUtil();
ApkInfo apkInfo = apkUtil.parseApk(apkPath);
System.out.println("-------------------------------------");
System.out.println("APK INFO : ");
System.out.println(apkInfo);
System.out.println("-------------------------------------");
ApkIconUtil.extractFileFromApk(apkPath, apkInfo.getIcon(), "src/test/resources/icon.png");
}
}