Jetpack 最新release版本升级 | 杂谈

3,492 阅读4分钟

背景

最近我司正在做关于kotlinjetpack版本升级的工作。我这次就被分派到了jetpack的升级工作了,这次目标版本就是谷歌最新的release版本。

本来以为是个非常简单的工作,就是把所有版本都升上去就搞定了吗!这不是分分钟就能搞定的事情吗。

最后发现竟然这么多坑点的吗。

今天的大部分文章内容我都在路由的那个项目里面,完成了简单的代码以及demo,有兴趣的可以了解下。 传送门

全是坑啊

首先我们根据官方文档对上述版本进行升级。我们在升级androidx.fragment:fragment-ktxandroidx.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所有的子模块。

这个方式的好处就是因为所有的子模块的都剔除了对应的依赖,这样后续就不会直接使用到依赖的代码了。

allprojects {
    configurations.all { Configuration c ->
        if (c.state == Configuration.State.UNRESOLVED) {
            exclude group: 'androidx.lifecycle', module: "lifecycle-extensions"
        }
    }
}

通过allproject+configuration的方式,我们就可以这部分调用exclude的方式给项目统一移除特定的依赖了。

当然还有另外一种方式了,就是通过策略,然后将一部分依赖进行一次替换,A换成B就是这样。

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-ktxandroidx.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问题,我们都只能见招拆招。

好了,我装完逼了,下次看看是不是能装个更厉害的。

下次一定。