zoukankan      html  css  js  c++  java
  • c#调用aapt查看apk文件信息功能实现

    第一篇随笔就此开始。

    1. 起源

    思路源自于项目开发过程中。需要确认apk文件版本以验证其功能差异以便于定位问题,于是度娘,得到APK信息查看器(APK-info)这个工具,其版本号为0.2。
    它能显示apk详细的信息,如下图示:

    但它使用不够方便,只能通过双击打开对话框找到apk文件然后显示,或者拖放apk到其图标上打开,不支持拖放至界面打开。它也没有再打开入口,且对中文支持很不好,如右图百度手机卫士apk信息。

    2. 原理

    析其原理,原来通过aapt.exe解开apk包中AndroidManifest.xml文件来实现信息展示。
    而aapt.exe使用方法,网上诸多教程。apk信息尽存于AndroidManifest.xml中,它是加密的xml文件,用aapt之dump命令做个解析尝试,其语法如下:

    >aapt dump badging QQ_482.apk

    似乎想要的信息都有了……慢着,中文呢?
    >aapt dump badging QQ_482.apk

    中文显示乱码。乱就乱吧,咱转码!
    如何不自己写个类似工具?好,整!

    3. 实现

    以此为思路,c#实现解析,获取cmd管道输出数据,核心代码如下(为界面响流畅,我置解析入一线程中):

            private void Decoder(object state)
            {
                if (!File.Exists(this.apkPath))
                    return;
                string aaptPath = Path.Combine(this.appPath, @"toolsaapt.exe");
                if (!File.Exists(aaptPath))
                    aaptPath = Path.Combine(this.appPath, @"aapt.exe");
                if (!File.Exists(aaptPath))
                {
                    var handler = AaptNotFoundEvent;
                    if (handler != null)
                        handler();
                    return;
                }
    
                var startInfo = new ProcessStartInfo(aaptPath);
                string args = string.Format("dump badging "{0}"", this.apkPath);
                startInfo.Arguments = args;
                startInfo.UseShellExecute = false;
                startInfo.RedirectStandardOutput = true;
                startInfo.CreateNoWindow = true;
                using (var process = Process.Start(startInfo))
                {
                    var sr = process.StandardOutput;
                    while (!sr.EndOfStream)
                    {
                        infos.Add(sr.ReadLine());
                    }
                    process.WaitForExit();
                    //解析
                    ParseInfo(sr.CurrentEncoding);
                }
            }
    //application: label='MobileGo™' icon='r/l/icon.png'
    if (info.IndexOf("application:") == 0)
    {
        string appName = GetKeyValue(info, "label=");    
        this.AppName = Encoding.UTF8.GetString(currentEncoding.GetBytes(appName));
        this.IconPath = GetKeyValue(info, "icon=");
        GetAppIcon(this.IconPath);
    }

    其执行界面如下:

    可以看得出,对中文支持,仍然不够友好,即便通过utf-8到默认中文编码转换。
    怎么办呢?

    4. 改进

    而用其直接输出于一外部文件中,中文显示却是正确的:
    >aapt dump badging QQshurufa_1991.apk > info.txt

    解析输出文件吧!对这种方案,我一开始是抵触的,因为不想额外成生文件;能截用内部cmd管道输出,我就不愿生成外部文件,说是情怀也好洁癖也罢,只是个人喜好。
    但目前转码方案尝试无效,就只得用吧,获取输出信息代码如下:

            private void Decoder(object state)
            {
                if (!File.Exists(this.apkPath))
                    return;
                string aaptPath = Path.Combine(this.appPath, @"toolsaapt.exe");
                if (!File.Exists(aaptPath))
                    aaptPath = Path.Combine(this.appPath, @"aapt.exe");
                if (!File.Exists(aaptPath))
                {
                    var handler = AaptNotFound;
                    if (handler != null)
                        handler();
                    return;
                }
    
                StringBuilder sb = new StringBuilder(255);
                int result = GetShortPathName(aaptPath, sb, 255);
                if (result != 0)
                    aaptPath = sb.ToString();
    
                var startInfo = new ProcessStartInfo("cmd.exe");
                string dumpFile = Path.GetTempFileName();
                //如此费事做中转,只为处理中文乱码
                string args = string.Format("/k {0} dump badging "{1}" > "{2}" &exit", aaptPath, this.apkPath, dumpFile);
                startInfo.Arguments = args;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                this.infos.Clear();
                using (var process = Process.Start(startInfo))
                {
                    process.WaitForExit(2000);
                }
                if (File.Exists(dumpFile))
                {
                    //解析
                    using (var sr = new StreamReader(dumpFile, Encoding.UTF8))
                    {
                        string line;
                        while ((line = sr.ReadLine()) != null)
                        {
                            this.infos.Add(line);
                        }
                        ParseInfo();
                    }
                    try
                    {
                        File.Delete(dumpFile);
                    }
                    catch
                    {
                    }
                }
            }

    好吧,一切正常了……只是其中构建cmd管道脚本,颇为费些工夫。

    看看下图中文信息显示,一切正常:

    5. 后记

    这是我第一篇博客,写代码十数年,虽时时想记录经验与心得,奈何懒惰,至此方忍不住,终于写出来。

    其实此例成完成已久,只是近来更做完善,查询资料过程中看到Meteoric_cry的博文:windows下apk查看工具的原理,颇觉异曲同工之妙,而他也因此写了APK Helper这一工具,简单而易用。

    本欲置源代码入Github,奈何折腾半天,亦未成功,因此计划暂且搁置。

    此工具我置于网上,亦根据需要作不定时更新,如有需要伙伴尽管拿去用,下载地址为:ApkInfo.zip。若小伙伴有其它需要,可留言以待

    6. 追加

    2017-03-14更新:费了许多工夫,终于传代码至GitHub,今夜可以安睡。项目址为:https://github.com/awei78/ApkInfo
    希望有需要的朋友以做参考。或者,咱们一起更完善它,以适合实际需要。

  • 相关阅读:
    14. D3D光照
    17. 增加对硬件光照的支持
    ECommerce Starter Kit 数据库表和存储过程一览
    使用 DataAdapter 执行批量更新
    学习Professional ASP.NET 2.0(四)
    c#泛型学习(二)
    学习Professional ASP.NET 2.0(一)
    学习Professional ASP.NET 2.0(二)
    下载:微软网页设计工具CTP测试版(支持asp.net2.0)
    学习ECommerce Starter Kit (1)
  • 原文地址:https://www.cnblogs.com/crwy/p/6540160.html
Copyright © 2011-2022 走看看