Java使用aapt解析安卓apk信息(Windows、Linux)

最近在做spring boot的项目应用更新管理模块,上传android apk并自动解析apk信息。

我使用的方法有两种:

1.种用axmlprinter2.jar包解析,读取AndroidManifest文件相关信息。

2.使用aapt(Android Asset Packaging Tool),Android资源打包工具。

使用jar解析时有些apk读取不出来,因此推荐使用第二种方法。

aapt解析apk信息(支持Windows、Linux)

1.获取aapt.exe,Windows上使用。

android SDK安装目录下:\Android\Sdk\build-tools\28.0.3

2.获取aapt,Linux上使用。

首先下载最新工具包,apktool_2.3.4.jar

下载地址:https://ibotpeaches.github.io/Apktool/install/

解压缩,aapt在prebuit/aapt/linux/

3.将aapt放在src/main/resources

具体实现代码如下:

/*****
 * 
 * @author ZhongXiang.Huang
 * apk工具类。封装了获取Apk信息的方法。
 * 
 * ******/
public class ApkUtil {
	
	private static final Logger log = LoggerFactory.getLogger(AppUpdateController.class);
	
	/********
	 * 使用aapt.exe工具解析
	 * 
	 * *******/
	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/aapt/";
//
    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 aaptToolPath, 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));
    }
}
ApkUtil apkUtil = new ApkUtil();
ApkInfo apkInfo = apkUtil.parseApk(getApptToolPath(), path);

/*****
*/部署时aapt/目录下要放在jar包同级目录,并要给aapt赋予运行权限
***/
private String getApptToolPath() {
    if(env.equals("dev")) {
    	return "src/main/resources/aapt/";
    }else {
    	//ali环境 Linux,以jar包运行
    	String jarPath = System.getProperty("java.class.path");
      	int firstIndex = jarPath.lastIndexOf(System.getProperty("path.separator")) + 1;
       	int lastIndex = jarPath.lastIndexOf(File.separator) + 1;
       	String path = jarPath.substring(firstIndex, lastIndex);
       	return path + "/aapt/";       	
    }  
}

使用jar包解析

maven地址: 

<dependency>
	<groupId>ca.mcgill.sable</groupId>
	<artifactId>axmlprinter2</artifactId>
	<version>2016-07-27</version>
</dependency>

具体代码:

/*****
 * 
 * @author ZhongXiang.Huang
 * apk工具类。封装了获取Apk信息的方法。
 * 
 * ******/
public class ApkUtil {
	
	private static final Logger log = LoggerFactory.getLogger(AppUpdateController.class);
	
    /********
	 * 使用axmlprinter2-1.21.jar解析
	 * 
	 * *******/
    public static Map<String,Object> readAPK(String apkUrl){
        ZipFile zipFile;
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("code", "success");
        try {
            zipFile = new ZipFile(apkUrl);
            Enumeration<?> enumeration = zipFile.entries();
            
            ZipEntry zipEntry = null;
            while (enumeration.hasMoreElements()) {
                zipEntry = (ZipEntry) enumeration.nextElement();
                if (zipEntry.isDirectory()) {

                } else {
                    if ("androidmanifest.xml".equals(zipEntry.getName().toLowerCase())) {
                        AXmlResourceParser parser = new AXmlResourceParser();
                        parser.open(zipFile.getInputStream(zipEntry));
                       
                        while (true) {
                            int type = parser.next();
                            if (type == XmlPullParser.END_DOCUMENT) {
                                break;
                            }
                            String name = parser.getName();
                            if(null != name && name.toLowerCase().equals("manifest")){
                                for (int i = 0; i != parser.getAttributeCount(); i++) {
                                    if ("versionName".equals(parser.getAttributeName(i))) {
                                        String versionName = getAttributeValue(parser, i);
                                        if(null == versionName){
                                            versionName = "";
                                        }
                                        map.put("versionName", versionName);
                                    } else if ("package".equals(parser.getAttributeName(i))) {
                                        String packageName = getAttributeValue(parser, i);
                                        if(null == packageName){
                                            packageName = "";
                                        }
                                        map.put("package", packageName);
                                    } else if("versionCode".equals(parser.getAttributeName(i))){
                                        String versionCode = getAttributeValue(parser, i);
                                        if(null == versionCode){
                                            versionCode = "";
                                        }
                                        map.put("versionCode", versionCode);
                                    }
                                }
                                break;
                            }
                        }
                    }

                }
            }
            zipFile.close();
        } catch (Exception e) {
            map.replace("code", "fail");
            map.put("error","读取apk失败,请手动填写。");
            e.printStackTrace();
        }
        return map;
    }

    private static String getAttributeValue(AXmlResourceParser parser, int index) {
        int type = parser.getAttributeValueType(index);
        int data = parser.getAttributeValueData(index);
        if (type == TypedValue.TYPE_STRING) {
            return parser.getAttributeValue(index);
        }
        if (type == TypedValue.TYPE_ATTRIBUTE) {
            return String.format("?%s%08X", getPackage(data), data);
        }
        if (type == TypedValue.TYPE_REFERENCE) {
            return String.format("@%s%08X", getPackage(data), data);
        }
        if (type == TypedValue.TYPE_FLOAT) {
            return String.valueOf(Float.intBitsToFloat(data));
        }
        if (type == TypedValue.TYPE_INT_HEX) {
            return String.format("0x%08X", data);
        }
        if (type == TypedValue.TYPE_INT_BOOLEAN) {
            return data != 0 ? "true" : "false";
        }
        if (type == TypedValue.TYPE_DIMENSION) {
            return Float.toString(complexToFloat(data)) + DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
        }
        if (type == TypedValue.TYPE_FRACTION) {
            return Float.toString(complexToFloat(data)) + FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
        }
        if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
            return String.format("#%08X", data);
        }
        if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
            return String.valueOf(data);
        }
        return String.format("<0x%X, type 0x%02X>", data, type);
    }

    private static String getPackage(int id) {
        if (id >>> 24 == 1) {
            return "android:";
        }
        return "";
    }

    // / ILLEGAL STUFF, DONT LOOK :)
    public static float complexToFloat(int complex) {
        return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3];
    }

    private static final float RADIX_MULTS[] = 
    {
         0.00390625F, 3.051758E-005F, 
         1.192093E-007F, 4.656613E-010F 
     };
    private static final String DIMENSION_UNITS[] = { "px", "dip", "sp", "pt", "in", "mm", "", "" };
    private static final String FRACTION_UNITS[] = { "%", "%p", "", "", "", "", "", "" };


}

参考文献:https://blog.csdn.net/silent_paladin/article/details/57112105

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解析 APK 并获取其信息和公钥,可以使用 Android SDK 中的 aapt 工具和 .NET 的 Process 类来执行命令并获取输出。下面是一个示例 C# 代码: ```csharp using System; using System.Diagnostics; namespace ApkParser { class Program { static void Main(string[] args) { string apkPath = "path/to/apk/file.apk"; string aaptPath = "path/to/aapt.exe"; // 执行命令获取 APK 信息 var processStartInfo = new ProcessStartInfo { FileName = aaptPath, Arguments = $"d badging \"{apkPath}\"", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(processStartInfo)) { process.WaitForExit(); var output = process.StandardOutput.ReadToEnd(); // 解析输出获取 APK 信息 var packageName = GetValueFromOutput(output, "package: name='", "'"); var versionCode = GetValueFromOutput(output, "versionCode='", "'"); var versionName = GetValueFromOutput(output, "versionName='", "'"); var publicKey = GetValueFromOutput(output, "publicKey='", "'"); Console.WriteLine($"Package Name: {packageName}"); Console.WriteLine($"Version Code: {versionCode}"); Console.WriteLine($"Version Name: {versionName}"); Console.WriteLine($"Public Key: {publicKey}"); } } static string GetValueFromOutput(string output, string startTag, string endTag) { var startIndex = output.IndexOf(startTag) + startTag.Length; var endIndex = output.IndexOf(endTag, startIndex); return output.Substring(startIndex, endIndex - startIndex); } } } ``` 在代码中,我们首先指定 APK 文件路径和 aapt 工具路径,然后使用 Process 类执行命令获取 APK 信息,并解析输出获取信息和公钥。最后将结果输出到控制台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值