补齐Android技能树 - 玩转Gradle插件 | 小册免费学(下)

简介: 本节就来了解下:Gradle插件编写的知识储备 及 插件发布相关 姿势,读者亦可自行查阅官方文档:Packaging a plugin

0x3、常用API补漏


创建配置dsl,先定义dsl结构,定义里面的属性,然后在plugin apply方法中添加以下:


TestExtension extension = project.getExtensions().create("testExt", TestExtension)
project.extensions.add("testExt", TestExtension)
project.task("TestTask") {
    doLast {
        //2.获取外界配置的 TestExtension
        TestExtension extension = project.testExt
        //3.输出插件扩展属性
        println ">>>>>>" + extension.message
    }
}
testExt {
    //给插件扩展的属性赋值
    message  "helloworld"
}


0x4、插件源码探索——美团渠道包生成插件Walle


没有啥idea,强行写个没啥用的插件没啥意思,刚好群里有人谈到了打包插件:walle,直接看人家插件是怎么实现的~


网络异常,图片无法展示
|


比起Android自带打包要快上许多,在美团技术团队的博客上有介绍这个工具的大概实现原理:新一代开源Android渠道包生成工具Walle,简单说说,等下慢慢跟一波源码~

先是v2签名前后的APK包差异:


网络异常,图片无法展示
|


多了个 APK Signing Block 区块,除它之外其它三个区块都是受保护的,签名后对这些区块的修改都逃不过应用签名方案的检查。美团的打包插件就是从 APK Signing Block 区块入手的,区块2格式描述如下:


网络异常,图片无法展示
|


然后就是从 ID-value 入手的,v2签名信息是以 ID(0x7109871a) 的ID-value来保存在这个区块中,Android系统对于其它的ID-value选择忽略,打包插件就是定义了自定义的ID-value把渠道信息写入到这个区域,App运行时读取渠道信息,再去完成特定渠道初始化。整套插件主要由四个部分组成:


  • ① 用于写入ID-value信息的Java类库;


  • ② Gradle构建插件用来和Android的打包流程进行结合 ;


  • ③ 用于读取ID-value信息的Java类库;


  • ④ 用于供 com.android.application 使用的读取渠道信息的AAR;


行吧,大概原理就了解到这里,接着跟一波插件具体的实现源码,直接定位到插件配置文件:


网络异常,图片无法展示
|


打开看下接口实现类是哪个:


网络异常,图片无法展示
|


1. GradlePlugin


定位到 GradlePlugin.groovy,逻辑不算复杂:


网络异常,图片无法展示
|


定位到 Extension.groovy,就是DSL传递的参数:


网络异常,图片无法展示
|


对应文档这里:


网络异常,图片无法展示
|


看完 applyExtension() 接着看看 applyTask()


网络异常,图片无法展示
|


跟下 ChannelMaker Task类~


2. ChannelMaker


集成 DefaultTask@TaskAction 注解标识Task本身要执行的方法:


网络异常,图片无法展示
|


然后判断


根据下述几种情况调用对应生成渠道APK的方法:


  • PROPERTY_CHANNEL_LIST→ channelList.each { generateChannelApk(...) }
  • PROPERTY_CONFIG_FILEgenerateChannelApkByConfigFile(...)
  • PROPERTY_CHANNEL_FILEgenerateChannelApkByChannelFile(...)
  • configFile instanceof FilegenerateChannelApkByConfigFile(...)
  • channelFile instanceof FilegenerateChannelApkByChannelFile(...)
  • variantConfigFileName != null && variantConfigFileName.length() > 0generateChannelApkByConfigFile(...)


上述方法各自有不同的处理,但最终调用的都是:generateChannelApk


网络异常,图片无法展示
|


呕吼,接着看看ChannelWriter是怎么写入渠道信息的~


3. ChannelWriter


跟下 put() 方法,最后调用的都是:


网络异常,图片无法展示
|


跟下 putRaw() 方法:


网络异常,图片无法展示
|


定位下 APK_CHANNEL_BLOCK_ID


网络异常,图片无法展示
|


哈,这个插件把渠道信息写到 APK Signing Block 里的 ID,跟下 PayloadWriter.put()


4. PayloadWriter


网络异常,图片无法展示
|


一步步跟,跟到putAll,看上面的代码似乎很复杂的样子?其实不然先是 ApkSigningBlockHandler 回调接口,定义了一个handle方法:


网络异常,图片无法展示
|


传入了一个 originIdValues,其实就是apk本身带的ID-value,然后遍历新的 idValues,写入其中,最后通过 addPayload() 将数据塞到 ApkSigningBlock 实例中返回。


网络异常,图片无法展示
|


接着是v3签名的一些处理,然后把渠道信息写到apk里,这里就真的是 技术活,太强了!!!


byte级别精细化的文件操作,这功底...我的确是个假安卓,跟到 ApkSigningBlock → writeApkSigningBlock()


网络异常,图片无法展示
|


就是对应上表,把区块2的内容写回apk中:


网络异常,图片无法展示
|


把渠道包信息打入到apk的大概流程就这样,任务的执行时机也在 assemble 后。

写弄懂了,接着看下读,官方文档中写道:


网络异常,图片无法展示
|


APP还要另外依赖这个aar,在运行时读取对应的渠道信息


网络异常,图片无法展示
|


跟下 WalleChannelReader,在项目的 library 目录下:


网络异常,图片无法展示
|


5. WalleChannelReader


网络异常,图片无法展示
|


传入comtext,获取apk的路径,接着传入 ChannelReader.get()


6. ChannelReader


网络异常,图片无法展示
|


跟下getMap():


网络异常,图片无法展示
|


跟下 PayloadReader.getString()


7. PayloadReader


getString() → get() → getAll()


网络异常,图片无法展示
|


RandomAccessFile.getChannel() 获得文件通道对象,然后传入 ApkUtil.findApkSigningBlock()


网络异常,图片无法展示
|


就是找到 APK Signing Block 区块,返回ByteBuffer实例,然后 ApkUtil.findIdValues(apkSigningBlock2) 获取Id-Values 们,此时再回到 ChannelReader → get() 处,就懂了吧。


这是调用 getChannel() 的实现,如果根据 key 获取则是走 getChannelInfoMap(),流程比较相似,就不再复述了。


以上就是此插件实现的完整讲解,当然核心难点Byte级别的文件操作,后面解完apk构建过程再去研究研究~


参考文献:



相关文章
|
29天前
|
Android开发
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
|
27天前
|
Android开发
Android gradle task任务检查各个module之间资源文件冲突.md
Android gradle task任务检查各个module之间资源文件冲突.md
Android gradle task任务检查各个module之间资源文件冲突.md
|
1月前
|
Java Android开发 Windows
玩转安卓之配置gradle-8.2.1
为安卓开发配置Gradle 8.2.1,包括下载和解压Gradle、配置环境变量、修改配置文件以增加国内镜像,以及在Android Studio中配置Gradle和JDK的过程。
60 0
玩转安卓之配置gradle-8.2.1
|
12天前
|
Android开发
我是一位Android工程师,用通义灵码的AS插件做开发工作助手,对比之前没有灵码,现在提效了60%
我是一位Android工程师,用通义灵码的AS插件做开发工作助手,对比之前没有灵码,现在提效了60%
28 0
|
6月前
|
编解码 Java Android开发
Android技能树 — 屏幕适配小结,2024年最新android开发环境搭建教程
Android技能树 — 屏幕适配小结,2024年最新android开发环境搭建教程
|
3月前
|
Android开发
Android Studio: 解决Gradle sync failed 错误
本文介绍了解决Android Studio中出现的Gradle同步失败错误的步骤,包括从`gradle-wrapper.properties`文件中获取Gradle的下载链接,手动下载Gradle压缩包,并替换默认下载路径中的临时文件,然后重新触发Android Studio的"Try Again"来完成同步。
1138 0
Android Studio: 解决Gradle sync failed 错误
|
3月前
|
Java 开发工具 Maven
Flutter和Android中覆盖gradle中的repositories仓库地址
Flutter和Android中覆盖gradle中的repositories仓库地址
174 4
|
3月前
|
Android开发 Kotlin
The Android Gradle plugin supports only Kotlin Gradle plugin version 1.3.10 and higher
The Android Gradle plugin supports only Kotlin Gradle plugin version 1.3.10 and higher
68 3
|
3月前
|
Java 开发工具 Android开发
Android Studio利用Build.gradle导入Git commit ID、Git Branch、User等版本信息
本文介绍了在Android Studio项目中通过修改`build.gradle`脚本来自动获取并添加Git的commit ID、branch名称和用户信息到BuildConfig类中,从而实现在编译时将这些版本信息加入到APK中的方法。
65 0
|
3月前
|
IDE API 开发工具
与Android Gradle Plugin对应的Gradle版本和Android Studio版本
与Android Gradle Plugin对应的Gradle版本和Android Studio版本
361 0