AndroidX 对原始 Android 支持库进行了重大改进。 与支持库一样,AndroidX 与 Android 操作系统分开提供, 并与各个 Android 版本向后兼容。 AndroidX 完全取代了支持库,不仅提供同等的功能, 而且提供了新的库。此外,AndroidX 还包括以下功能:
AndroidX 中的所有软件包都使用一致的命名空间,以字符串 androidx 开头。 支持库软件包已映射到对应的 androidx.* 软件包。 有关所有旧类到新类以及旧编译工件到新编译工件的完整映射,请参阅软件包重构页面。
与支持库不同,AndroidX 软件包会单独维护和更新。 androidx 软件包使用严格的语义版本控制,从版本 1.0.0 开始。 您可以单独更新项目中的 AndroidX 库。
所有新支持库的开发工作都将在 AndroidX 库中进行。 这包括维护原始支持库工件和引入新的 Jetpack 组件。
对应官方文档:
[developer.android.com/jetpack/and…]( )
简单点说就是,对App开发者而言,AndroidX更加友好,因为我们引入时,只需要关注AndroidX中具体的需要引入的构件版本即可。且大部分具体的构件,具有一致的版本号。开发者使用起来不再需要关注项目自身的最低支持版本和编译版本了,只需要像引入其他的第三方库一样,v1.0、v2.0、v3.0这种方式引入即可。
如原有的引入写法
`com.android.support:recyclerview-v7:28.0.0`
变成了
`androidx.recyclerview:recyclerview:1.0.0`
官方文档也提供了Androidx版本具体的升级日志记录。
[developer.android.com/jetpack/and…]( ) [developer.android.com/jetpack/and…]( )
三、支持库迁移到AndroidX
----------------
### 3.1 迁移AndroidX的必要性
AndroidX对开发者使用更加友好,同时,支持库文档上官方已经明确支持库后续不再维护。另外,在Android Studio上新建模块时,也发现如果没有迁移到AndroidX,模块创建不了,表明开始有强制性的措施使得开发者必须迁移到AndroidX。
![](https://user-gold-cdn.xitu.io/2019/9/18/16d424baaebe0771?imageView2/0/w/1280/h/960/ignore-error/1)
### 3.2 迁移AndroidX的前置条件
Android Sudio在3.2版本开始,对直接迁移到AndroidX进行了支持。在操作路径`Refactor > Migrate to AndroidX`下,但使用时会发现可能存在如下提示:
![](https://user-gold-cdn.xitu.io/2019/9/18/16d424e4a53fc036?imageView2/0/w/1280/h/960/ignore-error/1)
![](https://user-gold-cdn.xitu.io/2019/9/18/16d424e7f5deee09?imageView2/0/w/1280/h/960/ignore-error/1)
这也说明了,利用官方内置的迁移方式迁移AndroidX之前,工程环境上最好满足如下条件:
1,Android Studio 3.2及以上。当前时点最新版本已经是3.5稳定版了。
2,AGP版本3.2.0及以上,对应的Gradle版本4.6及以上。
3,项目编译版本28及以上。
如果当前项目没有满足上述条件,可以先升级对应的配套。
### 3.3 迁移过程
Android官方提供了具体的迁移指引。具体参见文档:
[developer.android.com/jetpack/and…]( )
Just Start!
以下主要记录实际项目中的迁移过程,以及遇到的问题及解决。
`Refactor > Migrate to AndroidX`操作后,AS会有对应的迁移提醒,提示你去备份项目文件,如有必要可以先备份。但一般而言,AS项目都是基于Git进行管理,直接单独切一个分支进行迁移操作即可,此处备份成zip现实意义不大。
![](https://user-gold-cdn.xitu.io/2019/9/18/16d425b0ad058c9c?imageView2/0/w/1280/h/960/ignore-error/1)
点击`Migrate`后,会出现弹窗`Looking for Usages`,开始在当前项目中搜索所有可能需要迁移的源文件,包括代码源文件、XML文件、build.gradle配置文件等,最终会列出当前主工程使用到支持库的所有文件列表。
![](https://user-gold-cdn.xitu.io/2019/9/18/16d4260bea42a53f?imageView2/0/w/1280/h/960/ignore-error/1)
点击`Do Refactor`确认迁移,AS自动执行迁移AndroidX的替换过程。如将对应的支持库类名、包名、构件名等都替换成相应的AndroidX形式。
一点时间后,主工程替换完成。此时打开`gradle.properties`,会发现自动添加了如下配置项。
android.useAndroidX=true android.enableJetifier=true
`android.useAndroidX=true`,表示主工程使用AndroidX形式。
`android.enableJetifier=true`,表示针对主工程中使用到的三方库,也会自动执行AndroidX的替换过程。
同时,在自动执行三方库的替换时,出下了如下报错信息:
ERROR: Unable to resolve dependency for ‘:MyCorn@prodDebug/compileClasspath’: Failed to transform file ‘fingerprint-1.1.1.aar’ to match attributes {artifactType=processed-aar} using transform JetifyTransform
大致的意思是使用`JetifyTransform`对`fingerprint-1.1.1.aar`进行替换过程中,出现了问题。但具体问题没有进一步的提示信息。于是,直接通过命令执行下构建看一下:
./gradlew assembleDevDebug … …
1: Task failed with an exception.
- What went wrong:
Could not resolve all files for configuration ‘:MyCorn:devDebugCompileClasspath’.
Failed to transform file ‘fingerprint-1.1.1.aar’ to match attributes {artifactType=processed-aar} using transform JetifyTransform Failed to transform ‘/Users/corn/.gradle/caches/modules-2/files-2.1/com.corn.feature/fingerprint/1.1.1/ae2da4c824fb2923eac7a1340222d50d6308f7ea/fingerprint-1.1.1.aar’ using Jetifier. Reason: 8. (Run with --stacktrace for more details.) To disable Jetifier, set android.enableJetifier=false in your gradle.properties file.
进而,带上--stacktrace看看。
./gradlew assembleDevDebug --stacktrace … … Caused by: 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:39) at com.android.tools.build.jetifier.processor.Processor.visit(Processor.kt:328) at com.android.tools.build.jetifier.processor.archive.ArchiveFile.accept(ArchiveFile.kt:41) 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.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:${supportVersion}",
"support-core-utils" : "com.android.support:support-core-utils:${supportVersion}",
"support-core-ui" : "com.android.support:support-core-ui:${supportVersion}",
"support-media-compat": "com.android.support:support-media-compat:${supportVersion}",
"support-fragment" : "com.android.support:support-fragment:${supportVersion}",
"support-annotations" : "com.android.support:support-annotations:${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:${androidXVersion}",
"androidx-core-utils" : "androidx.legacy:legacy-support-core-utils:${androidXVersion}",
"androidx-core-ui" : "androidx.legacy:legacy-support-core-ui:${androidXVersion}",
"androidx-media" : "androidx.media:media:${androidXVersion}",
"androidx-fragment" : "androidx.fragment:fragment:${androidXVersion}",
"support-annotations" : "androidx.annotation:annotation:${androidXVersion}",
"androidx-appcompat" : "androidx.appcompat:appcompat:${androidXVersion}",
....
## 最后
Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。
**人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。**
**我把自己这段时间整理的[Android最重要最热门的学习方向资料放在了我的CodeChina上](https://codechina.csdn.net/m0_60958482/android_p7),里面还有不同方向的自学编程路线、面试题集合/面经、及系列技术文章等。**
资源持续更新中,欢迎大家一起学习和探讨。
|