theme: smartblue
背景
最近我司正在做关于kotlin
和jetpack
版本升级的工作。我这次就被分派到了jetpack
的升级工作了,这次目标版本就是谷歌最新的release版本。
本来以为是个非常简单的工作,就是把所有版本都升上去就搞定了吗!这不是分分钟就能搞定的事情吗。
最后发现竟然这么多坑点的吗。
今天的大部分文章内容我都在路由的那个项目里面,完成了简单的代码以及demo,有兴趣的可以了解下。 传送门
全是坑啊
首先我们根据官方文档对上述版本进行升级。我们在升级androidx.fragment:fragment-ktx
和androidx.activity:activity-ktx
发现奇怪的问题,因为他们的pom
使用lifecycle-runtime
的版本,所以我们必须同时对lifecycle
也进行对应的升级。
然后我就裂开了,官方移除了androidx.lifecycle:lifecycle-extensions
这个仓库,这个库被变更成了androidx.lifecycle:lifecycle-process
。
这个时候我们发现了一个鬼畜的问题,因为一些在主工程的项目也有依赖了这个库,那么就会导致依赖被传递到主工程内。但是如果像打地鼠一样一个个把这个仓移除,万一漏掉了就会非常尴尬。
移除所有依赖
这次就要讲讲茴字的三种写法了!
其实可以在application
目录的build.gradle
下面添加如下groovy。可以保证在打包的时候剔除这部分依赖。
configurations {
all*.exclude group: 'androidx.lifecycle', module: 'lifecycle-extensions'
}
或者你可以考虑下用我的另外一种写法,通过根目录的build.gradle
剔除项目内所有project
所有的子模块。
这个方式的好处就是因为所有的子模块的都剔除了对应的依赖,这样后续就不会直接使用到依赖的代码了。
代码语言:javascript复制allprojects {
configurations.all { Configuration c ->
if (c.state == Configuration.State.UNRESOLVED) {
exclude group: 'androidx.lifecycle', module: "lifecycle-extensions"
}
}
}
通过allproject configuration
的方式,我们就可以这部分调用exclude的方式给项目统一移除特定的依赖了。
当然还有另外一种方式了,就是通过策略,然后将一部分依赖进行一次替换,A换成B就是这样。
代码语言:javascript复制allprojects {
configurations.all { Configuration c ->
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'androidx.lifecycle' && details.requested.name == 'lifecycle-extensions') {
details.useTarget group: 'androidx.lifecycle', name: 'lifecycle-process'
}
}
}
}
。 这部分功能吧,其实还是有很意思的。你能对于gradle的一个重要的configuration
有一个更深入的了解
ViewModelProviders被移除了
我们碰到的第二个问题就是在最新版本中ViewModelProviders
被移除了,这我的天啊,要了老命了。
这部分其实也还是比较简单的,因为我们上面剔除了旧的依赖,所以我们的项目内项目内其实已经没有了ViewModelProviders
的代码了。第一个版本我们尽量避免大面积改造,所以我们只要同包名下拷贝一个类似的ViewModelProviders
类就行了。
但是我们正常只需要几个of
方法就好了。
package androidx.lifecycle
@Deprecated("ViewModelProviders adapter not support any more")
object ViewModelProviders {
@MainThread
@JvmStatic
fun of(activity: FragmentActivity): ViewModelProvider {
return ViewModelProvider(activity)
}
@MainThread
@JvmStatic
fun of(activity: FragmentActivity, factory: ViewModelProvider.Factory?): ViewModelProvider {
return if (factory == null) {
ViewModelProvider(activity)
} else {
ViewModelProvider(activity, factory)
}
}
@MainThread
@JvmStatic
fun of(fragment: Fragment): ViewModelProvider {
return ViewModelProvider(fragment)
}
@MainThread
@JvmStatic
fun of(fragment: Fragment, factory: ViewModelProvider.Factory?): ViewModelProvider {
return if (factory == null) {
ViewModelProvider(fragment)
} else {
ViewModelProvider(fragment, factory)
}
}
}
所以我们大概只要生成要给这样类就行了,可以解决第一期的替换问题了。但是过期的类也就没必要一直这么维持下去了,所以我们后续打算二期通过静态检查(lint)的方式,让业务进行改动。
jvm 1.8也挂了?
这次在我们升级的过程中,我们发现了有一部分仓库直接用了androidx.activity:activity-ktx
和androidx.fragment:fragment-ktx
。他们获取到ViewModel
的形式是通过fragment或者activity的拓展函数,viewModels
委托来完成的。
但是由于升级SDK
,其中的noinline
方法内联由于需要使用到kotlin jvm 1.8
来进行编译,所以就出现了无法编译的问题,解决方案也比较简单,就是通过在Module
下的build.gradle
设置如下代码。
kotlinOptions {
jvmTarget = "1.8"
}
但是有没有一个比较通用的方法可以直接把项目内所有的模块都设置成jvmTarget
的方法呢?
allprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
上述方法就是了,这样我们就可以统一把项目内的所有的kotlinOptions
的版本调整到我们想要的版本上了。
Binding真香
最后因为要准备开始使用ViewBinding
了,所有我偷鸡了下hi-dhl
大佬的Binding
,我阉割了一个只有ViewBinding
的版本。
Binding 项目地址
但是这种委托的写法还是很香的,大佬牛逼。
这部分之前也有好几个大佬介绍过了,我这里就不展开说明了。
总结
当然一些别的调整我就不一一举例了,比如啥主进程注册啊,另外一些奇奇怪怪的crash问题,我们都只能见招拆招。
好了,我装完逼了,下次看看是不是能装个更厉害的。
下次一定。