看到标题就应该知道,这又是一篇 BUG 修复的复盘文章。这个 BUG 起源于 Google 程序员多年前埋的坑【FLAG_TEST_ONLY】,这是一个 API 级别 4 时候就存在的属性。这是一个没有存在感的属性,以至于十几年的时间内都没有引起多少人注意。直到 Android Studio 3.0 的发布,这个版本的 IDE 会在测试版 APK 的清单文件中自动注入 android:testOnly="true"
属性配置。如果清单文件中有这样的配置,那就意味着 APK 只能通过 adb 的方式安装。为了更加精准的了解这个属性的作用,我们还是看下官方文档是怎么描述的。
✦ 官方文档 | android:testOnly 指示此应用是否仅用于测试目的。例如,它可能会在自身之外公开功能或数据,这样会导致安全漏洞,但对测试很有用。此类 APK 只能通过 adb 安装,您不能将其发布到 Google Play。当您点击 Run 图标时,Android Studio 会自动添加此属性。
文档的描述简洁干练,提供的信息也乏善可陈。那么,应该怎么解决这个问题呢?通过考古,网上普遍流行两种方法:
编号 | 解决方法 |
---|---|
1 | 通过 Build -> Generate Signed Bundle / APK 生成签名文件 |
2 | 在 gradle.properties 中增加 android.injected.testOnly=false 配置 |
如果通过这两种方式就能解决应用安装失败的话,就不会有这篇文章了。下面,我们正式开始复盘问题的定位和解决过程。
1. 问题定位
像大多数人一样,我优先采用了文章开篇中提到的两种解决方法。下图是分别采用这两种方法后,反编译 APP 查看清单文件得到的结果,可以看到测试属性值依然被注入了。有人说,这又不会影响什么?那是没有意识到问题的严重性。这个 BUG 的可怕之处在于,如果你的签名包中包含这个属性的话,所有手机是禁止直接安装的。什么意思呢?这意味着即使你的 APP 发布到了应用市场,用户下载后也是无法安装的,大部分的手机都会提示安装失败。
文章开篇提到的解决方法在之前可能是生效的,但是这种解决方法可能忽略了一些前置条件,比如 Android Studio 的版本、AGP 的版本以及 targetSdkVersion 的版本。因为,这些前置条件直接决定了解决问题的方向。 这里有必要列出笔者的开发环境,为后续的问题查找做个铺垫,因为上述的解决方法不生效的原因就是下面的开发环境自身的缺陷导致的。
编号 | 编号 | 版本 |
---|---|---|
1 | Android Studio | Android Studio Electric Eel 2022.1.1 Patch 2 |
2 | AGP | 7.4.2 |
3 | targetSdkVersion | 33 |
笔者在上述环境下多次的尝试生成签名 APK 包后,清单文件中依然有测试属性被注入。最终确定了这应该是 Google 的一个 BUG,当我准备向 Issuetracker 提交 BUG 的时候,居然发现在 2 周前已经有开发人员提交了类似的 BUG,截图如下:
紧接着通过进一步的查找,又找到了一个 2022 年 5 月份提交的 Issue,在这个 Issue 中已经有人将原因指向了 android:testOnly="true"
。只是,当时还不确定测试属性的注入是不是将 API 级别指向 33 后的特有行为。最后,就是 2023 年 3 月 3 日的 Issue,这个 Issue 终于引起了 Google 程序员的注意,并和 Issue 的提出者展开了多轮测试。2023 年 3 月 8 日, Google 程序员确认了这个 BUG 并建议开发者将 AGP 的版本升级到 V8.1.0-alpha01 或更高的版本,同时搭配 android.injected.testOnly=false
使用,之后通过开发者的验证,测试属性的注入确实取消了。
编号 | 时间 | BUG描述 |
---|---|---|
1 | 2022-05-04 | adb install doesn’t work anymore for apps that target API 33 |
2 | 2023-03-03 | android.injected.testOnly=false does not work |
2. 解决方案
Google 程序员提出的解决方案其实漏掉了很多细节,还记得上文中笔者列出的开发环境吗?是的,那些环境都需要变更才能生效,因为他们是有版本匹配要求的,具体参见:Android Gradle 插件和 Android Studio 兼容性、Android Studio Giraffe 2022.3.1 Canary 9。完成如下表格中的环境变更后,重新生成签名包,这时会发现测试属性的注入被取消了。
编号 | 环境 | 解决方法 |
---|---|---|
1 | Android Studio | Android Studio Giraffe 2022.3.1 Canary 9 |
2 | AGP | 8.1.0-alpha09 |
3 | targetSdkVersion | 33 |
4 | gradle.properties | android.injected.testOnly=false |
5 | build.gradle | android 节点增加 android.buildFeatures.buildConfig true |
6 | build.gradle | compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } |