将Compose迁移到现有项目

11/18/2021 AndroidCompose

# 升级AndroidStudio

你可以升级AndroidStudio为最新版,直接去AndroidStudio官网 (opens new window)更新AndroidStudio即可。

# 升级gradle

你需要升级你的gradle为7.0及以上,如下:

buildscript {
    ...
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        ...
    }
}
1
2
3
4
5
6
7

这一步可能遇到很多问题,请移步到后面的问题以及解决

# 升级kotlin版本

接着,你需要升级你的kotlin版本为1.5.21及以上,如下:

plugins {
    id 'org.jetbrains.kotlin:android' version '1.5.21'
}
1
2
3

# 开启Compose

接着,你需要将应用的最低API版本设置为21及以上,并在build.gradle中启用Compose,还需要指定kotlin编译器插件版本,如下:

android {
    defaultConfig {
        ...
        minSdkVersion 21 // 最低版本为21
    }

    buildFeatures {
        // 为当前module启用 compose
        compose true
    }
    ...

    // java和kotlin编译版本都指定为1.8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }

    // 指定编译版本
    composeOptions {
        kotlinCompilerExtensionVersion '1.0.1'
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

并且,你需要指定项目的JDK版本为JDK11及以上AndroidStudio -> 设置 -> Gradle -> Gradle JDK -> 选择JDK11及以上

# 添加依赖

接着,你需要在开启compose的module中的build.gradle中添加compose使用的依赖,比如我自己的项目中添加有如下依赖:

compose_version = '1.0.1'

// 基础UI框架
implementation "androidx.compose.ui:ui:$compose_version"
// Material风格布局
implementation "androidx.compose.material:material:$compose_version"
// Compose扩展Activity
implementation 'androidx.activity:activity-compose:1.3.0-alpha06'
// UI测试
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
// UI工具包
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"

// Material风格图标
implementation("androidx.compose.material:material-icons-core:$compose_version")
implementation("androidx.compose.material:material-icons-extended:$compose_version")

// 图片加载框架
implementation 'io.coil-kt:coil-compose:1.3.0'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这些依赖不唯一,可以根据项目的需要添加。

# Compose和原生View的互调

# Android原生View使用ComposeView

比如我用Compose写了个界面,要在原来的xml布局中使用它,可以这样:

  1. 在xml布局中添加androidx.compose.ui.ComposeView,然后findViewById(id)出来,然后使用composeView.setContent(@Composable)即可。
  2. 直接在代码中创建出ComposeView,然后使用composeView.setContent(@Composable)

比如第一种方式:

我们先在xml文件中添加androidx.compose.ui.ComposeView

<androidx.compose.ui.platform.ComposeView
    android:id="@+id/compose_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
1
2
3
4

然后在代码中使用:

// 定义一个Compose风格的View
@Composable
fun TextView() {
    Text(text = "this is a compose TextView")
}


// 使用
val composeView: ComposeView = findViewById(R.id.compose_view)
composeView.setContent { TextView() }
1
2
3
4
5
6
7
8
9
10

# ComposeView使用Android原生View

在@Composable内使用: androidx.compose.ui.viewinterop.AndroidView,然后在factory里面返回原生View即可。如下:

@Composable
fun TextView() {
    Text(text = "this is a compose TextView")
    // 使用androidx.compose.ui.viewinterop.AndroidView
    AndroidView(
        // 需要提供一个factory来返回我们要使用的Android原生View,这里我们返回一个原生的ImageView
        factory = { context ->
            ImageView(context)
        },
        // modifier,可以不提供
        modifier = Modifier.padding(20.dp),
        // update,每次compose重组会调用到这里,可以不提供
        update = { imageView ->
            Log.d("Compsose", "$imageView has update")
        })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

AndroidView的函数原型如下:

@Composable
fun <T : View> AndroidView(
    factory: (Context) -> T, // 返回原生View
    modifier: Modifier = Modifier, // 修饰符
    update: (T) -> Unit = NoOpUpdate // 每次界面重组(更新)调用
)
1
2
3
4
5
6

# 问题以及解决

我们遇到的大部分问题都是兼容性问题,而且集中在升级gradle到7.0这一步,再次吐槽下gradle!

  • 1 所有使用compile 'xxxx'需要替换为api/implementation 'xxxx'。
  • 2 gradle7.0不再支持非http的依赖,所以原有的http仓库的依赖,需要替换为https依赖,比如:
maven {
    url 'http://dl.bintray.com/umsdk/release' // http仓库不安全
}
1
2
3

就要替换为

maven {
    url 'https://dl.bintray.com/umsdk/release' // 替换为https类型的仓库
}
1
2
3
  • 3 一些插件会失效,所以要 去这些插件的官网 或者 gradle官网 查看更新日志 来找到对应的替换方案,比如: 比如 apply plugin 'maven',需要替换为 apply plugin 'maven-publish'
  • 4 gradle的一些语法有更新,需要查看更新日志来进行更新,比如: 使用maven进行仓库发布的api更新了,就需要查看官网进行修改。
  • 5 如果你的项目是混合开发,比如rn或者flutter,就需要检测这些项目并且做相应更新(很蛋疼!)。

# 最后

迁移Compose到现有项目,需要耐住脾气和性子,一点一点来,不然很容易火大,而且要自底向上迁移,尽量缩小影响范围。

最后想吐槽一下,Google更新的真频繁!!!

Last Updated: 1/28/2022, 4:13:43 PM