关于Flutter空安全升级方案整理

前言

Flutter 从 2.0 版本开始支持空安全(Null Safety)。dart 版本为:

dart 复制代码
 environment:
  sdk: ">=2.12.0 < 3.0.0"

升级到空安全后,由于语法的变动,基本上整个工程,代码都爆红,这对项目来说简直是灾难性的打击,不升级的话只是缓兵之计,因为随着时间的推移,flutter将不再维护非空安全的版本,同时一些三方库也将无法使用,因此空安全升级变成了一个不得不做的事情,项目越复杂需要的时间也就越持久,考虑到对项目的稳定性,和开发周期。选择一个合适自己项目的迁移方案非常重要。下面自己会讲下自己对空安全迁移的理解和实施方案,目前成功迁移几个项目,还是比较有经验的。

语法变动

空安全升级后dart语法是存在很大的变化的,但是理念很简单即:万物皆可为空 ,和以往不同,现在任意创建一个对象都需要判断对象是否为空,这样在使用的时候,便明确知道这个对象是否可能为空,可以避免很多空指针的情况。
Dart 空安全的关键语法

1.不可空类型

在启用空安全的 Dart 中,默认情况下所有类型都是不可空的。这意味着一个变量声明后,不能为 null。例如:

dart 复制代码
int x = 42; // x 不能为 null

如果尝试将 null 赋值给不可空类型,编译器将会报错。

2.可空类型

如果一个变量可以是 null,则必须在类型后加上 ?。例如:

dart 复制代码
int? y = null; // y 可以是整数或 null

这种语法清晰地表明 y 是可空的,开发者在使用时必须考虑它可能为 null 的情况。

3.非空断言操作符 !

当你确定一个可空变量不为 null 时,可以使用 ! 操作符进行非空断言。例如:

dart 复制代码
int? a = 5;
int b = a!; // 断言 a 不为 null,安全地将其赋值给 b

使用 ! 操作符时要小心,因为如果断言错误(即变量实际上为 null),程序会抛出异常。因此对于不确定的变量尽量不要强制!

4.空合并操作符 ??

空合并操作符提供了一种为可空变量指定默认值的便捷方式。例如:

dart 复制代码
String? name;
String displayName = name ?? 'Guest'; // 如果 name 为 null,则使用 'Guest'

这种操作符在开发中是非常常用的,我们经常会通过??来给一些可为空的对象创建兜底值

5.late 变量

有时候我们明确知道这个对象一定是不会为null的但是再创建的时候拿不到值,便可以通过late 来延迟初始化这个对象

dart 复制代码
late String description;

void initialize() {
  description = 'Dart is fun!';
}

使用 late 声明的变量在首次使用前必须被初始化,否则将导致运行时错误。

空安全迁移

Flutter 官方提供了空安全迁移方案:使用dart migrate 工具可以借助该工具

在开始迁移之前,请确保做好以下准备工作:

升级 Dart SDK:确保你使用的 Dart SDK 版本是 2.12 或更高版本。可以通过 dart --version 检查当前的 Dart 版本。

更新依赖:确保项目中的所有依赖包都支持空安全。可以使用以下命令查看哪些包需要更新:

dart 复制代码
dart pub outdated --mode=null-safety

可以根据输出的日志将不支持空安全的版本升级或者替换

以上都完成后,便可以使用 dart migrate 来进行代码的替换了

dart migrate工具会为你构建迁移后的代码建议,并启动一个交互式的迁移网页界面。

dart 复制代码
View the migration suggestions by visiting:

  http://127.0.0.1:60278/Users/you/project/mypkg.console-simple?authToken=Xfz0jvpyeMI%3D

以上便可以通过dart migrate进行简单的迁移
手动迁移

真实的开发场景哪有这么理想,因此使用dart migrate对很多大型项目并不是很使用,并且使用dart migrate会大量的添加** !** 导致项目一堆异常,无法真正的运行起来。

另外也没有那么多时间,让项目进度停下来做空安全迁移。

因为我们做的方案是:创建一个支持空安全语法的module

dart 复制代码
//需要安卓和iOS模块
flutter create --template=plugin --org com.xxxx.xxx --platforms android --platforms ios --project-name aaa bbb
dart 复制代码
flutter create --template=plugin --org com.xxxx.xxxxx  --project-name aaaa bbbb

将创建好的工程以module的形式,依赖到主项目中,此方法不会打破项目的连续性,可以边迁移,边做需求开发。需要注意的是:

需要将主项目(非空安全)和子module(空安全)以相对路径的方式进行依赖因此需要修改pubspec.yaml 中的依赖方式

UT和覆盖率需要以下面的方式进行run

dart 复制代码
flutter test --no-sound-null-safety

在整体空安全都迁移完成后,再将项目移会去,这样边可以,一部分同时进行正常的需求开发,一部分同时进行空安全整改,最大化的提高工作效率。

当然在迁移过程中会涉及到import的问题,这里自己写了脚本,用于批量修改导包

dart 复制代码
#!/bin/sh

echo "修改工程导包"

# 修改对应的一级文件夹
CHANGEFILE="xxxx"


# 修改以package开头的导包
package_name="package:xxxxx\/$CHANGEFILE\/"
new_string=""
old_string="\.\.\/"
search_string="\.\.\/$CHANGEFILE"
old_import="$CHANGEFILE\/"
# 从主项目迁移到空安全路径修改导包路径名称
new_import="package:mobile_cn_null_safety\/$CHANGEFILE\/"

find . -name "*.dart"|while read fname; do

 echo "The string is found on line(s): $fname"
#package 开头导包
 if grep -q "$package_name" "$fname"; then
    # 使用grep查找字符串所在行
    package_line_number=$(grep -n "${package_name}" "$fname" | cut -d: -f1)
    # 遍历行号
    for each1 in $package_line_number
     do
       if [ -n "$each1" ];then
         sed -i  '' "${each1}s/${package_name}/${new_import}/g" "$fname"
       fi
     done

 fi


# 相对路径导包
  if grep -q "$search_string" "$fname"; then
      # 使用grep查找字符串所在行
      line_number=$(grep -n "${search_string}" "$fname" | cut -d: -f1)
      for each in $line_number
       do
         if [ -n "$each" ];then
           sed -i  '' "${each}s/${old_string}//g" "$fname"
           sed -i  '' "${each}s/${old_import}/${new_import}/g" "$fname"
         fi
       done

  fi
done

以上差不多便是全部内容。

相关推荐
江上清风山间明月16 小时前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能1 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人1 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen1 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-2 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11192 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
机器瓦力2 天前
Flutter应用开发:对象存储管理图片
flutter