代码改变世界

Android插件化开发之OpenAtlas生成插件信息列表

2017-08-03 10:47  tlnshuju  阅读(565)  评论(0编辑  收藏  举报

上一篇文章。[Android插件化开发之Atlas初体验](
http://blog.csdn.net/sbsujjbcy/article/details/47446733),简单的介绍了使用Atlas的整个流程,可是假设你没有实践过的话预计还是一头雾水。从这篇文章開始,慢慢的切入细节。这篇文章的主题是生成插件信息列表。

细心的你也许发现了上篇文章中我们使用了一个叫openatlasbundler的项目生成了so以及一个json文件,说白了这个so仅仅只是就是apk重命名的。而这个json文件里包括了插件的信息。比方上篇文章中的两个插件,其信息例如以下。

[
  {
    "pkgName": "com.lizhangqu.test",
    "version": "1.0",
    "activities": [
      "com.lizhangqu.test.MainActivity"
    ],
    "services": [],
    "receivers": [],
    "contentProviders": [],
    "dependency": [],
    "md5": "882d50a3c2668360b96a3af8f72b3bd2",
    "size": 24780,
    "hasSO": false
  },
  {
    "pkgName": "com.lizhangqu.zxing",
    "version": "1.0",
    "activities": [
      "com.lizhangqu.zxing.android.CaptureActivity"
    ],
    "services": [],
    "receivers": [],
    "contentProviders": [],
    "dependency": [],
    "md5": "e68270557ae9776d218bb034916c124a",
    "size": 312352,
    "hasSO": false
  }
]

能够看到里面存了插件的一些组件信息。以及大写和md5等。

依照作者原话说是这种。

BundleList的生成。这部分用的Java写的,BundleListInfo一个存储json的文本文件,我们所做的这一切无非是提高效率,举个样例。你安装插件的时候假设有动态库的话要解压。不能安装的时候每个文件检測一下apk存在so不。打开文件本来就慢。程序优化一点是一点

我们能够试试,假设不将该so文件打包进去,程序执行会出现什么。

这里写图片描写叙述

这里写图片描写叙述

这里写图片描写叙述
我们发现,打印了一个日志说找不到插件信息列表。

至于插件信息列表的读取。这里姑且不去理会,本篇的重点是怎样生成该列表。

打开BundleMakeBooter类,里面就一个main函数,也就是说这个仅仅只是是普通的java项目,事实上我们能够从命令行将參数传入,可是还记得上篇文章我们将前三行代码凝视掉,增加了三行写死的代码。

args=new String[2];
args[0]="C:\\Users\\kltz\\Desktop\\AtlasDemo\\plugin";
args[1]="C:\\Users\\kltz\\Desktop\\AtlasDemo\\plugin\\bundle-info.json";

数组第一个參数代表待处理的apk所在文件夹,数组第二个參数代表生成的插件信息存的文件。而我们是在项目根文件夹建立一个文件夹叫plugin,后来将插件的apk都拷贝到该文件夹进行处理。

main函数中開始调用了ApkPreProcess.preProcess(path);将第一个參数传入,该函数所做的事事实上非常easy,就是将apk重命名为so,怎么个重命名法呢。

首先遍历该文件夹,得到以apk后缀的文件,通过解析拿到该apk的包名,将该apk命名为lib开头。后面紧跟包名。包名中的.会被替换成_。最后文件后缀是so,假设该文件夹存在了该so,则将原so文件删除。然后将apk重命名。就是这么简单。

看代码

public static void preProcess(String mDir) {
        Collection<File> apkFiles = org.apache.commons.io.FileUtils.listFiles(new File(mDir), new String[]{"apk"}, true);

        for (File file : apkFiles) {
            String pkgName = PackageLite.parse(file.getAbsolutePath()).packageName;

            pkgName = "lib" + pkgName.replaceAll("\\.", "_") + ".so";
            File targetFile = new File(mDir + File.separator + pkgName);
            if (targetFile.exists())
                targetFile.delete();

            System.out.println("rename: " + file.getName() + " -> " + pkgName);
            while(!file.renameTo(targetFile)) {
                System.gc();
                Thread.yield();
            }
            System.out.println("ApkPreProcess.preProcess() processed " + pkgName);
        }
    }

重命名完毕后接下来就是遍历该文件夹,查找以libcom_开头的的文件,注意这里是一个约定,就是包名以com开头。

然后通过PackageLite.parse()函数解析每个so。通过packageLit.getBundleInfo()函数获得解析结果并将其扔到一个json数组中去。最后将该json数组写入文件。也就是args数组第二个參数指定的内容。

置于怎样解析,这里不做展开了,代码太长。事实上这个已经涉及到反编译的范畴了,事实上该项目的一大部分源代码是AXMLPrinter的源代码。一个android xml反编译的东西,这里提供源代码下载AXMLPrinter。 倒是能够看看getBundleInfo()函数

public JSONObject getBundleInfo() throws JSONException {
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("pkgName", packageName);
        jsonObject.put("version", versionName);
        JSONArray activityArray=new JSONArray();
        for (String name:activitys) {
            activityArray.put(name);
        }
        jsonObject.put("activities", activityArray);
        JSONArray servicesArray=new JSONArray();
        for (String name:services) {
            servicesArray.put(name);
        }
        jsonObject.put("services", servicesArray);
        JSONArray receiversArray=new JSONArray();
        for (String name:receivers) {
            receiversArray.put(name);
        }
        jsonObject.put("receivers", receiversArray);

        JSONArray providersArray=new JSONArray();
        for (String name:providers) {
            providersArray.put(name);
        }
        jsonObject.put("contentProviders", providersArray);
        JSONArray dependencyArray=new JSONArray();
        for (String name:dependency) {
            dependencyArray.put(name);
        }
        jsonObject.put("dependency", dependencyArray);
        jsonObject.put("md5", apkMD5);
        jsonObject.put("size", size);
        jsonObject.put("hasSO", hasSO);

        return jsonObject;

    }

事实上就是将解析结果转化为json。非常easy有木有。

注意生成的json文件的文件名称要为bundle-info.json,当然你也能够通过改动代码使用别的文件名称,然后该文件要放在assets文件夹下。

解析该json文件的代码在openatlascore项目中的BundleParser类中的parser函数中,有兴趣能够先去看看。

接下来要做的事就是将该json打包进apk,把so放到相应文件夹。即armeabi文件夹下,依照作者的原话就是加快启动速度,能够见这个issue插件能够不放在主project的libs/armeabi目錄下麼

还有,赶紧亲自试一试吧,仅仅要亲自试过了之后,才会认为,哦。原来是这么一回事啊。

什么,源代码。木有源代码,代码见上一篇文章末尾[Android插件化开发之Atlas初体验](
http://blog.csdn.net/sbsujjbcy/article/details/47446733)