03 March 2020

Walle

知识点

  1. ApplicationInfo.sourceDir 获取已安装应用对应的安装文件apk
  2. 系统安装apk时是如何做签名校验的
  3. 基于ZIP文件格式和APK Signing Block存储格式而构建,基于文件的二进制流进行处理 签名后apk文件构成
    1. ZIP文件的格式是
       [local file header + file data + data descriptor]{1,n} + central directory + end of central directory  record
       [文件头+文件数据+数据描述符]{此处可重复n次}+核心目录+目录结束标识
       当压缩包中有多个文件时,就会有多个[文件头+文件数据+数据描述符]
      

    首先我们找到 end of central directory record 的起始位置,从末尾开始找,因为comment的长度不固定,还得遍历一下,得到comnentLength

    1. 得到comnentLength后,根据eocd的格式构成,可以知道 central directory 的size(offset16 4位表示)。得到了centralDirStartOffset

    2. 这样我们可以准确定位到 APK Signing Block 的存储区域

    3. 分析 APK Signing Block 的格式

      1. 该块包含ID值对,这种方式使得APK更容易找到该块,APK的v2签名存储在ID为0x7109871a的键值对中。

GradlePlugin 插件分析学习呀呀呀呀呀

知识点

  • 已经可以用kotlin编写gradle文件了,语法清晰,可读性好,支持语法高亮,代码补全,代码跳转 https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/

  • DSL(Domain Specific Language’) 领域专用语言。DSL的简洁性往往是一种思维上的简洁性,使我们不用费太多的气力就能看懂代码所对应的业务含义。Groovy是一种开源的脚本语言,在Java基础上进行了扩展,支持闭包、动态类型、元编程等特性。

  1. 构建模型
    • 是个有向无环图
  2. 三个构建阶段
    1. 初始化阶段,解析 settings.build 哪些project会参与构建
    2. 配置阶段,构建task的有向无环图,执行属于配置阶段的代码,解析 build.gradle
    3. 执行阶段,按序执行task
     //setting.gradle
     println 'This is executed during the initialization phase.' // settings.gradle 中的代码在初始化阶段执行
    
     //build.gradle
     println 'This is executed during the configuration phase.' // 在配置阶段执行
    
     // 普通的自定义 Task
     task testBoth {
         doFirst {
           println 'This is executed first during the execution phase.' // doFirst 中的代码在执行阶段执行
         }
         doLast {
           println 'This is executed last during the execution phase.' // doLast 中的代码在执行阶段执行
         }
         println 'This is executed during the configuration phase as well.' // 非 doFirst 或者 doLast 中的代码,在配置阶段执行
     }
    
  3. 一个build.gradle对应一个Project对象,在gradle文件中可通过project属性访问该对象。 rootProject属性代表根Project对象,即项目根目录下的build.gradle文件。

  4. Project是由一系列的task组成,你可以自定义task,也可以继承已有的task,如Copy Delete
     task customTask(){
         doLast{
             print '自定义任务'
         }
     }
    
  5. 如何访问task。通过TaskContainer对象,在gradle文件中通过 tasks 属性访问该对象
     afterEvaluate {
         def aTask = tasks.getByName('assembleDebug')
         println "aTask name is ${aTask.name}"
         aTask.dependsOn(customTask)
         // 这样执行 assembleDebug 前都会执行customTask
     }
    
  6. 在build.gradle中调用属性,或调用Project.property(java.lang.String)方法时,会按顺序从以下范围查找:

    1. Project自身定义的属性
    2. Project的Extra属性
    3. 插件添加的Extension属性
    4. 插件添加的Convension属性
    5. Project中Task的名字
    6. 从父Project继承的属性,一直递归到RootProject

    在build.gradle中调用方法时,会按顺序从以下范围查找:

    1. Project自身定义的方法
    2. build.gradle脚本定义的方法
    3. 插件添加类型为Action或Closure的Extension
    4. 插件添加的Convension方法
    5. Project中Task的名字都会创建一个对应方法
    6. 从父Project继承的方法,一直递归到RootProject
    7. Project中为Closure类型的属性可以作为方法调用
  7. Task代表构建过程中的一个原子操作,每个Task属于一个Project。每个Task都有一个名字。所属Project名+Task名可组成唯一的完整名 每个Task包含一个Action序列,并在Task执行时按先后顺序执行。通过Task的doFirst/doLast方法可以往Action序列的头部/末尾添加Action,支持Action或闭包(闭包会被转换成Action对象)

每个Task可以依赖其他Task,执行Task时会先执行其依赖的Task,通过dependsOn可设置依赖。每个Task还可以设置在其他Task之前、之后执行,一般可通过mustRunAfter设置。 例如下面的配置,执行A时一定会先执行B;执行A不一定会执行C;当A、C都要执行时一定先执行C。

taskA.dependsOn(taskB) taskA.mustRunAfter(taskC)

* Task的创建
    在build.gradle中创建Task,最常见写法如下。task(xxx)是Project提供的API,最终调用了TaskContainer的create方法。可接收参数包括:
        Task名称(必选)
        Map<String, ?>类型配置(可选)
        闭包配置(可选)

* 还可以用类实现Task,创建Task时指定type为这个class即可,并且还可以传参数 [gradle基础](https://www.paincker.com/gradle-develop-basics)
  1. PluginAware主要定义了插件相关API,Gradle Settings Project等接口均继承了PluginAware接口。

apply plugin:’java’ 其中 plugin:’java’ 是一个map类型 apply plguin:’com.android.application’ 编译android的插件,独立的复杂的大插件,研究的也是这个。

apply from:’xxx/my_script.gradle’ 注意在 my_script 中定义的属性和方法,build.gradle无法访问,因为每个gradle文件都编译成单独的Groovy Script,这些属性只是Script类的成员。

如果在不同脚本之间传递数据,可以利用Gradle/Setting/Project对象的ext属性实现。

  1. 简易插件开发 下面的示例代码实现了HelloPlugin的简易插件,代码可直接写在build.gradle中。

插件在apply(Project)方法里,给Project创建了一个名为hello的Extension和一个名为welcome的Task;Task执行时读取Extension并打印字符串。

在build.gradle执行到apply plugin: HelloPlugin时,HelloPlugin.apply(Project)方法被执行,从而Project有了hello的Extension,于是后面可以调用hello {}对插件进行配置。

class HelloExtension {
    Boolean enable = true
    String text = ''
}
class HelloPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.extensions.create('hello', HelloExtension)
        project.task('welcome') {
            doLast {
                HelloExtension ext = project.extensions.hello;
                println ext.enable ? "Hello ${ext.text}!" : 'HelloPlugin is disabled.'
            }
        }
    }
}
apply plugin: HelloPlugin
hello {
    enable = true
    text = 'Gradle'
}
在命令行中执行结果如下。

$ ./gradlew welcome
:welcome
Hello Gradle!
BUILD SUCCESSFUL
Total time: 0.917 secs


blog comments powered by Disqus