2BAB's Engineering Blog

Gradle 日常崩 - 含 buildscript 闭包的脚本执行顺序问题

最近在改一个裹脚布项目,对打包脚本升级的要求是「循序渐进」(工期紧,稳定为主)——Debug 下用新版的 Gradle Plugin,Release 用旧版的。嗯,很自然会想到改动 root project 下的 build.gradle,加一段判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// apply isDebug() method from utils.gradle
apply from: project.getRootProject().rootDir.absolutePath + '/scripts/utils.gradle'
def gradlePluginVersion = isDebug() ? '2.3.3' : '2.0.0'
buildscript {
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
dependencies {
// use outer variable
classpath "com.android.tools.build:gradle:$gradlePluginVersion"
classpath ...
}
}
...

Gradle 日常崩 - AAR 的 tools:replace 冲突

最近做一些 SDK 升级时,有些包引入后会有诸如此类的报错:

AndroidManifest.xml:22:9-40 Error:
Attribute application@theme value=(@style/AppTheme) from AndroidManifest.xml:22:9-40
is also present at [some:libraries:version] AndroidManifest.xml:9:18-62 value=(@style/AnotherTheme).
Suggestion: add ‘tools:replace=”android:theme”‘ to element at AndroidManifest.xml:18:5-65:19 to override.

这是一个很常见的错误了,照着提示做 replace 就 OK 了。但是当我加上 replace 的代码后,发现依旧报错:

Multiple entries with same key: @android:theme=REPLACE and android:theme=REPLACE.

百思不得其解,查看了一下依赖库的 AndroidManifest.xml 源码,发现它也设置了tools:replace="android:theme",而 Manifest Merger 把这个视为冲突抛了出来。

Gradle 日常崩 - 再谈 AAR 与混淆

之前写了篇文章讲到了由于 buildTypes 默认设置的原因导致 library module 无法 debug 的情况。事实上,当时只解决了打 Debug 包的情况,而忽略了打 Release 包时还埋了一个隐藏的问题。

问题还原:我们在做全局的 rebuild 或者 assembleRelease 时,会出现有些类找不到的情况,而 assembleDebug 不会。仔细观察会发现,这些报错的类都是被外部 module 引用的部分,例如 module A 有类 Clazz,被 module B 引用,则 Clazz 报错。

Gradle 日常崩 - 2.3.0 Plugin 再无 exploded-aar

升级 Android Gradle Plugin 至 2.3.0 后,会发现 exploded-aar 这个 build 目录下的文件夹大部分情况下不存在了(但是仍然有时候会出现一两个 aar 的解压包,有些诡异)。这个改动最相关的原因是 2.3.0 默认开启了 Build Cache,具体在这里有说明。

Gradle 日常崩 - Library Module BuildTypes

最近工作中换了一个工程,重新配了一遍 Gradle 的环境,然后发现所有的 Library Module 都无法 Debug 或者只能取到某些全局变量(局部变量找不到)。百思不得其解时,突然发现我明明打的是 Debug 包 assembleDebug,我的 Library Module 执行的却都是 transformClassesAndResourcesWithProguardForRelease。明明在这些 module 都配置了 debugbuildTypes,但却不生效,反而打了混淆的 release 包。

Android源码笔记-2-源码结构及Framework层结构

源码结构

框架图

图片来自 Android Source Overview

android_framework_details

Android源码笔记-1-编译&烧录的一些坑

由于最近工作需要 + 自己也挺感兴趣,折腾起 Android 的下层开发。

环境描述:

  • macOS 10.12 Sierra
  • Xcode 8(安装各种环境会用到,然而正式编译时没用这个)
  • android-5.1.1_r14,LMY48M,Nexus 7(flo)

Android插件化笔记-6-StartPluginService

Demo: https://github.com/2BAB/Android-Plugin-Dev-Notes

上节学习到了插件化资源 ID 冲突的问题和解法,本节主要讨论 Service 的插件化启动。按照本系列的尿性,肯定要简单易搞,所以预注册 Service 是本节的讨论前提。具体原因在 Activity 那节写了,但是需要额外说明的是其实 Service 由于量少且新增少,是比较少做复杂插件化方案的。

Android插件化笔记-5-ResModificationPlugin

Demo: https://github.com/2BAB/Android-Plugin-Dev-Notes

上节学习到「各插件构造各自的 Resource 对象,各个插件的资源互不影响」,本节使用另外一种方案——「所有插件的资源都加载到一个 AssetManager,全局可用」。

单一 Resource(AssetManager)的方案,主要问题在于资源 ID 冲突,解决的方案大体上分三种:

  1. 修改 AAPT 的源码
  2. 修改 AAPT 的生成产物(R.java,resource.arsc,各类 xml 包括 layout)
  3. 使用 public.xml 手动设置 padding

其中方案 1 出现的较早,原理也比较简单,修改的部分不多,携程的 DynamicApk 等开源项目都在使用。而方案 2 则鲜为人知,但是 Small 项目给我们做了一个完整的实例,本节的 Gradle 插件就是基于 Small 的源码「抽离 + 修改」而来。方案 3 不涉及到打包流程改动,在此不做阐释。

Android插件化笔记-4-LoadPluginResource

Demo: https://github.com/2BAB/Android-Plugin-Dev-Notes

插件化的资源加载大体上也分两种:

  • 每个插件构造单一的 Resource 对象,各个插件的资源互不影响
  • 所有插件的资源都加载到一个 AssetManager,全局可用,但是会出现资源 ID 冲突的现象,必须在打包流程中做修改

本节以构造单一对象为基础讲解,资源冲突的问题和方案下节讲。

资源的寻找过程

在Activity中的getResources()方法会走到ContextWrapper的实现上,而ContextWrapper顾名思义它只是一个包装类,最终的调用是ContextWrapper的实际类ContextImpl中的方法。

ContextImpl中getResources()方法返回了它的成员变量mResource,我们看一下ContextImpl的构造函数,其中mResources被第一次赋值是通过下面的函数调用:

1
Resources resources = packageInfo.getResources(mainThread);