今天傍晚,Google将幽灵调用的修复正式合入到R8的诸多版本中,App终于可以用起来了。下面我简单介绍下,再讲下如何在App中快速应用。
整体情况
Google已将修复合入到以下几个R8版本中,注意,是R8版本,而非AGP(Android Gradle Plugin)版本:
- 8.10.36
- 8.11.28
- 8.12.24
- 8.13.10
- 9.0.11-dev
对于R8 8.x系列,它们通常会随着 AGP的迭代进入正式版本。举个例子:AGP 目前最新版本是 8.13,未来如果继续发 8.13.1、8.13.2 等小版本,就有可能包含这次 R8 的修复。但也不排除某个大版本只发一次,如果没有新迭代,那这个 AGP 分支就不会带上修复。
而对于即将在下半年发布的 AGP 9.0,Google明确提到会包含此次修复。
当下的解决方案
未来版本什么时候发布我们无法完全确定,那现在该怎么办?
答案是:通过替换 R8 的方式来立即应用修复 。Google 官方提供了操作方法:r8.googlesource.com/r8/#replaci...
To override the embedded version with a prebuilt R8 with version , merge the following into the top level settings.gradle or settings.gradle.kts:
scss
pluginManagement {
buildscript {
repositories {
mavenCentral()
maven {
url = uri("https://storage.googleapis.com/r8-releases/raw")
}
}
dependencies {
classpath("com.android.tools:r8:<version>")
}
}
}
核心思路很简单:
- Google 已经把这些修复过的 R8 版本存档在仓库:storage.googleapis.com/r8-releases...
- 我们只需要在构建脚本里指定这个仓库,并在 classpath 中写入需要的 R8 版本号,就能让 AGP 使用我们指定的 R8,自然也就包含了修复。
实测验证
我在本地项目里亲测了一遍,配置如下:
arduino
classpath "com.android.tools:r8:8.10.36"
然后打开 minifyEnabled,编译生成 release APK,并对其中的 classes.dex 执行:
dexdump -d classes.dex
结果显示:
sql
09a198: |[09a198] com.xxx.testdedupe.MyViewA.onDetachedFromWindow:()V
09a1a8: 6f10 540b 0100 |0000: invoke-super {v1}, Landroid/view/View;.onDetachedFromWindow:()V // method@0b54
09a1ae: 6300 0000 |0003: sget-boolean v0, LA/c;.a:Z // field@0000
09a1b2: 3800 0900 |0005: if-eqz v0, 000e // +0009
09a1b6: 6e10 c80a 0100 |0007: invoke-virtual {v1}, Landroid/view/View;.getAlpha:()F // method@0ac8
09a1bc: 0a00 |000a: move-result v0
09a1be: 6e20 900b 0100 |000b: invoke-virtual {v1, v0}, Landroid/view/View;.setAlpha:(F)V // method@0b90
09a1c4: 0e00 |000e: return-void
sql
09a1fc: |[09a1fc] com.xxx.testdedupe.MyViewB.onDetachedFromWindow:()V
09a20c: 6f10 540b 0100 |0000: invoke-super {v1}, Landroid/view/View;.onDetachedFromWindow:()V // method@0b54
09a212: 6300 0000 |0003: sget-boolean v0, LA/c;.a:Z // field@0000
09a216: 3800 0900 |0005: if-eqz v0, 000e // +0009
09a21a: 6e10 c80a 0100 |0007: invoke-virtual {v1}, Landroid/view/View;.getAlpha:()F // method@0ac8
09a220: 0a00 |000a: move-result v0
09a222: 6e20 900b 0100 |000b: invoke-virtual {v1, v0}, Landroid/view/View;.setAlpha:(F)V // method@0b90
09a228: 0e00 |000e: return-void
虽然字节码内容完全一样,但因为有invoke-super
指令,所以无法复用,字节码地址不同表明了这一点。
这就说明修复生效,幽灵调用的问题彻底解决。