每年Google Play都会要求所有上架海外的App在8月(新包)及11月(在架包)进行新系统版本的适配,今年,我们苦逼的海外开发者又必须要适配Android 15了,晚干不如早干,近期我们也是将Android 15适配提上了日程!
以下Android 15 实战所遇问题,仅适用于阿文的项目,如果您所遇问题不同,欢迎留言或私信阿文一起讨论。
开始集成Android 15
阿文目前项目环境如下:
Java version :11.0.18
Android version :API 34, Android 14
Installation platform & version :Gradle 7.5
AGP :7.4.2
首先,我们将compileSdkVersion以及targetSdkVersion升级为35,开始Build
android {
compileSdkVersion 35
defaultConfig {
minSdkVersion 23
targetSdkVersion 35
}
}
不出意外,意外就来了。下面我们一一来看:
(1) 一堆啥也看不懂的报错,小白先盲猜是AGP问题,查文档,果然是!
官方环境要求:https://developer.android.com/build/releases/gradle-plugin?hl=zh-cn
如上图所示,我们需要下载Koala 功能更新 | 2024.2.1 以上版本 |AGP 最低版本8.6.0。
秉着不使用Google最新版本为主的理念(少踩坑),所以接下来我们升级AGP到8.6.0即可,可以通过Android Studio AGP Upgrade Assistant 进行升级,如下所示:
升级后AS会将清单文件的package主动移除,并在build.gradle文件中添加namespace属性,具体原因可看链接:https://discuss.gradle.org/t/namespace-not-specified-for-agp-8-0-0/45850。
同时gradle.properties文件新增3个属性。
android.defaults.buildfeatures.buildconfig=true (强制启用 BuildConfig 类的生成)
android.nonTransitiveRClass=false (启用传递性 R 类生成)
android.nonFinalResIds=false (将资源 ID 声明为 final)
gradle-wrapper文件中gradle版本会自动升级到8.9版本:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip。
(2) gradle 8.9 Kotlin 要求最低1.8+,我升级的的版本是1.8.10。官方文档:https://developer.android.com/build/kotlin-support?hl=zh-cn。
(3) 移除kotlin-android-extensions插件(在2020年开始弃用, kotlin1.8 正式移除),这次真心不能用了,相关代码需要更改。
(4) gradle 8.x需要使用jdk 17。
运行环境修改为jdk 17后依然提示项目错误,修改各个模块的gradle文件填加相关配置,指定源代码编译时遵循的 Java 版本语法规则(sourceCompatibility)以及指定生成的字节码(.class 文件)兼容的 Java 版本(targetCompatibility)可解决问题。
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
(5) kotlin升级后语法校验更严格,找到对应位置进行处理(例如when的表达式必须有else):
(6) android 35的 api 可能和之前的不太一样,需要进行对应修改(例如返回值可能由之前的不为空改为了可为null)
项目优化:升级底层库以及三方库
建议升级,以防不兼容问题,需要AGP8.6.0对应的最新的稳定版本,阿文直接帮大家列举了一些通用SDK的升级版本,不通用的以三方为主,在这不多列举!
适配edge to edge
Edge-to-Edge(全屏/沉浸式)设计是一种让应用内容扩展到设备屏幕边缘(包括状态栏、导航栏和通知栏)的 UI 设计风格。具体可参考郭霖大神的文章,介绍较详细,本文不再赘述:Android 15新特性,强制edge-to-edge全面屏体验 。
但是我们的页面部分需要保留状态栏以及导航栏,查询到官方提供了相关的api,所以相关适配步骤如下:
(1)移除我们沉浸式适配相关的所有代码
(2)参考上文郭霖大神的文档进行修改(文档中有一句话enableEdgeToEdge()是一个Kotlin的扩展函数,最早可以支持到Android 6.0的设备,但我们在5.0的机器上测试了也是可以正常的,大家可以自行测试一下)
(3) 如果原项目部分页面之前有设置adjustResize属性(确保输入框不会被软键盘遮挡),但做了全面屏适配后,这种方式就失效了,所以需要通过insets.isVisible(WindowInsetsCompat.Type.ime()) 获取软键盘高度后自行进行处理。
以下是Api的说明以及我的工具类,朋友们可以进行借鉴:
ViewCompat.setOnApplyWindowInsetsListener //系统 UI(如状态栏、导航栏、输入法键盘)显示或隐藏时,系统会触发 WindowInsets 事件
insets.getInsets(WindowInsetsCompat.Type.navigationBars() //获取导航栏
insets.getInsets(WindowInsetsCompat.Type.statusBars()) //获取状态栏
insets.isVisible(WindowInsetsCompat.Type.ime()) //获取软件盘
fun View.hasSafeDistanceNavigationBars(activity: Activity) {ViewCompat.setOnApplyWindowInsetsListener(
this
) { v, insets ->
val
navigationBars =
insets.getInsets(WindowInsetsCompat.Type.navigationBars())
val
isImeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
val
imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
if
(isImeVisible && activity
is
IAdjustResizePage) {
v.setPadding(
navigationBars.left,
navigationBars.top,
navigationBars.right,
imeHeight
)
}
else
{
v.setPadding(
navigationBars.left,
navigationBars.top,
navigationBars.right,
navigationBars.bottom
)
}
insets
}
}
fun
View.hasSafeDistanceStatusBars() {
ViewCompat.setOnApplyWindowInsetsListener(
this
) { v, insets ->
val
statusBars = insets.getInsets(WindowInsetsCompat.Type.statusBars())
v.setPadding(statusBars.left, statusBars.top, statusBars.right, statusBars.bottom)
insets
}
}
16kb内存页面适配
这个如果自己没有写NDK项目,一般由三方进行适配,篇幅原因,在此先不过多介绍,稍后单独总结一篇。
aabresguard资源混淆问题
项目中material库的版本在1.7.0时,使用aabresguard进行资源混淆后无法解析成apks(根本问题字节的aabresguard混淆插件aapt2版本过低导致)
所以解决方案有如下2种(建议使用第二种方案)
1.回退material库的版本在1.7.0以下
2.aabresguard资源混淆插件升级bundletool版本为1.18.1,这个需要自行下载源码修改下即可,不是很难!
结语
改到这里,基本就大功告成了。其他有关Android 15的行为变更,可参考官方文档:https://developer.android.com/about/versions/15/behavior-changes-all?hl=zh-cn ,有任何问题,欢迎在评论区留言讨论或通过下方公众号私信讨论。