升级targetSDK为33后的十来个坑

一. 事件背景

若是有和我一样, 要上线Google Play Store的同学, 那你们也应该知道, Google现在要求: "在8月31号之前, targetSDK要升为33"

政策改变

以前的政策是:

  • 新app, 要求8月31号之前, targetSDK升级到X
  • 老app, 要求11月1号之前, targetSDK升级到X

现在的政策则变了, 对于新或老app, 全都一视同仁, 要求在8月31号之前, targetSDK要升到某一版本号. 而且时间就是每年的8月31号了.

因此, 我本来计划是9月进行的升级targetSDK工作, 提前到了7月底开始进行. 也因此碰到了多个坑, 血淋淋的坑, 填这些坑花了两三天时间. 下面分享出来, 毕竟离8月底的deadline已经很近了, 希望本文对有需要的同学有所帮助.

二. 升级targetSDK 33

升级targetSDK蛮容易的, 就是去 app/build.gradle中把compileSDK, targetSDK全升成33就行了.

但其实的工作却要多一些, 要去Android 13 features and chagnes list官网上看各种新加的东西. 比如新加了POST_NOTIFICATION, 我们app就要动态处理, 不然notification根本不会出来 (当然也不会crash啦); ...

网上关于升级targetSDK到33, 要注意哪些 (如新权限, 新功能, 现有功能的变化), 文章有不少的. 我就不写重复写了. 下面的因为升级targetSDK引发的各种连锁反应是网上少有文章涉及的, 所以才是我这文章的重点

三. 升级targetSDK引发的开发工具出现问题

3.1 Android Studio (下文简称AS)

背景

因为讨厌新的logcat格式, 所以我一直呆在android studio bumblebee, 一直都没有升级Android Studio.

问题

升级了targetSDK后, 我发现很多功能没有了. 比如说我新建个xml, 然后在里面输入"id", 一般来说, 是有这样的提示的:

或是输入layout_width后, 有可选值的提示:

现在这些智能提示通通没了. 找了一些资料, 才发现, 是说targetSDK升级了的原因.

于是我把targetSDK从刚升级到的33, 回滚到原来的31. 果然, 上面这些智能提示全有了.

解决

这下破案了: targetSDK升级导致我的Android Studio BumbleBee不再支持一些功能.

所以若想有更好的开发体验, 我要么降级targetSDK (这一点肯定不行, 因为google不让), 要么就是升级Android Studio.

查看了下AS官网, 发现现在的稳定版已经出到了'长颈鹿'了, 也就是AS Giraffe. 本着'不想每年都折腾这么一下'的想法, 就直接升到最新的稳定版吧. 于是我就下载了AS Giraffe, 并安装成功.

后续

于是潘多拉魔盒打开了, 各种问题接踵而来.

3.2 Android Gradle Plugin (下文简称AGP)

AS的官网上其实已经写明: 升级了AS, 那AGP也要升级! 它们二者的对应关系如下:

我原来的AGP版本是4.1, 现在也本着索性就升到最新稳定版的思想, 我就想升到Giraffe支持的最高版本, 也就是AGP 8.1.

手动升级AGP是比较累的, 因为要改的东西很多, 还涉及到从4.1到8.1这么多个版本, 所以手动升级是不可能手动升级的, 这辈子都不可能手动升级的. AS里工具这么多, 说话又好听, 肯定要用AS的工具啊.

工具就在这里: Tools -> AGP Upgrade Assistant...

点开来后, 你可以选择, 从当前AGP版本, 升级到哪个版本. 然后点击"Run selected steps"即能自动完成升级了:

升级成功后样子如下:

再看下Git变动记录, 你就知道, 有manifest文件被改动了, 还有多个gradle文件改了. 这要是自己手动来升级AGP怕要累死, 所以还是工具好

现在的根目录下的build.gradle已经是这样的了:

gradle 复制代码
plugins {  
  // AGP版本
  id 'com.android.application' version '8.1.0' apply false  
  id 'com.android.library' version '8.1.0' apply false  
  // Kotlin版本 (没变)
  id 'org.jetbrains.kotlin.android' version '1.5.31' apply false  
}

备注: 若有同学对AGP升级了, kotin版本是否要升级有疑问, 请放心, AGP与kotlin二者不相关, 互相独立. 所以升级了AGP, 你的kotlin仍可以呆在1.5 或 1.6 .

-- 说这一点, 是因为应该有不少同学还在用kotlin-android-extensions吧, 这个在kotlin 1.8被remove了. 所以你要是升级到了kotlin 1.8, 那就得对项目进行大幅修改, 全面用findViewById或是ViewBinding了. 这个kotlin的版本问题, 后面会再讲, 不用担心

JDK变化

要是你碰到什么android LintModelSeveirty requires Java 61, the current is 55的问题, 那说明你的JDK不行.

JDK的内部版本如下:

java 复制代码
49 = Java 5 ; 50 = Java 6 ; 51 = Java 7 ; 52 = Java 8
53 = Java 9 ; 54 = Java 10
55 = Java 11 ; 56 = Java 12 ; 57 = Java 13 ; 58 = Java 14; 59 = Java 15 ; 60 = Java 16
61 = Java 17 ; 62 = Java 18 ; 63 = Java 19 ; 64 = Java 20

所以这个错误就是说, 你用的是JDK 11, 但需要使用JDK 17才行.

原因

原因是以前用JDK 11就行, 但自从AGP 8.1开始, 就需要使用JDK 17 (如下图所示).

解决

要是你下载了新AS, 那直接使用AS内置的JDK就行. 你可以在AS里这样设置, 在Settings -> Build, Execution, Deployment -> Buiild Tools -> Gradle -> 右侧 Gradke JDK里选中jbr-17即可 (图中的jbr是指jetbrains runtime的意思啦)

3.3 修复各种AGP升级引发的问题

升级了AGP后, 就引发各种牛鬼蛇神, 下面我就一一简略地说一下如何解决它们.

java.util.Set错误

Stackoverflow上的说明, 升级google play service即可

Apple Chip问题

要是你用的是Mac的M1, M2芯片, 那你的ROOM可能会在升级后build失败

解法有多种:

1). 要么升级ROOM到2.4.0以上

2). 要么不用AS自带的JDK 17, 而去Open JDK中下载一个JDK 17, gradle去用这个Open JDK 17

3). 要么就在gradle的依赖里加一句kapt "org.xerial:sqlite-jdbc:3.34.0"

这三种方法都可以. 第一种方法就是还要变化一些代码, 因为ROOM的api有点变化. 另外两种方法更简单些.

3.4 升级Kotlin与Androidx包

升级Kotlin

应该有不少同学还在使用kotlin-android-extensions这个插件吧, 只要用id就能得到一个view, 很方便的 但是这个插件在Kotlin 1.8中被彻底删除了. 所以现在还不想大规模修复这个问题, 就得保证你的kotlin在1.8版本之下. 比如说: 在1.8之下最高的版本, 即1.7.22

改kotlin版本还是蛮容易的, 去根目录下的build.gradle里修改

gradle 复制代码
plugins {  
  // AGP版本
  id 'com.android.application' version '8.1.0' apply false  
  id 'com.android.library' version '8.1.0' apply false  
  // Kotlin版本 (升级了)
  id 'org.jetbrains.kotlin.android' version '1.7.22' apply false   //原来是1.5.31
}

升级后会有一些kt文件有些问题, 但这些都是null与non-null的小问题, 修复起来不难.

升级androidx

androidx的几个关键包, 如core-ktx, appcompat, activity, fragment, lifecycle都是和targetSDK或kotlin版本绑定得很死的. 你要是用了不对的版本, 那就会因为和kotlin不匹配而编译失败.

经过我一一试错, 发现下面的版本是最适合targetSDK = 33的, 再高就要编译失败了:

groovy 复制代码
    // core-ktx 1.9.0与Android 13 (API 33)更兼容;  版本再高如1.10.0就编译出错, 因为它需要kotlin 1.8版本
    implementation 'androidx.core:core-ktx:1.9.0'
    //targetSDK = 33后, 可以从1.4.1升到最新的1.6.1
    implementation 'androidx.appcompat:appcompat:1.6.1'
    // targetSDK = 33后, 从1.6.0可升到最新的1.9.0.    // 再也没这个编译错误了: "Can't determine type for tag '<macro name="m3_comp_assist_chip_container_shape">?attr/shapeAppearanceCornerSmall</macro>'"
    implementation 'com.google.android.material:material:1.9.0'

    // targetSDK = 33后, 版本不能是最新的1.7.1与1.6.0, 不然会因为kotlin-stdlib要使用1.8而编译不能
    implementation "androidx.activity:activity-ktx:1.5.0"
    implementation "androidx.fragment:fragment-ktx:1.5.0"

    // targetSDK = 33后, 不能高到2.6去, 不然会因为kotlin-stdlib要使用1.8而编译不能
    def lifecycle_version = "2.5.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

小细节

另外请注意, 若你以前用了lifecycle-extensions包, 那现在这个包没了 这个lifecycle-extensions包里的内容分散到了独立的更小的包里了, 如以前在lifecycle-extensions包里的ProcessLifecycleOwner类, 现在已经在 implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"包里了.

3.5 CircleCI新问题

打debug包失败

经过上面几步, 我在本地打debug包都没问题了. 但到了CI/CD上 (我们公司用的是CircleCI), 结果出现打包失败

查了好久, 发现网上说的

1). 设置executor

yaml 复制代码
executors:
  java17:
    docker:
      - image: 'cimg/openjdk:17.0'

2). 自己下载jdk 17

yaml 复制代码
steps:  
    - checkout  
    - run:  
        name: Install OpenJDK 17  
        command: |  
            sudo apt-get update && sudo apt-get install openjdk-17-jdk  
            sudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java  
            sudo update-alternatives --set javac /usr/lib/jvm/java-17-openjdk-amd64/bin/javac  
            java -version

这两个方法全都没用, 不能解决"不能打包"的问题

接着查, 才知道原来CircleCI的docker镜像是有设置JAVA_HOME的, 如android:2023.07中就使用了JDK17的JAVA_HOME环境变量的.

所以解决办法就是就是升级android image:

结果就是经过了上面的修复后, build debug apk成功!

打release包失败

但后来又发现, 打release包竟然又失败了. 好在这次的失败, AGP帮我们搞出了原因:

arduino 复制代码
> Task :app:minifyStagingReleaseWithR8  
> ERROR: Missing classes detected while running R8.  
   Please add the missing classes or apply additional keep rules  
   that are generated in /home/circleci/repo/xxx/build/xxx/mapping/stagingRelease/missing_rules.txt.  
> ERROR: R8: Missing class com.abc.camera.hardware.VersionInterval  
   (referenced from: com.abc.hardware.Version com.abc.internal.DeviceInfo.mEglVersions and 4 other contexts)

这下AGP帮我们指出了哪些新规则需要添加, 我们把这个missing_rules.txt文件中的内容, 添加到自己项目里的proguard-rules.pro文件中就行了.

bash 复制代码
# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
-dontwarn com.abc.hardware.VersionInterval
-dontwarn com.abc.internal.DeviceInfo.mEglVersions
-dontwarn com.abc.internal.client.ClientCallback

果然, 现在打release包也成功了

四. 总结

原来以为简单的升级targetSDK, 结果发现连带着还要把AS, AGP, JDK, Kotlin, Androidx, Google Play Service, ...这些东东一一升级一下. 而且还碰到了好多稀奇古怪的错误, 跟我们代码无关的错误, 整个的修复过程还是很累人的.

希望我踩过并填了的坑的经验, 能帮到更多的人吧, 毕竟8月31号就要到了, 要升级的怕是时间也不多了.

相关推荐
吃着火锅x唱着歌1 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
_Shirley2 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
hedalei4 小时前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576
锋风Fengfeng4 小时前
安卓多渠道apk配置不同签名
android
枫_feng4 小时前
AOSP开发环境配置
android·安卓
叶羽西5 小时前
Android Studio打开一个外部的Android app程序
android·ide·android studio
qq_171538856 小时前
利用Spring Cloud Gateway Predicate优化微服务路由策略
android·javascript·微服务
Vincent(朱志强)8 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式
mmsx8 小时前
android 登录界面编写
android·登录界面
姜毛毛-JYM8 小时前
【JetPack】Navigation知识点总结
android