关于一个新的Flutter项目的安卓踩坑之旅

2,904 阅读10分钟

关于Flutter安卓编译的一些问题与解答

问题一:我项目中配置的版本是1.9.23,但是报错了:* What went wrong:

The Android Gradle plugin supports only kotlin-android-extensions Gradle plugin version 1.6.20 and higher. The following dependencies do not satisfy the required version: project ':map_launcher' -> org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31

问题二:更新项目的 AGP、Gradle、Kotlin 版本 至兼容组合

image.png

升级jdk: 一方面设置项目的 File-ProjectStructure 另一方面设置app模块下的build.gradle的jdk版本

image.png

image.png

问题三:提示项目中 kotlin所使用的java版本与项目使用的java版本不兼容

  • 兼容设置一:

image.png

coreLibraryDesugaringEnabled = true
  • 兼容设置二:

image.png

coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' // 请检查最新版本
  • 强制让子模块的kotlin使用java17版本

image.png

// 强制指定Kotilin版本
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
    afterEvaluate {
        if (it.hasProperty('android')) {
            if (it.android.namespace == null) {
                def manifest = new XmlSlurper().parse(file(it.android.sourceSets.main.manifest.srcFile))
                def packageName = manifest.@package.text()
//                    println("Setting ${packageName} as android namespace")
                android.namespace = packageName
            }
            // 指定Kotilin版本
            def javaVersion = JavaVersion.VERSION_17
            android {
                compileOptions {
                    sourceCompatibility javaVersion
                    targetCompatibility javaVersion
                }
                tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
                    kotlinOptions {
                        jvmTarget = javaVersion.toString()
                    }
                }
//                    println("Setting java version to ${javaVersion.toString()} which is $javaVersion")
            }
        }
    }
}

问题四:namespace命名空间问题(自己去查Android applicationId 和 package namespace 区别是什么?都是干什么用的?)

What went wrong: A problem occurred evaluating root project 'android'. > A problem occurred configuring project ':app'. > Could not create an instance of type com.android.build.api.variant.impl.ApplicationVariantImpl. > Namespace not specified. Specify a namespace in the module's build file: /Users/jiayuanfa/Desktop/Code/client_mobile/android/app/build.gradle. See d.android.com/r/tools/upg… 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 d.android.com/r/tools/upg… for general information about using the AGP Upgrade Assistant. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at help.gradle.org.

  • 说明从Android Gradle插件(AGP)7.0开始,manifest中的package属性需要迁移到build.gradle中的namespace属性,以提升模块化和避免包名冲突。

用户提供的上下文中有多个关于Kotlin插件版本1.9.23的引用,但主要错误与namespace配置无关,因此可能需要检查AGP版本是否至少为7.0。不过用户的问题重点在于如何解决这个namespace缺失的问题。

  • 删掉AndroidManifest.xml的package字段
  • 在app下面的build.gradle里面新增namespace字段 ,字段结果使用刚才删掉的AndroidManifest.xml里面的package的值

image.png

  • 在android目录下的build.gradle里面也处理一下,为了使得子模块也拥有namespace

image.png

// The below script
subprojects {
    afterEvaluate { project ->
        if (project.hasProperty('android')) {
            project.android {
                if (namespace == null) {
                    namespace project.group
                }
            }
        }
    }
}

问题五:其他通过命令行编译安卓项目的技巧

  • 清理项目

image.png

  • 进入上面的文件夹
  • 执行
./gradlew clean  
rm -rf .gradle/  
rm -rf build/  
  • 编译项目
./gradlew build
  • 运行项目
./gradlew build
  • 清理flutter缓存
flutter clean && rm -rf build/
  • 算了,不一一写了
好的,我现在需要帮助用户解决如何在命令行中使用 `./gradlew` 来运行他们的Android项目的问题。用户之前遇到了一系列Gradle相关的问题,包括找不到命令、版本不匹配等。现在用户想知道如何具体运行项目,可能之前通过Android Studio运行过,但现在想用命令行。

首先,我需要确认用户对基本步骤的理解程度。用户已经提到了使用Android Studio内置的Gradle,但可能遇到了问题,所以现在想通过命令行操作。我需要一步步详细说明如何使用./gradlew执行构建和运行应用等操作。

接下来,我应该考虑用户可能的环境:他们可能在Linux或macOS下,因为使用zsh以及./gradlew的语法。所以步骤要针对这些系统,但也要注意通用性。

用户可能已经安装了Gradle在Android Studio中,但之前的错误提示显示命令缺失,所以可能需要提醒他们确认项目目录下确实存在gradlew文件,以及文件权限是否正确。另外,用户可能之前已经解决了如何安装Gradle的问题,所以现在可以假设他们已经设置了正确的路径或使用Gradle Wrapper。

接下来,我需要分步骤说明如何执行常见任务,比如清理、构建、安装应用到设备上。每个步骤需要具体命令,并解释其作用。例如:

  1. 清理项目:./gradlew clean
  2. 构建并安装Debug版本:./gradlew assembleDebug./gradlew installDebug
  3. 运行应用:可能需要先打包再安装,或者用./gradlew run?不过可能不同项目路径不同,需要更详细的说明,比如./gradlew :app:run或者配置的启动器Activity名称。

同时,用户可能需要知道如何查看日志,调试命令,以及常见的构建问题处理。例如,添加--info--stacktrace参数来获取更多信息。

另外,是否需要区分不同构建变体(Debug/Release)?用户可能需要知道如何指定构建类型。

还需要提到,如果项目中有多个模块,可能需要指定模块名,比如./gradlew :app:assembleDebug

还要注意,用户可能没有连接设备或模拟器,需要提示他们确认设备是否可用,或者如何启动模拟器。

最后,可能需要给出一些常见问题的解决办法,比如权限问题导致的zsh: command not found,需要赋予执行权限chmod +x gradlew

还需要确保用户理解和执行每个步骤的顺序,以及可能出现的常见错误提示和解决方案。

总结步骤列表,确保清晰简洁,分点说明,使用代码块格式标注命令,可能还需要解释每个命令的作用,让用户明白为什么要这样操作。

以下是使用 ./gradlew 命令在命令行中运行 Android 项目的详细步骤及常用命令,适用于 Linux/macOS(Windows 用户可以替换为 gradlew.bat):


步骤 1:进入项目目录

首先确保你的终端位于 项目根目录(即包含 build.gradlesettings.gradle 的目录):

cd /path/to/your/project

步骤 2:运行关键命令

使用以下命令执行常见操作:


1. 清理项目缓存

清除之前构建的中间文件(如 .apk.class 等):

./gradlew clean

2. 单次构建(Debug 版本)

构建 APK(Debug 版本)并生成二进制文件:

./gradlew assembleDebug  # 或 ./gradlew build(包含测试和构建)
  • 成功后,APK 位于:app/build/outputs/apk/debug/app-debug.apk

3. 安装到连接的设备或模拟器

若已经连接设备,直接安装 APK:

./gradlew installDebug  # 安装 Debug 版本
# 或
./gradlew uninstallDebug  # 卸载 Debug 版本

4. 运行应用

若需直接启动应用(仅支持 Android Studio 插件支持的项目):

./gradlew run  # 默认运行主模块
# 或指定模块:
./gradlew :app:run

5. 同步项目(类似 Android Studio 的 Sync 操作)

同步 Gradle 配置(如依赖更新后):

./gradlew --no-daemon  # 强制重新同步

6. 显示所有可用任务

查看项目所有可用的 Gradle 任务:

./gradlew tasks  # 或 tasks --all

7. 启动 Android Emulator(需提前配置设备)

如果需要通过命令启动模拟器:

emulator -avd <设备名称>  # 例如:emulator -avd Pixel_6_API_34

8. 查看构建日志与调试信息

添加运行参数提高输出详细程度:

./gradlew build --info   # 详细输出
./gradlew build --debug  # 调试级输出
./gradlew build --stacktrace  # 错误堆栈跟踪

高级用法

指定构建变种(Flavors)

如项目配置了 productFlavors,可指定变种构建:

./gradlew assembleDevDebug  # 构建名为 "dev" 的 Debug 变种

指定模块构建

若项目有多个模块,运行特定模块的构建:

./gradlew :module_name:assembleDebug

强制使用特定 Gradle 版本

./gradlew -version --gradle-user-home=/path/to/cache

常见问题处理

  1. ./gradlew: not found

    • 确认项目根目录下存在 gradlew 文件。
    • 赋予执行权限:chmod +x gradlew
  2. 设备未连接或未识别

    • 使用 adb devices 确认设备列表。
    • 启动模拟器:通过 AVD Manager 或命令行启动模拟器。
  3. 构建超时或内存不足

    • 在项目根目录的 gradle.properties 中增加内存:
      org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError
      

典型运行流程示例

# 清理并构建 Debug 版本
./gradlew clean && ./gradlew assembleDebug

# 安装到设备
./gradlew installDebug

# 或单条命令组合
./gradlew clean assembleDebug installDebug

通过上述命令,你可以完全通过终端控制项目构建、安装和调试。如需更复杂的操作(如发布版本构建、测试执行),可参考 ./gradlew tasks --all 的任务列表进一步探索。

警告处理:

WARNING: Your project includes version 8.3.37 of R8, while Android Gradle Plugin was shipped with 8.9.27. This can lead to unexpected issues.

  • 嗯,用户遇到了一个关于R8版本警告的问题。让我仔细看看。用户提供的警告信息是:“Your project includes version 8.3.37 of R8, while Android Gradle Plugin was shipped with 8.9.27.” 这说明他们的项目中使用的R8版本与Android Gradle插件(AGP)自带的版本不一致,可能存在兼容性问题。

首先,我需要确认什么是R8。R8是Android的代码缩减和混淆工具,替换原有的ProGuard。AGP通常会自带R8,但用户可能在项目的依赖中显式指定了另一个版本,导致版本冲突。

接下来,分析警告的信息。用户使用的R8版本(8.3.37)比AGP自带的版本(8.9.27)旧。这可能导致在构建过程中出现不可预知的问题,比如代码缩减失败或优化不当。此外,R8的版本更新通常包含重要的修复和优化,旧版本可能存在已知问题。

用户为什么会遇到这个问题呢?可能是在项目的级build.gradle文件中手动添加了R8的dependency,或者某个第三方库强制依赖了旧版本的R8。这时候需要检查项目的dependencies,移除显式的R8依赖,让AGP使用内置的版本。

image.png

警告二

You are applying Flutter's app_plugin_loader Gradle plugin imperatively using the apply script method, which is deprecated and will be removed in a future release. Migrate to applying Gradle plugins with the declarative plugins block: flutter.dev/to/flutter-…

You are applying Flutter's main Gradle plugin imperatively using the apply script method, which is deprecated and will be removed in a future release. Migrate to applying Gradle plugins with the declarative plugins block: flutter.dev/to/flutter-…

警告三:NDK也就是C++的支持库问题

Your project is configured with Android NDK 23.1.7779620, but the following plugin(s) depend on a different Android NDK version:

  • alipay_kit_android requires Android NDK 27.0.12077973

  • audio_session requires Android NDK 27.0.12077973

  • camera_android requires Android NDK 27.0.12077973

  • device_info_plus requires Android NDK 27.0.12077973

  • emoji_picker_flutter requires Android NDK 27.0.12077973

  • ffmpeg_kit_flutter_full_gpl requires Android NDK 27.0.12077973

  • file_picker requires Android NDK 27.0.12077973

  • flutter_app_installer requires Android NDK 27.0.12077973

  • flutter_background requires Android NDK 27.0.12077973

  • flutter_downloader requires Android NDK 27.0.12077973

  • flutter_image_compress_common requires Android NDK 27.0.12077973

  • flutter_keyboard_visibility requires Android NDK 27.0.12077973

  • flutter_local_notifications requires Android NDK 27.0.12077973

  • flutter_native_splash requires Android NDK 27.0.12077973

  • flutter_new_badger requires Android NDK 27.0.12077973

  • flutter_openim_sdk requires Android NDK 27.0.12077973

  • flutter_plugin_android_lifecycle requires Android NDK 27.0.12077973

  • geolocator_android requires Android NDK 27.0.12077973

  • getuiflut requires Android NDK 27.0.12077973

  • image_cropper requires Android NDK 27.0.12077973

  • image_gallery_saver_plus requires Android NDK 27.0.12077973

  • image_picker_android requires Android NDK 27.0.12077973

  • just_audio requires Android NDK 27.0.12077973

  • local_auth_android requires Android NDK 27.0.12077973

  • map_launcher requires Android NDK 27.0.12077973

  • mobile_scanner requires Android NDK 27.0.12077973

  • mop requires Android NDK 27.0.12077973

  • open_filex requires Android NDK 27.0.12077973

  • package_info_plus requires Android NDK 27.0.12077973

  • path_provider_android requires Android NDK 27.0.12077973

  • permission_handler_android requires Android NDK 27.0.12077973

  • photo_manager requires Android NDK 27.0.12077973

  • record_android requires Android NDK 27.0.12077973

  • scan requires Android NDK 27.0.12077973

  • sensors_plus requires Android NDK 27.0.12077973

  • share_plus requires Android NDK 27.0.12077973

  • shared_preferences_android requires Android NDK 27.0.12077973

  • sound_mode requires Android NDK 27.0.12077973

  • sqflite_android requires Android NDK 27.0.12077973

  • uri_to_file requires Android NDK 27.0.12077973

  • url_launcher_android requires Android NDK 27.0.12077973

  • vibration requires Android NDK 27.0.12077973

  • video_compress requires Android NDK 27.0.12077973

  • video_player_android requires Android NDK 27.0.12077973

  • wakelock_plus requires Android NDK 27.0.12077973

  • webview_flutter_android requires Android NDK 27.0.12077973 Fix this issue by using the highest Android NDK version (they are backward compatible). Add the following to /Users/jiayuanfa/Desktop/Code/client_mobile/android/app/build.gradle:

    android { ndkVersion = "27.0.12077973" ... }

警告四:

Error: The 'kotlin-android-extensions' Gradle plugin is no longer supported. Please use this migration guide (goo.gle/kotlin-andr…) to start working with View Binding (developer.android.com/topic/libra…) and the 'kotlin-parcelize' plugin.

  • 这个问题很简单,涉及到原声代码,也就是不让你用kotlin-android-extensions了,这个库的作用就是xml的控件可以直接使用控件的id点出来使用,那么不让用了,我们直接findViewById或者使用ViewBinding即可