Flutter 3.x 版本升级实战:让老项目焕发新生

news/2025/1/12 8:46:46/


随着 Flutter 框架的不断更新,开发者时常需要面对项目升级和改造的问题。从 Flutter 2.xFlutter 3.x 的版本不仅带来了新特性,也引入了许多 breaking changes架构优化。最近在做的就是 Flutter 老项目的升级改造,将 Flutter 的版本升到最新的stable 3.27.1,这里记录一下更新过程中遇到的问题及解决办法,也希望对你有所帮助。

null safety 支持

支持 null safety 可以帮助你在编译时捕捉空值相关的错误,避免运行时错误和异常,也是本次老项目升级改造改动代码最多的。通常的做法就是,如果变量不允许为 null,则使用具体的 Type 类型,而不是 Type?(即声明为非可空类型),如 String name = 'John';

对于某个可以为 null 的类型,使用类型后加 ? 来表示它是可空类型。例如,String? 表示该值可以是一个字符串或 nullString? name = null;

对于不可为 null 的变量,但又要确保它们在构造函数中被正确初始化。可以使用 late 关键字来延迟初始化某个变量。

late String name;
name = 'John';

在使用可空类型的变量时,需要进行 null 检查。例如,使用 ?.?? 来避免空引用错误。

String? name;
print(name?.length); // 如果 name 为 null,则不会引发异常// 使用默认值
String displayName = name ?? 'Guest';

项目中的代码改造成支持 null safety 之后,还需要更新 pubspec.yaml 文件中依赖的版本,确保它们与 null safety 兼容。我这里使用 flutter pub outdated 命令查看需要更新的插件版本,然后手动编辑更新,一旦发现报错及时修改。当然也可以用以下命令一起更新:

flutter pub upgrade --major-versions

构造函数中如何给数组类型的变量赋默认值,通常的做法是这样的。

class GatewayModel {List<DeviceModel> devices;// 如果没有提供参数,则使用默认空数组GatewayModel({this.devices = const []});
}

但是这样给数组赋默认值有一个问题,就是在后面使用的过程中,数组devicesImmutable类型的,不能向devices数组内添加元素。可以在this.devices前面加上required,也就是说调用构造函数时必须给devices赋值,或者像下面这样初始化devices

class GatewayModel {List<DeviceModel> devices;// GatewayModel({required this.devices});GatewayModel({List<DeviceModel>? devices}): this.devices = devices ?? [];
}

当然以上做法对于 map 类型也同样适用。

Namespace not specified 报错问题

Flutter 更新到3.27.1后,相应的需要升级 Android Gradle Plugin(AGP) 至兼容版本,当 android 工程的 AGP 大于等于 8.x.x 以上时,该报错会出现。

FAILURE: Build failed with an exception.* What went wrong:
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: xxx/android/app/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.

根据上述报错给出的提示,首先使用 AGP Upgrade Assistant 来更新 gradle 版本。打开android工程后,在菜单栏中找到并点击Tool ->AGP Upgrade Assistant,更新完成后,在android->build.gradle 的文件中添加如下配置。

allprojects {repositories {google()mavenCentral()}// add this codesubprojects {afterEvaluate { project ->if (project.hasProperty('android')) {project.android {if (namespace == null) {namespace project.group}}}}}// add this code
}

添加这个配置的目的是给让当前 Flutter 项目中所有的子项目或插件都加上 namespace,以便适配最新的 gradle 版本。再次运行发现还会报错:

Caused by: java.lang.ClassNotFoundException: Didn't find class "android.MainActivity" on path: DexPathList[[zip file

那就在android->app->build.gradle文件中配置一下namespace:

android {...namespace "应用的包名"...
}

上述操作完成后,如果还是有报错,尝试 Build -> Clean Project,然后 File -> Invalidate Caches / Restart

MultiDex 报错问题

这也是一个比较坑的问题,因为在 Flutter 运行在 Android 手机设备上的时候一直卡在 Installing apk 这里,也没有看到任何报错,打开 android 项目运行知道是 MultiDex 未启用。

好在解决起来也不难,Android 的官方文档中(https://developer.android.com/build/multidex?hl=zh-cn#kotlin)有详细的解决步骤,这里简单介绍一下我在项目中的操作。

  1. android->app->build.gradle文件中启用 MultiDex,并将 MultiDex 库添加为依赖项。
android {defaultConfig {minSdk = 24multiDexEnabled = true // 1. open MultiDex enable...}
}dependencies {implementation 'androidx.multidex:multidex:2.0.1' // 2. add it as a dependency here
}

位置1打开multiDexEnabled,位置2设置依赖项。这里需要说明一下,如果 minSdkVersion 为21或更高版本,会默认启用 MultiDex,并且您不需要 手动配置 MultiDex 库,反之,如果则需要。我这里的 minSdk 虽然是24,但是项目中其它组件用到的 minSdk 为16,所以还是需要收到配置 MultiDex 库。

  1. AndroidManifest.xmlapplication 标签中添加 android:name
<application android:name="androidx.multidex.MultiDexApplication" >...
</application>
  1. MainActivity 中重写 attachBaseContext 方法,并调用 MultiDex.install
import android.content.Context
import androidx.multidex.MultiDexclass MainActivity: FlutterActivity(){override fun attachBaseContext(base: Context) {super.attachBaseContext(base)MultiDex.install(this)}
}
  1. 如果前面三步配置好之后运行没问题的话,可以忽略该步骤。如果还是不行,老规矩尝试 Build -> Clean Project,然后 File -> Invalidate Caches / Restart

小结

除了上面记录的问题,还有 Flutter 3.0 及第三方的依赖库引入了一些 API 的更改或弃用。在迁移时,可能需要对一些弃用的 API 进行替换,或者更新你的依赖库以确保兼容性。改造完成后还需要对整个 App 的功能进行测试,以确保能够正常运行。


http://www.ppmy.cn/news/1562450.html

相关文章

HarmonyOS开发:粒子动画应用实战

目录 引言 粒子动画技术概述 关于粒子动画 粒子发射器的实现 设置粒子颜色 关于粒子的生命周期 粒子扰动场的设置 粒子动画的简单实现 最后 引言 做应用开发的小伙伴想必都清楚动画是必备技能&#xff0c;尤其是在移动应用开发中的动画使用频率是非常高的。而粒子动画…

Docker: 教程07 - ( 如何对 Docker 进行降级和升级)

如果我们使用 docker 来管理容器&#xff0c;那么保持 docker 引擎的更新将会是十分重要的&#xff0c;这一篇文章我们将会讨论如何对Docker 进行降级和升级。 准备工作 - docker 环境 我们需要拥有一个安装好 docker 的运行环境。 如果你需要了解如何安装 docker 可以通过如…

An FPGA-based SoC System——RISC-V On PYNQ项目复现

本文参考&#xff1a; &#x1f449; 1️⃣ 原始工程 &#x1f449; 2️⃣ 原始工程复现教程 &#x1f449; 3️⃣ RISCV工具链安装教程 1.准备工作 &#x1f447;下面以LOCATION代表本地源存储库的安装目录&#xff0c;以home/xilinx代表在PYNQ-Z2开发板上的目录 ❗ 下载Vivad…

HTML5 Audio(音频)

HTML5 Audio(音频) HTML5 的 <audio> 元素是一个重要的革新,它为网页开发者提供了一种简单的方式来嵌入音频内容。在这篇文章中,我们将探讨 HTML5 <audio> 元素的特性、用法、浏览器兼容性,以及如何通过 JavaScript 和 CSS 对其进行控制和定制。 1. HTML5 <…

基于Java+SpringMvc+Vue技术的宠物分享平台

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

从攻击视角探讨ChatGPT对网络安全的影响

ChatGPT是OpenAI 发布的基于人工智能的对话机器人&#xff0c;上线短短2个月活跃用户就突破了1亿&#xff0c;成为全球关注的焦点。ChatGPT可以自动化地处理对话&#xff0c;可以通过基于自然语言处理技术的模型、情景模型和语言模型来自动生成文章&#xff0c;甚至可以按照用户…

微服务电商平台课程七:前端框架vue

后台商城: https://github.com/macrozheng/mall-admin-web 前台商城:https://github.com/macrozheng/mall-app-web Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编…

seleniun 自动化程序,python编程 我监控 chrome debug数据后 ,怎么获取控制台的信息呢

python 好的&#xff0c;使用 Python 来监控 Chrome 的调试数据并获取控制台信息&#xff0c;可以使用 websocket-client 库来连接 Chrome 的 WebSocket 接口。以下是一个详细的示例&#xff1a; 1. 安装必要的库 首先&#xff0c;你需要安装 websocket-client 库。可以使用…