likes
comments
collection
share

Flutter NullSafety工程迁移兼容问题解决

作者站长头像
站长
· 阅读数 93

一文解决Flutter NullSafety工程兼容问题

1. 背景

Dart语言在2.12以上开始实现NullSafety空安全功能,因此在Flutter工程开启Null Safety需指定Dart版本>=2.12.0 , 当然指定<2.12以下可以关闭NullSafety;

environment:
  sdk: ">=2.12.0 <3.0.0"

迁移NullSafety有什么优势呢?

  • Dart/Flutter社区绝大多数pub库已经都迁移至NullSafery,开启空安全属于一种趋势;

  • 更简约代码进行判空逻辑处理,实现更优质代码,比如如下代码会直接提示错误,因为controller可能为null,这保证在使用时避免出现null情况;

 ScrollController controller;
 controller.position;
  • 系统针对非空对象进行编译优化,具备更快的运行速度;

迁移过程会遇到的问题:

  • 空安全开启后主仓库/插件等迁移的兼容性问题;
  • 空安全开启后单测能力实现的兼容性问题;

2. Null Safety 优雅代码

  • 编译期提示报错

      String name;
      print('name is $name.');
    

    开启空安全后上述代码无法编译通过,在非空安全代码下这段代码是可正常编译通过的,提升代码健壮性;

  • ! 操作符

    String? name;
    
    void main() {
      setName();
      if (name!.isNotEmpty) {
        print('name = ${name.toString()}');
      }
    }
    
    void setName() {
      name = 'marry';
    }
    

    确定对象使用时非空,可以在表达式添加!,保证后续都不需要写判空条件;

  • late 延迟确定某个对象不为空

    class _ListWidgetState extends State<ListWidget> {
    
      late ScrollController controller;
    
      @override
      void initState() {
        controller = ScrollController();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return ListView(
          controller: controller,
          children: [],
        );
      }
    }
    

    如上,开始controller时一个空的对象,但是当使用它时必须保证非空,此时可以使用late关键字表示对象在时候时必须为非空对象,避免写判空条件;

  • 集合条件判空条件

    在非空安全dart版本,List/Set/Map中集合可能存在null元素,需要在遍历过程剔除后使用,但是升级空安全版本后,可以List使用元素无法在插入空元素;如果想在List集合插入空元素需使用List<String?>,对比List? list则表示list集合可能时空;

3. 工程兼容问题解决

3.1 lib模块迁移空安全遇到的兼容性问题大致会分为如下几类:

  • 主仓库开启空安全,而插件未兼容空安全运行
Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:

 - package:intl

遇到这种情况可以使用flutter run --no-sound-null-safety方式执行代码即可

  • 主仓库未开启空安全,拆分module模块或插件先支持了空安全:这种模式运行应该是没有任何问题的,空安全可向下兼容非空安全代码;

  • 代码仓库过大,想开启空安全代码,但是不想动旧代码,只想将特性应用在新代码上:

    这个应该是实际开发遇到的最多场景,遇到较大工程模块时,很多开发没有精力做迁移工作,那可不可以开启空安全后混编模式运行呢?经测试发现,只需要将没有实现空安全的文件开头添加@dart = xxx如下代码即可:

    // @dart = 2.9
    
    import 'package:flutter/material.dart';
    
    class ListDemo extends StatefulWidget {
      const ListDemo({Key key}) : super(key: key);
    
      @override
      State<ListDemo> createState() => _ListDemoState();
    }
    

    如上,我指定dart版本号为2.9运行环境,当dart<2.12时空安全相关功能即失效,这样就可以实现混合空安全和非空安全模式开发;因此实现一个python脚本将旧模块代码一次性添加dart版本注释就可以暂时开启空安全;

3.2 单测模块迁移问题大致分为如下几种

  • 开启空安全后的单测代码会遇到如下问题:

    Error: Cannot run with sound null safety, because the following dependencies
    don't support null safety:
    
     - package:intl
    

    这里碰到插件依赖非空安全库执行问题不能和上面仓库代码迁移类似执行flutter run --no-sound-null-safety绕过,主要原因是因为flutter test不支持--no-sound-null-safety命令执行,因此只能在单测模块指定@dart = xxxx版本号,将空安全功能关闭,目前暂未发现其他解决方案;

  • 开启安全后可能会遇到dart版本号注释指定冲突问题:

    57aa4681533c35fd526e75c0f98d7db906ceefaa/lib/src/messages.dart:4:1: Error: A library can't opt out of null safety by default, when using sound null safety.
    // @dart = 2.8
    ^^^^^^^^^^^^^^
    

    这个主要是多个版本dart注释版本冲突引起,你只需要将test环境下的dart版本稍微比冲突的版本大于等于即可;

4. 总结

空安全是一个好东西,可以减少很多非必要的判空条件,保证代码健壮性,同时提升代码可读性,使得代码更加优雅;本文主要介绍空安全优势同时在迁移空安全过程发现的一个问题,记录描述空安全迁移过程中一些需要兼容的问题,希望对大家有所帮助;

转载自:https://juejin.cn/post/7136886789683281957
评论
请登录