Android 携程动态加载框架的打包流程分析

转载 2015年11月20日 09:27:12

最近携程开源了一套动态加载的框架,总的来说,该框架和OpenAtlas还是有一定的相似之处的,比如资源的分区。此外该框架也支持热修复。个人觉得该框架中携程做的比较多的应该在打包语句的编写上面,这篇文章主要用于记录自己学习该框架的一个过程,携程的打包语句是我见过最复杂的,所以还是非常值得借鉴的。在携程的github上的DynamicAPK上,给出的打包方法是命令行执行gradle,如下

<code class="hljs php has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">git <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">clone</span> https:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//github.com/CtripMobile/DynamicAPK.git</span>
cd DynamicAPK/
gradlew assembleRelease bundleRelease repackAll</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

该命令行中执行打包的语句gradlew assembleRelease bundleRelease repackAll,之后就会在对应目录下生成/build-outputs/appname-release-final.apk文件,这条打包语句可以分解为三条语句依次执行,即gradlew assembleReleasegradlew bundleReleasegradlew repackAll,我们依次来看这三个命令到底做了什么。

gradlew assembleRelease

该命令定义在sample模块的build.gradle文件中

<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">//打包后产出物复制到build-outputs目录。apk、manifest、mapping
task copyReleaseOutputs(type:Copy){
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">from</span> (<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/outputs/apk/sample-release.apk"</span>) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">rename</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'sample-release.apk'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-base-release.apk'</span>
    }
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">from</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/intermediates/manifests/full/release/AndroidManifest.xml"</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">from</span> (<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/outputs/mapping/release/mapping.txt"</span>) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">rename</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'mapping.txt'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-base-mapping.txt'</span>
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">into</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">new</span> File(rootDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'build-outputs'</span>)
}

assembleRelease<<{
    copyReleaseOutputs.execute()
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

从上面的语句看到,在执行完assembleRelease的时候,还执行了copyReleaseOutputs这个task,而这个task所做的就是将sample目录下的build目录中生成的部分文件拷贝到build-outputs目录中

  • 第一个文件是生成的apk文件,并对其进行了重命名;该文件用于后续插件打包的时候资源的引用等。
  • 第二个文件是android的清单文件AndroidManifest.xml,直接复制不进行重命名;
  • 第三个文件是mapping.txt文件,并对其进行了重名名。其中第三个文件是和代码混淆相关的,如果没有开启代码混淆,该文件是不存在的。

该task执行后,目录中生成的文件如图所示,其中mapping.txt文件的存在是因为我开启了混淆。

这里写图片描述

开启混淆的方式如下

<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">buildTypes {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
    release {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
        minifyEnabled true
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

gradlew bundleRelease

之后执行的就是bundleRelease,这个task最终目的是生成插件so(后缀为so,本质还是apk,这也是很多加壳的应用反编译不出来什么东西的原因)

<code class="hljs bash has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">task bundleRelease (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">type</span>:Zip,dependsOn:[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'compileRelease'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'aaptRelease'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'dexRelease'</span>]){
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/dex/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${project.name}</span>_dex.zip"</span>
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/res/resources.zip"</span>

    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${rootDir}</span>/build-outputs/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${apkName}</span>.so"</span>

    archiveName = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${apkName}</span>.so"</span>
    destinationDir = file(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${rootDir}</span>/build-outputs"</span>)
    duplicatesStrategy = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'fail'</span>
    from zipTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/dex/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${project.name}</span>_dex.zip"</span>)
    from zipTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/res/resources.zip"</span>)
}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

该task会生成插件的相关so文件到build-outputs目录,该目录在会在其依赖的task中事先创建好,首先会在插件模块的build目录中将dex.zip和resources.zip压缩文件中的文件(这两个文件的生成在其依赖的task中完成)作为输入文件,重新压缩为一个so文件,so的名字为包名.so,其中包名中的点修改为了下划线,见下图

这里写图片描述

这里写图片描述

这里写图片描述

该task需要依赖其他三个Task,依次为aaptReleasecompileReleasedexRelease

<code class="hljs scala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化,确保必要目录都存在</span>
task init << {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(rootDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'build-outputs'</span>).mkdirs()

    buildDir.mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'gen/r'</span>).mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'intermediates'</span>).mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'intermediates/classes'</span>).mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'intermediates/classes-obfuscated'</span>).mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'intermediates/res'</span>).mkdirs()

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(buildDir, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'intermediates/dex'</span>).mkdirs()

}

task aaptRelease (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">type</span>: Exec,dependsOn:<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'init'</span>){
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$sdk.androidJar"</span>
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${rootDir}/build-outputs/demo-base-release.apk"</span>
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/AndroidManifest.xml"</span>
    inputs.dir <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/res"</span>
    inputs.dir <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/assets"</span>
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${rootDir}/sample/build/generated/source/r/release/ctrip/android/sample/R.java"</span>

    outputs.dir <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/gen/r"</span>
    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/intermediates/res/resources.zip"</span>
    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/intermediates/res/aapt-rules.txt"</span>

    workingDir buildDir
    executable sdk.aapt

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> resourceId=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> parseApkXml=(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> XmlParser()).parse(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(rootDir,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'apk_module_config.xml'</span>))
    parseApkXml.Module.each{ module->
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>( module.<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@packageName</span>==<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${packageName}"</span>) {
            resourceId=module.<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@resourceId</span>
            println <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"find packageName: "</span> + module.<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@packageName</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" ,resourceId:"</span> + resourceId
        }
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> argv = []
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'package'</span>   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//打包</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-v"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-f'</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//强制覆盖已有文件</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-I"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$sdk.androidJar"</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//添加一个已有的固化jar包</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-I'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${rootDir}/build-outputs/demo-base-release.apk"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-M'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/AndroidManifest.xml"</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//指定manifest文件</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-S'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/res"</span>                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//res目录</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-A'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$projectDir/assets"</span>                 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//assets目录</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-m'</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//make package directories under location specified by -J</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-J'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/gen/r"</span>         <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//哪里输出R.java定义</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-F'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/intermediates/res/resources.zip"</span>   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//指定apk的输出位置</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-G'</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//-G  A file to output proguard options into.</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$buildDir/intermediates/res/aapt-rules.txt"</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// argv << '--debug-mode'      //manifest的application元素添加android:debuggable="true"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'--custom-package'</span>      <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//指定R.java生成的package包名</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${packageName}"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-0'</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//指定哪些后缀名不会被压缩</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'apk'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'--public-R-path'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${rootDir}/sample/build/generated/source/r/release/ctrip/android/sample/R.java"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'--apk-module'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$resourceId"</span>

    args = argv

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li></ul>

可以看到输出了一个resources.zip文件,这个文件就是bundleRelease 中用到的压缩文件之一,总的来说该task就是拼接命令行参数生成文件。

aaptRelease是对插件资源文件的编译,依赖于aapt命令行工具,在了解该Task之前,需要了解一下该命令的一些参数。

  • -I add an existing package to base include set

这个参数可以在依赖路径中追加一个已经存在的package。在Android中,资源的编译也需要依赖,最常用的依赖就是SDK自带的android.jar本身。打开android.jar可以看到,其实不是一个普通的jar包,其中不但包含了已有SDK类库class,还包含了SDK自带的已编译资源以及资源索引表resources.arsc文件。在日常的开发中,我们也经常通过@android:color/opaque_red形式来引用SDK自带资源。这一切都来自于编译过程中aapt对android.jar的依赖引用。同理,我们也可以使用这个参数引用一个已存在的apk包作为依赖资源参与编译。

  • -G A file to output proguard options into.

资源编译中,对组件的类名、方法引用会导致运行期反射调用,所以这一类符号量是不能在代码混淆阶段被混淆或者被裁减掉的,否则等到运行时会找不到布局文件中引用到的类和方法。-G方法会导出在资源编译过程中发现的必须keep的类和接口,它将作为追加配置文件参与到后期的混淆阶段中。

  • -J specify where to output R.java resource constant definitions

在Android中,所有资源会在Java源码层面生成对应的常量ID,这些ID会记录到R.java文件中,参与到之后的代码编译阶段中。在R.java文件中,Android资源在编译过程中会生成所有资源的ID,作为常量统一存放在R类中供其他代码引用。在R类中生成的每一个int型四字节资源ID,实际上都由三个字段组成。第一字节代表了Package,第二字节为分类,三四字节为类内ID。

在对插件的编译过程中,携程主要用了三个参数。其中也不乏携程自己改装aapt增加的参数。如下

  • 使用-I参数对宿主的apk进行引用。

据此,插件的资源、xml布局中就可以使用宿主的资源和控件、布局类了。

  • 为aapt增加–apk-module参数。

资源ID其实有一个PackageID的内部字段。我们为每个插件工程指定独特的PackageID字段,这样根据资源ID就很容易判明,此资源需要从哪个插件apk中去查找并加载了。

  • 为aapt增加–public-R-path参数。

按照对android.jar包中资源使用的常规手段,引用系统资源可使用它的R类的全限定名android.R来引用具体ID,以便和当前项目中的R类区分。插件对于宿主的资源引用,当然也可以使用base.package.name.R来完成。但由于历史原因,各子BU的“插件”代码是从主app中解耦独立出去的,资源引用还是直接使用当前工程的R。如果改为标准模式,则当前大量遗留代码中R都需要酌情改为base.R,工程量大并且容易出错,未来对bu开发人员的使用也有点不够“透明”。因此我们在设计上做了让步,额外增加–public-R-path参数,为aapt指明了base.R的位置,让它在编译期间把base的资源ID定义在插件的R类中完整复制一份,这样插件工程即可和之前一样,完全不用在乎资源来自于宿主或者自身,直接使用即可。当然这样做带来的副作用就是宿主和插件的资源不应有重名,这点我们通过开发规范来约束,相对比较容易理解一些。

了解了这么一些基础的概念之后,回头再来看看该task所做的工作。首先调用了task init进行一些目录的创建,然后引入创建apk资源文件所有必要的文件,再通过检查apk_module_config.xml文件,找到对应包名的resourceId,该文件的定义如下

<code class="hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">ApkModules</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">Module</span>  <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">packageName</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"ctrip.android.demo1"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">resourceId</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"0x31"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">Module</span>  <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">packageName</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"ctrip.android.demo2"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">resourceId</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"0x36"</span>/></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">ApkModules</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

之后做的就是拼接命令行语句,执行生成资源就可以了。而拼接的命令行语句中,指定了很多参数,如-I、–apk-module、–public-R-path等等,具体意义在上文已经解释过了,最终的产物就是资源文件的压缩包resources.zip。

compileRelease这个task的作用就是编译java文件,会指定classpath目录以及目标目录等相关信息。

<code class="hljs bash has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">task compileRelease(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">type</span>: JavaCompile,dependsOn:<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'aaptRelease'</span>) {
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$sdk</span>.androidJar"</span>
    inputs.files fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${projectDir}</span>/libs"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.jar'</span>)
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${rootDir}</span>/sample/build/intermediates/classes-proguard/release/classes.jar"</span>
    inputs.files fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$projectDir</span>/src"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/*.java'</span>)
    inputs.files fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/gen/r"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/*.java'</span>)

    outputs.dir <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/classes"</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">source</span>Compatibility = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'1.6'</span>
    targetCompatibility = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'1.6'</span>
    classpath = files(
            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${sdk.androidJar}</span>"</span>,
            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${sdk.apacheJar}</span>"</span>,
            fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${projectDir}</span>/libs"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.jar'</span>),


            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${rootDir}</span>/sample/build/intermediates/classes-proguard/release/classes.jar"</span>
        )

    destinationDir = file(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/intermediates/classes"</span>)

    dependencyCacheDir = file(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${buildDir}</span>/dependency-cache"</span>)

    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">source</span> = files(fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$projectDir</span>/src"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/*.java'</span>),
            fileTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$buildDir</span>/gen/r"</span>).include(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/*.java'</span>))
    options.encoding = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'UTF-8'</span>
}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>

最终的生成文件会在build/intermediates/classes中,可以看出最终的产物应该是一些列的class类文件

dexRelease这个task的作用就是根据compileRelease生成的classes文件,调用dx命令行工具打包成android专用的dex文件。

<code class="hljs bash has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">task dexRelease (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">type</span>:Exec){
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${buildDir}</span>/intermediates/classes"</span>
    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${buildDir}</span>/intermediates/dex/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${project.name}</span>_dex.zip"</span>
    workingDir buildDir
    executable sdk.dex

    def argv = []
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'--dex'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"--output=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${buildDir}</span>/intermediates/dex/<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${project.name}</span>_dex.zip"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${buildDir}</span>/intermediates/classes"</span>

    args = argv
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

这个task输出了一个dex.zip,也是bundleRelease这个task中用到的一个压缩包之一。

gradlew repackAll

这个task主要是调用了其他5个task

<code class="hljs rust has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">task</span> repackAll(dependsOn: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'reload'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'resign'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'repack'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'realign'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'concatMappings'</span>])
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

下面来一一分析这几个task

reload的作用就是往最开始生成的宿主文件的apk的assets目录中,添加插件so,而so正是前面几个task生成的插件so文件,最终的产物是demo-release-reloaded.apk这个文件

<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">//base apk的assets中填充各子apk<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//输入:Ctrip-base-release.apk</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//输出:Ctrip-release-reloaded.apk</span>
task reload(type:Zip){
    inputs.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span>  <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-base-release.apk"</span>
    inputs.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">files</span> fileTree(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">new</span> File(rootDir,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'build-outputs'</span>)).<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">include</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.so'</span>)
    outputs.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-reloaded.apk"</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">into</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'assets/baseres/'</span>,{
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">from</span> fileTree(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">new</span> File(rootDir,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'build-outputs'</span>)).<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">include</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.so'</span>)
    }

    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">from</span> zipTree(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-base-release.apk"</span>), {
        exclude(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/META-INF/*.SF'</span>)
        exclude(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'**/META-INF/*.RSA'</span>)
    }

    destinationDir <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/"</span>)

    archiveName <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-release-reloaded.apk'</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

apk文件发生了改变,需要对其进行重新签名,resign这个task的目的就是这个,调用命令行签名工具,添加证书的信息进行签名,但是在签名前会进行一次压缩,repack 这个task就是进行这个操作,最后输出的是demo-release-repacked.apk,打包完毕后便会进行签名的操作,也就是resign这个task所做的工作

<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//对apk重新压缩,调整各文件压缩比到正确</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//输入:Ctrip-release-reloaded.apk</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//输出:Ctrip-release-repacked.apk</span>
task repack (dependsOn: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'reload'</span>) {
    inputs.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-reloaded.apk"</span>
    outputs.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-repacked.apk"</span>

    doLast{
        println <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"release打包之后,重新压缩一遍,以压缩resources.arsc"</span>

        def oldApkFile = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-reloaded.apk"</span>)

        assert oldApkFile != <span class="hljs-constant" style="box-sizing: border-box;">null</span> : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"没有找到release包!"</span>

        def newApkFile = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">new</span> File(oldApkFile.parentFile, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-release-repacked.apk'</span>)

       <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> //重新打包</span>
        repackApk(oldApkFile.absolutePath, newApkFile.absolutePath)

        assert newApkFile.exists() : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"没有找到重新压缩的release包!"</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
<code class="hljs bash has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">//对apk重签名
//输入:Ctrip-release-repacked.apk
//输出:Ctrip-release-resigned.apk
task resign(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">type</span>:Exec,dependsOn: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'repack'</span>){
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$rootDir</span>/build-outputs/demo-release-repacked.apk"</span>
    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$rootDir</span>/build-outputs/demo-release-resigned.apk"</span>

    workingDir <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$rootDir</span>/build-outputs"</span>
    executable <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">${System.env.'JAVA_HOME'}</span>/bin/jarsigner"</span>

    def argv = []
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-verbose'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-sigalg'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'SHA1withRSA'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-digestalg'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'SHA1'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-keystore'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$rootDir</span>/demo.jks"</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-storepass'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'123456'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-keypass'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'123456'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-signedjar'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-release-resigned.apk'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-release-repacked.apk'</span>
    argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo'</span>

    args = argv
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

签名完毕后会输出签名后的文件demo-release-resigned.apk

而repack这个task最终调用的是repackApk重新进行压缩打包的

<code class="hljs scala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.zip.ZipEntry
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.zip.ZipFile
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.zip.ZipOutputStream

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 打包过程中很多手工zip过程:</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1,为了压缩resources.arsc文件而对标准产出包重新压缩</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2,以及各子apk的纯手打apk包</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 但对于音频等文件,压缩会导致资源加载报异常</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 重新打包方法,使用STORED过滤掉不应该压缩的文件们</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 后缀名列表来自于android源码</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> repackApk(originApk, targetApk){
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> noCompressExt = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".jpg"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".jpeg"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".png"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".gif"</span>,
                         <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".wav"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mp2"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mp3"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".ogg"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".aac"</span>,
                         <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mpg"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mpeg"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mid"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".midi"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".smf"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".jet"</span>,
                         <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".rtttl"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".imy"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".xmf"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".mp4"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".m4a"</span>,
                         <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".m4v"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".3gp"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".3gpp"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".3g2"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".3gpp2"</span>,
                         <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".amr"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".awb"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".wma"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".wmv"</span>]

    ZipFile zipFile = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ZipFile(originApk)
    ZipOutputStream zos = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ZipOutputStream(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> BufferedOutputStream(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FileOutputStream(targetApk)))
    zipFile.entries().each{ entryIn ->
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(entryIn.directory){
            println <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"${entryIn.name} is a directory"</span>
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>{
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> entryOut = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ZipEntry(entryIn.name)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> dotPos = entryIn.name.lastIndexOf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'.'</span>)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> ext = (dotPos >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) ? entryIn.name.substring(dotPos) : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> isRes = entryIn.name.startsWith(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'res/'</span>)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(isRes && ext in noCompressExt){
                entryOut.method = ZipEntry.STORED
                entryOut.size = entryIn.size
                entryOut.compressedSize = entryIn.size
                entryOut.crc = entryIn.crc
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>{
                entryOut.method = ZipEntry.DEFLATED
            }
            zos.putNextEntry(entryOut)
            zos << zipFile.getInputStream(entryIn)
            zos.closeEntry()
        }
    }
    zos.finish()
    zos.close()
    zipFile.close()
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li></ul>

当然,签名完毕后会对该apk进行4K对齐操作。

<code class="hljs scala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//重新对jar包做对齐操作</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//输入:Ctrip-release-resigned.apk</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//输出:Ctrip-release-final.apk</span>
task realign (dependsOn: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'resign'</span>) {
    inputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-resigned.apk"</span>
    outputs.file <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-final.apk"</span>

    doLast{
        println <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'重新zipalign,还可以加大压缩率!'</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> oldApkFile = file(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"$rootDir/build-outputs/demo-release-resigned.apk"</span>)
        assert oldApkFile != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"没有找到release包!"</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> newApkFile = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(oldApkFile.parentFile,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'demo-release-final.apk'</span>)

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> cmdZipAlign = getZipAlignPath()
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> argv = []
        argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-f'</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//overwrite existing outfile.zip</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// argv << '-z'    //recompress using Zopfli</span>
        argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-v'</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//verbose output</span>
        argv << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'4'</span>     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//alignment in bytes, e.g. '4' provides 32-bit alignment</span>
        argv << oldApkFile.absolutePath
        argv << newApkFile.absolutePath

        project.exec {
            commandLine cmdZipAlign
            args argv
        }

        assert newApkFile.exists() : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"没有找到重新zipalign的release包!"</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>

最后还有一个task,就是concatMappings,这个task很简单,做的就是合并一下mapping文件。


/**
 * 用来连接文件的task
 */
class ConcatFiles extends DefaultTask {
    @InputFiles
    FileCollection sources

    @OutputFile
    File target

    @TaskAction
    void concat() {
        File tmp = File.createTempFile('concat', null, target.getParentFile())
        tmp.withWriter { writer ->
            sources.each { file ->
                file.withReader { reader ->
                    writer << reader
                }
            }
        }
        target.delete()
        tmp.renameTo(target)
    }
}
//合并base和所有模块的mapping文件
task concatMappings(type: ConcatFiles){
    sources = fileTree(new File(rootDir,'build-outputs')).include('*mapping.txt')
    target = new File(rootDir,'build-outputs/demo-mapping-final.txt')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

最终repackAll这个task的产物如下

这里写图片描述

以上就是携程动态加载框架的打包流程分析,纯属个人看法,如有不正确的地方,请给予指正。

阿里调度系统zeus 安装使用

1、下载携程修改的zeus源码 git clone https://github.com/ctripcorp/dataworks-zeus.git 2、编译源码 进入工程目录,  编译成eclipse...

DynamicAPK基本概念

从这篇blog开始,我准备写一个关于Android动态加载的博客,主要Android插件开发的原理,前面几篇主要以携程开源的DynamicAPK 的源码作为基础来进行分析,后面可能会对该库进行一些改...
  • lzyzsd
  • lzyzsd
  • 2015年12月06日 23:39
  • 7384

携程DynamicAPK插件化框架源码分析

携程DynamicAPK插件化框架源码分析Author:莫川插件核心思想1.aapt的改造分别对不同的插件项目分配不同的packageId,然后对各个插件的资源进行编译,生成R文件,然后与宿主项目的R...

[Android 插件化(一)] DynamicLoadApk的用法

1 简介Android大型项目中为了减小apk的体积,可以采用插件化的方法,即一些不常用的功能独立成插件,当用户需要的使用的时候再从服务器上下载回来,动态加载。这样就避免了为了满足所有用户需求而把功能...

dynamic-load-apk动态加载框架 无需安装apk可由宿主调起

singwhatiwanna/dynamic-load-apk https://github.com/singwhatiwanna/dynamic-load-apk DL : ...

正确运行携程DynamicAPK

首先保证你已经配置好JAVA环境,检查系统变量里面是否含有JAVA_HOME 然后从github下载项目 $ git clone https://github.com/CtripMobile/Dy...
  • ujnnet
  • ujnnet
  • 2016年07月27日 10:16
  • 947

【FastDev4Android框架开发】实例解析之SwipeRefreshLayout+RecyclerView+CardView(三十五)

(一).前言:              作为Android L开始,Google更新了新控件RecyclerView和CardView,这两个控件在之前的文章中已经做了详细介绍和使用,同时在前面还对...

Android M 新的运行时权限开发者需要知道的一切

android M 的名字官方刚发布不久,最终正式版即将来临! android在不断发展,最近的更新 M 非常不同,一些主要的变化例如运行时权限将有颠覆性影响。惊讶的是android社区鲜有谈论这事...

携程动态加载框架

  • 2016年07月09日 11:19
  • 7.73MB
  • 下载

携程Android App的插件化和动态加载框架

携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验。本文将详细介绍Android平台插件式开发和动态加载技术的原理和实...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 携程动态加载框架的打包流程分析
举报原因:
原因补充:

(最多只允许输入30个字)