血泪总结!Android传统项目接入Compose的7大深坑与填坑方案

为什么采用 Compose

官方:Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发,打造生动而精彩的应用。它可让您更快速、更轻松地构建 Android 界面。

背景:现在AS创建项目默认compose,所以你说学不学,就和当初刚推kotlin一样,想继续干安卓就学吧。新项目在很多公司有可能没有,只在老项目进行迭代,那下面就说下老项目引入compose以及遇到的一些坑。下面是基于基于groovy进行升级的。

做准备

  • 先创建一个新的项目
  • 如果你的项目build.gradle是kotlin写的,也就是文件后缀是.kts,直接Finish就行,如果是老项目这里选择groovy。

升级版本

  • 升级AGP:agp = "8.9.0"
  • 升级对应的gradle :gradle-wrapper.properties
groovy 复制代码
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
  • 升级compileSdkVersion、targetSdkVersion、移除 buildToolsVersion
    • compileSdkVersion改为compileSdk,升级为 compileSdk= 34
    • targetSdkVersion 升级为 targetSdkVersion = 30
    • AGP 7.0.0buildToolsVersion被正式移除,在此版本及之后,不再需要手动指定buildToolsVersion,AGP会自动选择合适的Build Tools版本进行构建。
    • compileSdkVersion、targetSdkVersion为啥版本不一样
      • 因为没有那么多精力和时间,适配需要大量的时间和测试, compileSdkVersion升级为34是为了compose,compose的大部分依赖版本支持的是34,没升级最新的35,听说35有很大的变动,后面有时间再适配。
      • lintOptions加入 error "NewApi" // 将新API调用标记为错误(而非警告)
      • compileSdkVersiontargetSdkVersion 的区别总结
配置项 含义 影响范围 注意事项
compileSdkVersion 编译时使用的 Android SDK 版本 编译阶段可用的 API - 建议始终使用最新的版本,以访问新功能和优化 - 不会影响运行时行为
targetSdkVersion 应用的目标 Android SDK 版本 运行时的行为和兼容性模式 - 应定期更新,确保符合最新系统行为和安全要求 - Google Play 有最低要求

一、升级 build.gradle

  • 顶部plugin变更 1.alias()里面的写法在后面说明;apply from 放在plugins下面
  • 去掉dexOptions
  • buildFeatures 增加 compose true buildConfig true
    • buildConfig true在最新版是默认false的,如果项目用到了BuildConfig要加入这个,否则不需要。
arduino 复制代码
    buildFeatures {
        dataBinding true
        viewBinding true
        compose true
        buildConfig true
    }
  • 修改 compileOptions
    • jdk由原来的1.8改为11
    • 下载jdk,配置JAVA_HOME环境变量
ini 复制代码
 // 老
  compileOptions {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
     coreLibraryDesugaringEnabled true
  }
      kotlinOptions {
        jvmTarget = '8'
    }
  // 新
     compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
        coreLibraryDesugaringEnabled true
    }
    kotlinOptions {
        jvmTarget = '11'
    }
cpp 复制代码
plugins {
  alias(libs.plugins.android.application)
  alias(libs.plugins.kotlin.android)
  alias(libs.plugins.kotlin.compose)
  id 'kotlin-kapt'
  id 'com.kanyun.kace'
  id 'kotlin-parcelize'

}

apply from: '../other.gradle'


android {
  compileSdk 34
  namespace "清单文件里的package包名"

  defaultConfig {
    applicationId "com.xx.xx"
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName version

    vectorDrawables.useSupportLibrary = true


    multiDexEnabled true
    ndk {
      abiFilters 'arm64-v8a'
    }
    lintOptions {
      abortOnError false
      error "NewApi"  // 将新API调用标记为错误(而非警告)
    }

    sourceSets {
      main {
        jniLibs.srcDirs = ['libs']
      }
    }
  }
...

  buildFeatures {
    dataBinding true
    viewBinding true
    compose true
    buildConfig true
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_11
    targetCompatibility JavaVersion.VERSION_11
    coreLibraryDesugaringEnabled true
  }

  kotlinOptions {
    jvmTarget = '11'
  }

kapt {
  generateStubs = true
}
...
}

dependencies {
  implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
...
  implementation libs.coil
  implementation platform(libs.androidx.compose.bom)
  androidTestImplementation platform(libs.androidx.compose.bom)
  implementation libs.androidx.activity.compose
  implementation libs.androidx.lifecycle.viewmodel.compose
  implementation libs.androidx.lifecycle.runtime.ktx
  implementation libs.androidx.ui
  implementation libs.androidx.ui.viewbinding
  implementation libs.androidx.ui.util
  implementation libs.androidx.material3
  debugImplementation libs.androidx.ui.tooling
  implementation libs.androidx.ui.tooling.preview
  debugImplementation libs.androidx.ui.test.manifest
  implementation libs.androidx.ui.graphics
  androidTestImplementation libs.androidx.ui.test.junit4

}

二、升级项目级build.gradle

  • buildscript,allprojects变成pluginManagement、dependencyResolutionManagement并放入到setting.gradle
  • 老的项目
cpp 复制代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:5.2.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
        maven { url 'https://dl.google.com/dl/android/maven2/' }
        maven { url 'https://jitpack.io' }
      
    }
   
}
  • 改造后
cpp 复制代码
pluginManagement {
    repositories {
        maven { url "https://maven.aliyun.com/repository/google" }
        maven { url "https://maven.aliyun.com/repository/public" }
        maven { url "https://maven.aliyun.com/repository/central" }
        maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
        google()
        mavenCentral()
    }


}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven { url "https://maven.aliyun.com/repository/google" }
        maven { url "https://maven.aliyun.com/repository/public" }
        maven { url "https://maven.aliyun.com/repository/central" }
        maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
        maven { url "https://dl.google.com/dl/android/maven2/" }
        maven { url "https://jitpack.io" }
        maven { url "https://repo1.maven.org/maven2/" }
    }
}
  • buildscript里的classpath不支持新的alias插件配置方式
cpp 复制代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
  dependencies {
    // 不支持新的alias插件配置方式
    classpath 'com.xxx.xxx:xxx:1.6.0.300'//
  }
}

plugins {
  alias(libs.plugins.android.application) apply false
  alias(libs.plugins.kotlin.android) apply false
  alias(libs.plugins.kotlin.compose) apply false

}

三、升级setting.gradle

  • 第二步已经说明了,增加了pluginManagement、dependencyResolutionManagement
  • include变更
cpp 复制代码
pluginManagement {
    repositories {
        maven { url "https://maven.aliyun.com/repository/google" }
        maven { url "https://maven.aliyun.com/repository/public" }
        maven { url "https://maven.aliyun.com/repository/central" }
        maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
        google()
        mavenCentral()
    }


}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven { url "https://maven.aliyun.com/repository/google" }
        maven { url "https://maven.aliyun.com/repository/public" }
        maven { url "https://maven.aliyun.com/repository/central" }
        maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
        maven { url "https://dl.google.com/dl/android/maven2/" }
        maven { url "https://jitpack.io" }
        maven { url "https://repo1.maven.org/maven2/" }
    }
}

include(
        ":app",
        ":app1",
        ":app2",
        ":app3",
        ":app4",
        ":app5"
)
rootProject.name = "名字"

四、迁移到 Gradle 7.x or 8.x 使用 Version Catalogs 管理依赖,gradle引入libs.versions.toml

cpp 复制代码
[versions]

[libraries]

[plugins]
  • 这些部分的使用方式如下:
    • 在 versions 代码块中,定义用于保存依赖项和插件版本的变量。您可以在后续代码块(libraries 和 plugins 代码块)中使用这些变量。
    • 在 libraries 代码块中,定义依赖项。
    • 在 plugins 代码块中,定义插件。

五、引入Compose相关依赖

  • build.gradle引入
cpp 复制代码
  implementation libs.coil
  implementation platform(libs.androidx.compose.bom)
  androidTestImplementation platform(libs.androidx.compose.bom)
  implementation libs.androidx.activity.compose
  implementation libs.androidx.lifecycle.viewmodel.compose
  implementation libs.androidx.lifecycle.runtime.ktx
  implementation libs.androidx.ui
  implementation libs.androidx.ui.viewbinding
  implementation libs.androidx.ui.util
  implementation libs.androidx.material3
  debugImplementation libs.androidx.ui.tooling
  implementation libs.androidx.ui.tooling.preview
  debugImplementation libs.androidx.ui.test.manifest
  implementation libs.androidx.ui.graphics
  androidTestImplementation libs.androidx.ui.test.junit4
  
  • libs.versions.toml 文件中
cpp 复制代码
[versions]
agp = "8.9.0"
kotlin = "2.0.10"
composeBom = "2025.01.01"
lifecycleRuntimeKtx = "2.8.3"
activityCompose = "1.8.2"
coil-compose = "2.5.0"

[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } # 统一管理compose相关依赖版本
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } # 支持在activity中嵌入compose组件
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" } # 支持viewmodel
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } # 组件支持生命周期管理
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-viewbinding = { module = "androidx.compose.ui:ui-viewbinding" }
androidx-ui-util = { module = "androidx.compose.ui:ui-util" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } # 支持compose组件预览
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
coil = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil-compose" } # 图片

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

六、各个版本说明,Gradle、AGP、Kotlin、Compose

七、遇到的问题

  • 删除清单文件里的pacgage,添加 namespace,AGP8以上强制
cpp 复制代码
报错 Namespace not specified. Specify a namespace in the module's build file: build.gradle. See https://d.android.com/r/tools/upgrade-assistant/set-namespace for information about setting the namespace.

If you've specified the package attribute in the source AndroidManifest.xml, you can use the AGP Upgrade Assistant to migrate to the namespace value in the build file. Refer to https://d.android.com/r/tools/upgrade-assistant/agp-upgrade-assistant for general information about using the AGP Upgrade Assistant.
Affected Modules: xxx
>> Ask Gemini
  • 升级AGP8+ BuildConfig 找不到符号
vbnet 复制代码
:3: 错误: 找不到符号
import com.xxxe.lib.BuildConfig;
                           ^
  符号:   类 BuildConfig
  位置: 程序包 com.xxx.lib
Ask Gemini
// 添加  buildConfig true
buildFeatures {
  buildConfig true
}

八、相关知识点

在 Compose 中使用 View

在 View 中使用 Compose

可以愉快的写了

相关推荐
haogexiaole1 小时前
vue知识点总结
前端·javascript·vue.js
哆啦A梦15883 小时前
[前台小程序] 01 项目初始化
前端·vue.js·uni-app
小周同学@5 小时前
谈谈对this的理解
开发语言·前端·javascript
Wiktok5 小时前
Pyside6加载本地html文件并实现与Javascript进行通信
前端·javascript·html·pyside6
一只小风华~5 小时前
Vue:条件渲染 (Conditional Rendering)
前端·javascript·vue.js·typescript·前端框架
柯南二号5 小时前
【大前端】前端生成二维码
前端·二维码
程序员码歌6 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
博客zhu虎康7 小时前
React Hooks 报错?一招解决useState问题
前端·javascript·react.js
灰海7 小时前
vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)
前端·javascript·vue.js·heatmap·heatmapjs
王源骏8 小时前
LayaAir鼠标(手指)控制相机旋转,限制角度
前端