Android 支持库迁移到AndroidX,详细的Android学习指南

at com.android.tools.build.jetifier.processor.archive.Archive.accept(Archive.kt:66)
at com.android.tools.build.jetifier.processor.Processor.visit(Processor.kt:316)
at com.android.tools.build.jetifier.processor.archive.Archive.accept(Archive.kt:66)
at com.android.tools.build.jetifier.processor.Processor.transformLibrary(Processor.kt:312)
at com.android.tools.build.jetifier.processor.Processor.transform(Processor.kt:175)
at com.android.build.gradle.internal.dependency.JetifyTransform.transform(JetifyTransform.kt:199)
… 39 more

我们发现,JetifyTransform内部使用了ASM,在对aar进行ClassReader的过程中抛出了异常。并且从错误栈信息上看,应该有一类叫jetifier的工具,是在这个工具中调用的ASM操作。

官方文档搜索下,果然发现了jetifier的踪迹。
developer.android.com/studio/comm…

同样的,Google Source上也找到了其对应的实现。
android.googlesource.com/platform/fr…

下载对应的jetifier-standalone,解压后,执行命令对fingerprint-1.1.1.aar执行AndroidX转化。

➜ bin ./jetifier-standalone -i ./fingerprint-1.1.1.aar -o 11.aar
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 8
at org.objectweb.asm.ClassReader.readFrameType(ClassReader.java:2313)
at org.objectweb.asm.ClassReader.readFrame(ClassReader.java:2269)
at org.objectweb.asm.ClassReader.readCode(ClassReader.java:1448)
at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1126)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:698)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:500)
at com.android.tools.build.jetifier.processor.transform.bytecode.ByteCodeTransformer.runTransform(ByteCodeTransformer.kt:40)
at com.android.tools.build.jetifier.processor.Processor.visit(Processor.kt:539)
at com.android.tools.build.jetifier.processor.archive.ArchiveFile.accept(ArchiveFile.kt:53)
at com.android.tools.build.jetifier.processor.Processor.visit(Processor.kt:521)
at com.android.tools.build.jetifier.processor.archive.Archive.accept(Archive.kt:76)
at com.android.tools.build.jetifier.processor.Processor.visit(Processor.kt:521)
at com.android.tools.build.jetifier.processor.archive.Archive.accept(Archive.kt:76)
at com.android.tools.build.jetifier.processor.Processor.transformLibrary(Processor.kt:517)
at com.android.tools.build.jetifier.processor.Processor.transform2(Processor.kt:291)
at com.android.tools.build.jetifier.processor.Processor.transform2 d e f a u l t ( P r o c e s s o r . k t : 251 ) a t c o m . a n d r o i d . t o o l s . b u i l d . j e t i f i e r . s t a n d a l o n e . M a i n . r u n ( M a i n . k t : 156 ) a t c o m . a n d r o i d . t o o l s . b u i l d . j e t i f i e r . s t a n d a l o n e . M a i n default(Processor.kt:251) at com.android.tools.build.jetifier.standalone.Main.run(Main.kt:156) at com.android.tools.build.jetifier.standalone.Main default(Processor.kt:251)atcom.android.tools.build.jetifier.standalone.Main.run(Main.kt:156)atcom.android.tools.build.jetifier.standalone.MainCompanion.main(Main.kt:109)
at com.android.tools.build.jetifier.standalone.Main.main(Main.kt)

发现出现了同样的错误信息。

显然,应该是fingerprint-1.1.1.aar中有字节码有问题。经查,fingerprint内部直接以jar方式引入了三星的指纹识别库,已经很比较老的版本了,经业务同学确认,现在已经可以直接去除。

去除fingerprint内部的三星指纹库后,升级版本,下载对应的aar文件后,再次尝试转化:

./jetifier-standalone -i ./fingerprint-1.1.3-20190916.092208-1.aar -o mm.aar

执行成功,且有转换后的对应文件生成。

主工程更新fingerprint对应依赖版本后,重新执行构建,出现错误提示:

e: /Users/corn/AndroidStudioProjects/MyCorn/base/src/main/java/com/mycorn/base/mvvm/EventLiveData.kt: (13, 5): ‘observe’ overrides nothing
e: /Users/corn/AndroidStudioProjects/MyCorn/base/src/main/java/com/mycorn/base/mvvm/EventLiveData.kt: (20, 5): ‘removeObserver’ overrides nothing

原因在于对应的LiveData接口observe、removeObserver中的形参有所改动,从原来的

@NonNull Observer observer

变成了

@NonNull Observer<? super T> observer

修正EventLiveData类中的重写方法的对应形参,与接口保持一致即可。

再次重新构建,出现错误信息:

/Users/corn/AndroidStudioProjects/MyCorn/trans/src/main/java/com/mycorn/biz/supertrans/v12/slide/ItemSlideHelper.java:566: 错误: 程序包androidx.appcompat.recyclerview.R不存在
.getDimension(androidx.appcompat.recyclerview.R.dimen.item_touch_helper_swipe_escape_velocity);

/Users/corn/AndroidStudioProjects/MyCorn/trans/src/main/java/com/mycorn/biz/supertrans/v12/slide/ItemSlideHelper.java:568: 错误: 程序包androidx.appcompat.recyclerview.R不存在
.getDimension(androidx.appcompat.recyclerview.R.dimen.item_touch_helper_swipe_escape_max_velocity);

/Users/corn/AndroidStudioProjects/MyCorn/trans/src/main/java/com/mycorn/biz/supertrans/v12/slide/ItemSlideHelper.java:2115: 错误: 程序包androidx.appcompat.recyclerview.R不存在
androidx.appcompat.recyclerview.R.dimen.item_touch_helper_max_drag_scroll_per_frame);

核查官方文档,对应的替换关系应该是:

ndroid.support.v7.recyclerview.R

替换为

androidx.recyclerview.R

此处替换成了

androidx.appcompat.recyclerview.R

按照文档对应修正过来。

再次重新构建,可以构建成功。

3.4 核验与发现

此时构建成功,是不是就真的都处理好了呢,是不是都没问题了呢。显然不是的。

首先,分别查看主工程对应的编译时和运行时依赖,看看是否都从android.support.* 替换成了androidx.*

./gradlew -q MyCorn:dependencies --configuration devDebugAndroidTestCompileClasspath > ~/compile.txt

./gradlew -q MyCorn:dependencies --configuration devDebugAndroidTestRuntimeClasspath > ~/runtime.txt

仔细对比后发现,虽然依赖中都已经被替换成了androidx.* 。但编译时的依赖中含有大量的rc01。如:

androidx.appcompat:appcompat:1.0.0-rc01
androidx.recyclerview:recyclerview:1.0.0-rc01

但运行时依赖中却没有rc01

androidx.appcompat:appcompat:1.0.0
androidx.recyclerview:recyclerview:1.0.0

经核查后发现,主工程中之前依赖支持库时有两种写法,一种是直接写法,如:

implementation 'com.android.support:appcompat-v7:28.0.0

另一种是采取统一定义后,进行的变量形式引入:

api rootProject.ext.dependencies[“appcompat-v7”]

其中,具体变量,如appcompat-v7被统一定义在了专用的一个dependencies.gradle文件中。
大致形式如下:

// 统一配置管理
def supportVersion = “28.0.0”

project.ext {
android = [
“compileSdkVersion”: 28,
“minSdkVersion” : 19,
“targetSdkVersion” : 26,
“javaMaxHeapSize” : “5G”
]

dependencies = [
“support-compat” : “com.android.support:support-compat: s u p p o r t V e r s i o n " , " s u p p o r t − c o r e − u t i l s " : " c o m . a n d r o i d . s u p p o r t : s u p p o r t − c o r e − u t i l s : {supportVersion}", "support-core-utils" : "com.android.support:support-core-utils: supportVersion","supportcoreutils":"com.android.support:supportcoreutils:{supportVersion}”,
“support-core-ui” : “com.android.support:support-core-ui: s u p p o r t V e r s i o n " , " s u p p o r t − m e d i a − c o m p a t " : " c o m . a n d r o i d . s u p p o r t : s u p p o r t − m e d i a − c o m p a t : {supportVersion}", "support-media-compat": "com.android.support:support-media-compat: supportVersion","supportmediacompat":"com.android.support:supportmediacompat:{supportVersion}”,
“support-fragment” : “com.android.support:support-fragment: s u p p o r t V e r s i o n " , " s u p p o r t − a n n o t a t i o n s " : " c o m . a n d r o i d . s u p p o r t : s u p p o r t − a n n o t a t i o n s : {supportVersion}", "support-annotations" : "com.android.support:support-annotations: supportVersion","supportannotations":"com.android.support:supportannotations:{supportVersion}”,
“appcompat-v7” : “com.android.support:appcompat-v7:${supportVersion}”,


]
}

来到对应的文件,发现对应的android.support.*并没有被替换成androidx.*

而在build.gralde中直接引入的写法,是被相应替换了的。已经被正确替换成了:

implementation ‘androidx.appcompat:appcompat:1.0.0’

也就是说,构建时,遇到api rootProject.ext.dependencies["appcompat-v7"],其实是没有被准确识别的,按照编译时的依赖关系,最终被识别成了带有rc01的AndroidX版本。

于是,才出现了编译时和运行时大量的版本不一致情况。

解决起来很简单,直接在dependencies.gradle文件中,将android.support.*对应人为替换成androidx.*形式,并重新规范命名和版本,相应修正对应的被使用到的地方,并修正成统一的AndroidX依赖写法。

// 统一配置管理
def androidXVersion = “1.0.0”

project.ext {
android = [
“compileSdkVersion”: 28,
“minSdkVersion” : 19,
“targetSdkVersion” : 26,
“javaMaxHeapSize” : “5G”
]

dependencies = [
“androidx-core” : “androidx.core:core: a n d r o i d X V e r s i o n " , " a n d r o i d x − c o r e − u t i l s " : " a n d r o i d x . l e g a c y : l e g a c y − s u p p o r t − c o r e − u t i l s : {androidXVersion}", "androidx-core-utils" : "androidx.legacy:legacy-support-core-utils: androidXVersion","androidxcoreutils":"androidx.legacy:legacysupportcoreutils:{androidXVersion}”,
“androidx-core-ui” : “androidx.legacy:legacy-support-core-ui: a n d r o i d X V e r s i o n " , " a n d r o i d x − m e d i a " : " a n d r o i d x . m e d i a : m e d i a : {androidXVersion}", "androidx-media" : "androidx.media:media: androidXVersion","androidxmedia":"androidx.media:media:{androidXVersion}”,
“androidx-fragment” : “androidx.fragment:fragment: a n d r o i d X V e r s i o n " , " s u p p o r t − a n n o t a t i o n s " : " a n d r o i d x . a n n o t a t i o n : a n n o t a t i o n : {androidXVersion}", "support-annotations" : "androidx.annotation:annotation: androidXVersion","supportannotations":"androidx.annotation:annotation:{androidXVersion}”,
“androidx-appcompat” : “androidx.appcompat:appcompat:${androidXVersion}”,


]
}

重新输出编译时和运行时依赖,发现此时支持库版本已经一致。

重新构建项目,发现可以构建成功。

但到此时,我们依然有四个问题需要进一步确认:
1,主工程中是否有支持库相关的一些特别的写法,结果会跟上面的dependencies.gradle一样,不能被自动识别并迁移?例如反射?字符串?甚至字符串拼接?等等。

2,原有依赖库android.support.*肯定会有一些混淆配置,现在迁移成androidx.*后,混淆配置这块如何对应处理?

3,自动迁移时,依赖库与主工程其实是不一样的技术原理。显然,主工程采用的是对源文件的相应替换,而依赖库已经是编译后的class等二进制文件,采用的是ASM字节码操作,那是否也还存在一些不能被ASM操作的特殊情况?例如反射?字符串?甚至字符串拼接?等等。

4,对整个工程而言,如何进一步确认整体迁移确实已经成功?

第一个问题其实比较好处理,主工程直接全局搜索如android.support关键字,对搜索结果一一甄别,对应处理即可。最终主要发现的可疑问题有两处:

<provider
android:name=“androidx.core.content.FileProvider”

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

img
img

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip204888 备注Android获取(资料价值较高,非无偿)
img

总结:

各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

  • BAT大厂面试题、独家面试工具包,

  • 资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter

总结:

各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

  • BAT大厂面试题、独家面试工具包,

  • 资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter
    [外链图片转存中…(img-OCn9KM9M-1711544169719)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值