升级 Android 目标版本到 31(S) 这么多坑

news/2025/1/3 4:07:38/

1

背景

最近对我的应用做了一些小的改动,准备上架 Google Play. 本以为小事一桩,没想到要做非常多的改动。其中一个改动是谷歌要求 billing 库升级到 4.0 及以上版本。此外,另一个比较大的改动是要求升级目标版本到 31.

我之前从 29 升级到 30 那次改动已经非常大了。这次应该不会太多改动,没想到总归还是 too young too simple, sometimes naive. 升级目标版本到 31 也不是那么简单。下面是谷歌官方提供的两个文章,分别详细列举了升级到版本的变更以及升级到 Android 12 的详细的变更:

符合 Google Play 的目标 API 级别要求

https://developer.android.com/google/play/requirements/target-sdk

行为变更:以 Android 12 为目标平台的应用

https://developer.android.com/about/versions/12/behavior-changes-12

谷歌官方已经给了详细的说明,这里我分享我在适配过程中遇到的问题和解决思路。

2

exported 属性

本次适配需要做的最明显的一个变更是修改 exported 属性。这个属性是之前就存在。我之前只在个别几个 Service 属性中使用了它。在 31 上开始要求开发者明确指定组件的 exported 属性。

对于没有声明 exported 属性的应用,在启动的过程中就会抛出如下异常:

对于 exported 属性,你可以查看谷歌官方文档的详细解释:android:exported。

https://developer.android.com/guide/topics/manifest/activity-element#exported

适配这个属性并不难,只需要在 manifest 中明确指定每个组件的 exported 属性即可。一般来说,遵循如下原则:如果组件中使用了 intent-filter 等属性,那么它大概率是需要对外暴露的,此时需要将 exported 属性值为 true,其他情况下置为 false 即可。

对于引用的三方类库中的 xml 属性也可以通过覆写声明方式增加 exported 以兼容处理,

 
<activity android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"android:exported="false"/>

3

PendingIntent 的变动

这是一个隐藏的变动,非常坑又不像 exported 属性那样容易被察觉。这边变动主要是要求开发者指定在创建 PendingIntent 的时候传入的 flags 参数的可变性。

这可以通过在之前的 flags 基础上增加 FLAG_MUTABLE 和 FLAG_IMMUTABLE 两个属性来完成。比如,之前我的 flags 是,PendingIntent.FLAG_CANCEL_CURRENT,当我想将其修改为不可变的时候,就可以使用如下方式进行修改:

 
val flags = PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE

它可能是需要改动最多的一个变动,根据我在项目中修改的情况来看,以下几个场景需要排查:

  • 桌面小控件 Appwidget

  • 通知 Notification

  • 桌面快捷方式 Shortcut

同时从几个方向来检索项目中需要改动的地方:

  • 直接检索 PendingIntent 的 flags 的调用,比如 FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT 和 FLAG_UPDATE_CURRENT 等,建议查看源码之后进行检索。

  • PendingIntent 的静态方法工厂,比如 PendingIntent.getBroadcast()、PendingIntent.getActivity() 等。因为,获取 PendingIntent 的时候需要指定 flags 参数。

那么,另一个问题来了,究竟什么时候该选择 FLAG_MUTABLE,什么时候该选择 FLAG_IMMUTABLE 呢?

它的注释是这么说的:

Flag indicating that the created PendingIntent should be immutable. This means that the additional intent argument passed to the send methods to fill in unpopulated properties of this intent will be ignored.
FLAG_IMMUTABLE only limits the ability to alter the semantics of the intent that is sent by send by the invoker of send. The creator of the PendingIntent can always update the PendingIntent itself via FLAG_UPDATE_CURRENT.

也就是说,FLAG_IMMUTABLE 的“不可变”指的是,当 PendingIntent 设置了 flags 为“不可变”之后,调用它的 send 方法时传入的 Intent 将会被忽略。

这里举一个具体的场景,比如在列表类的 Appwidget 里,我们会使用 PendingIntent 设置列表的某一项的点击事件。考虑到列表量比较大,为每一个列表条目都声明一个 PendingIntent 显然开销太大。所以,Android 的处理机制是:

 
val views = RemoteViews(context.packageName, R.layout.layout_appwidget_note_list)
val i = Intent(context, MainActivity::class.java)
i.action = ACTION_APPWIDGET_NOTE_CLICK
val pi = PendingIntent.getActivity(context, 0, i, FLAG_CANCEL_CURRENT_MUTABLE)
views.setPendingIntentTemplate(R.id.lv, pi)

如上所示,首先定一个一个 PendingIntent,并调用 RemoteViews 的 setPendingIntentTemplate 方法传入,作为一个模版。然后在 RemoteViewsFactory 的 getViewAt 方法中为每个列表项设置点击时的 Intent。

 
val row = RemoteViews(context.packageName, R.layout.item_appwidget_note)
val i = Intent().putExtras(extras)
row.setOnClickFillInIntent(R.id.root, i)

当用户触发了点击事件的时候,系统会在调用 PendingIntent 的 send 方法时将 Intent 传入并唤起组件。此时,如果我们将 PendingIntent 的 flags 设置为 FLAG_IMMUTABLE,那么这里发送时传入的 Intent 参数将被忽略,因此可能导致虽然唤起了其他组件,但是参数丢失的情况。而对于那种,声明 PendingIntent 时就传入了 Intent 的时候,一般来说不需要设置为 FLAG_MUTABLE 的。

以上是 PendingIntent 的改动,刚好在我的项目里两种情况都有遇到,所以详细分析了一下。

4

构建项目 JDK 需要升级

 当将项目的 targetSdkVersion 升级到了 31 之后,构建项目的时候可能会遇到如下异常:

当然你也可能不会遇到这个问题。那主要的原因是,你的 Android Studio 里 Gradle 构建时用到的版本已经是 Java 11 的了。可以通过 Preference->Build->Gradle 查看当前 Android Studio 中使用的 JDK 版本。

 

在 Gradle JDK 处修改构建时用的 JDK 版本即可。

以上是针对 Android Studio 构建时的情况。但当我们使用脚本或者命令行构建项目的时候需要用到的就不是 Android Studio 的 JDK 版本了。此时,可以通过 java --version 查看环境变量中配置的 JDK 版本。

 

我们不能直接修改环境变量中的 JDK 版本解决上述编译问题。因为毕竟除了开发,我们可能还有很多其他应用在使用 JDK 环境。此时,我们可以通过 Gradle 构建时的命令来指定构建时使用的 JDK。

 
gradlew -Dorg.gradle.java.home=你的 JDK 路径

对于打包脚本的修改我也更新到了项目 autopackage 中。

5

总结

以上是个人升级项目的目标版本到 31 过程中遇到的一些典型的问题。此外,在适配的过程中可能还有许多其他细节需要修改,对此,参考文首的几个链接了解即可。升级 31 虽然没有升级到 30 改动多,但是对大型的项目来说,需要改动的点应该还是挺多的。

转自:升级 Android 目标版本到 31(S) 这么多坑


http://www.ppmy.cn/news/935162.html

相关文章

钉钉机器人消息MarkDown下发送带色消息兼容手机APP

添加font标签, 设置颜色, 一定要使用\"包围色号, 否则手机不显示颜色, 不支持英文颜色如red, blue… 只支持pc变色 <font color#0000FF> Test Content </font>支持pc和app变色 <font color\"#0000FF\"> Test Content </font>

手打 小份 kubernetes v1.27.3 集群

文章目录 1. 准备2. yum3. 安装 ansible4. 互信5. hosts6. 关闭防火墙、swap、selinux7. 配置系统文件句柄数8. 启用ipvs9. 修改内核参数10. 安装 containerd11. 安装nerdctl12. kubernetes yum13. 部署 kubernetes13.1 安装工具13.2 初始化配置 14. 部署 master15. 部署 node1…

Mybatis-动态SQL - 学员管理系统plus

动态SQL和lombok <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><

诺基亚被中国联通选中驱动该公司在北京的4G和5G网络

【TechWeb】7月10日消息&#xff0c;据国外媒体报道&#xff0c;诺基亚今日表示&#xff0c;已被中国联通选中来驱动该公司在北京的4G和5G网络。 诺基亚表示&#xff0c;其光学前端解决方案&#xff08;optical fronthaul solution&#xff09;将帮助中国联通实现2019年的5G计划…

石家庄联通宽带DNS服务器地址

联通&#xff1a;202.99.160.68&#xff0c;备用地址为202.99.166.4。【鸣谢】https://zhidao.baidu.com/question/1837207117540628460.html 转载于:https://blog.51cto.com/8010597/2343566

广东联通打通全球首个5G手机电话

近日,广东联通联合中兴通讯在深圳5G规模测试外场,打通了全球第一个基于3GPP最新协议版本的5G手机外场通话(FirstCall), 率先在5G网络下畅享了微信、视频等精彩应用,对5G商用进程意义重大。 在中央经济工作会议精神鼓舞下,中国联通积极响应国家号召,加快5G建设步伐,以打造极致用…

《小康》:漫游费降价,一场数字游戏?

导读&#xff1a; 手机漫游费新标准的出台,意味着运营商进一步降低漫游费在政策上已没有阻碍;也预示着,一场消费者和运营商之间的新一轮博弈又将拉开帷幕. 历经十个月的调研、论证和听证之后,备受瞩目的手机漫游费上限调整方案最终尘埃落定,2月13日,信息产业部、国家发展和改革…

中国联通3G网络覆盖全国200余城市

截至目前&#xff0c;持有WCDMA牌照的中国联通3G网络已覆盖全国31个省区市、285个地市&#xff0c;预计年内将达到335个地市。 15日&#xff0c;由中国联通集团主办、山东联通承办的中国联通“沃3G”手机博览会暨“沃3G”高峰论坛在济南举行&#xff0c;诺基亚、三星、LG等15个…