DIY 24 寸的 4K 显示器

这两天苹果上架了新款的 23.8 寸 LG UltraFine 4K 显示器,看了下边框还是那么的粗,Hmmm 还是桌上的这台自制 4K 显示器舒服。正好有朋友也想试试,于是想到记录一下折腾的过程,虽然大部分的工作量都是朋友 @Can 帮忙完成的哈哈。

合并两个 Repo

手头的项目之前是拆分成两个 repo 进行维护的,这里称之为 A 和 B 好了。B 是一个公共的基础代码库,设计之初被多个项目进行引用。随着几个项目的共同迭代,可共享的代码块越来越少,B 的维护从一个分支变成了每个项目一个分支。接手这个项目后觉得这个维护模式太复杂了,于是连同其他项目把 B 上自己的分支迁移走,彻底废弃 B repo。

博客迁移@2019

Hmmm 有很长一段时间没有更新博客了,一方面是确实懒,只有私底下还持续在写的一些 Gradle 的文章,但打算做成一个完整的知识图谱所以还没发出来;另一方面老的博客系统确实有点麻烦,有时候不在自己的电脑上就没办法写东西了。所以能不能我用个浏览器就能写文章,就成为了此次的目标啦。

插件化笔记#8 - 插件的代码编译

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

背景

为什么打包还要讲?因为我发现大家都没说过这回事啊…而且有些开源的插件化框架并没有看到有仔细处理这块,导致自己研究的时候很困惑。具体来说,打包这块也是分两块,插件代码和插件资源的打包,这节先看插件代码的打包。

一般地,我们的插件,和普通的 Android Library 不同,是直接声明成 Application。因为只有这样,才能简单地借助原有的(Application)打包插件来打出 Dex 和资源编译。而打包 Application,对于插件而言,会打入很多不必要的二方、三方依赖。有人会说,用 provided 声明插件模块的依赖不就好了,但这仅仅只能是解决 .jar 的模块,.aar 的依赖是不支持 provided 的。所以我们要解决的问题,也就很明显了,实现一个通用的打包仲裁:

插件化笔记#7 - MultiClassloader

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

为什么要有 Multi Classloader

如上篇所说,我们不管要起 Activity、Service,其实都是需要注入自定义的 Classloader。而 Service 没有一个很好的简单注入点,所以才有了 Hook 上层 Classloader 的方案。这种方案有两种,都是解决多 Dex 加载的情况(不管插件化与否其实只要方法数超 65535 都是需要做多 Dex 加载):

  1. 单一 Classloader:就是上篇说到的 MultiDex 使用的反射注入 DexPathList 的前部,这种是利用了 BaseDexClassloader 的 findClass 特性,由前往后查找 Dex 文件并加载 Class;
  2. 多 Classloader:利用双亲委派的 Classloader 机制,使得我们的 Classloader 可以优先于系统 Classloader 查找到 Class 并返回,通常会伴随着每个模块一个 Classloader,再由一个 HookClassloader 统一 Dispatch;

Gradle 日常崩#7 - debuggable 属性无效

问题回顾

不久前,在接手手头上这个老工程时,发现 build.gradle 中设置 debuggable 属性是无效的,只能手动在 AndroidManifest.xmlapplication 节点写死该属性(之前团队里就这样默默干了两年,发版前去掉这个属性,发版后再加上…),最近得空花了两三个周末研究了下缘由。

默认看此文章的人已经知道这点:

Android 系统判断一个 App 是否可 Debug 的标准是,AndroidManifest.xml 中的 application 节点是否存在 debuggable 属性,并且其值为 true。(可参考官方文档

Gradle 日常崩#6 - JDK 内的某个包失踪了

最近在改一个之前的 Annotation Processor,想要实现一个这样的需求:对一个 Class 所 implement 的 interface 做判断——这些 interface 是否 extends 自一个统一的父 Interface。于是 Debug + Evaluate Expression 挖一下 TypeElement 的实例里都有些啥,看看有没好使的 API。

Gradle 日常崩#5 - 含 buildscript 的脚本执行顺序

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

// 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 日常崩#4 - aar 的 tools:replace 冲突

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

AndroidManifest.xml:22:9-40 Error: Attribute [email protected] 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 把这个视为冲突抛了出来。