Flutter 2.0 的发布带来了很多的 break change
,特别是新增加的空声明安全,相信不少大哥尝鲜之后立马反思自己“手贱” ,事实上旧项目升级 Flutter 2.0 确实有很多兼容的点,但是“吃螃蟹”其实我们可以逐步拆解,比如“先蒸熟了再吃”?
其实正如《 Dart 2.12 发布,稳定空安全声明和FFI版本》 里所说,升级到 Flutter 2.0 并不会强制要求你马上使用空声明安全 ,所以我们可以把整个升级适配过程拆解几步来完成,最终完成 2.0 的升级适配。
首先你需要先将本地的 Flutter SDK 升级到 2.0 以上的版本,升级完成之后首先确保 Dart SDK 的 environment
小于 2.12.0
, 可以选中 2.10.0
之类的版本,如下所示的配置是不需要针对空声明安全进行适配,接下来我们就可以针对 SDK API 的 break change
先进行适配调整。
environment:
sdk: '>=2.10.0 <3.0.0'
首先你会应该遇到最多的应该是 List
对象的修改,因为 factory List
的函数已经被 Deprecated
,所以你需要使用 []
或者 List.filled
来替换你原有的实现,从这开始就是“体力活”了。
常见的还有 runZoned
的 onError
参数也被 Deprecated
,需要使用 runZonedGuarded
来替代。
一般使用
runZoned
的都是用于对Dart
层做错误信息收集。
Stack
控件的 overflow
参数也被 Deprecated
,需要替换为 clipBehavior
,比如以前的 Overflow.visible
可以修改为 Clip.none
,默认情况下是 Clip.hardEdge
。
FlatButton
也被标志为弃用,需要替换成 TextButton
;类似的 RaisedButton
需要替换为 ElevatedButton
。
这里主要需要注意的是: FlatButton
和 RaisedButton
上的 padding
、color
等方法现在需要使用 ButtonStyle
来设置。
类似的还有 Scaffold.of(builderContext).showSnackBar
方法需要替换为 ScaffoldMessenger.of(builderContext).showSnackBar
使用。
最后还有:
Scaffold
的 resizeToAvoidBottomPadding
参数正式取消,需要使用 resizeToAvoidBottomInset
参数替代。
Theme.of(context, shadowThemeOnly: true)
的 shadowThemeOnly
参数正式取消。
官方新增了 DateUtils
到 'package:flutter/material.dart'
里,可能会与你的项目里的 DateUtils
命名冲突。
Localizations.localeOf(context, nullOk: true)
和 MediaQuery.of(context, nullOk: true)
的 nullOk
参数正式取消。
大致上我遇到的 break change
或者弃用警告就是上面这些,调整完后在没有打开空安全配置的情况下,是可以正常运行的。
当然你也可能遇到:修改完后依旧无法运行的情况,因为还有第三方插件包依赖需要调整。
虽然 Flutter 2.0 没有要求主项目一定使用空声明安全,但是对于插件的适配要求却比价严格,所以你仍可能需要升级一些 pub 仓库的依赖来完成适配。
前提是祈祷你使用插件包有适配
null-safety
。
如图所示,正常支持 null-safety
的包在 pub 官网上是有 Null safety 的标签或者 nullsafety 的预览版本,这时候只要修改你的依赖版本,使用支持空声明安全的插件版本就可以了。
完了吗?明显没有!
因为大量的插件升级就可能带来版本冲突,比如 analyzer
版本冲突,在 json_serializable
和 built_value_generator
中他们分别依赖了不同的 analyzer
版本,所以会有版本冲突问题。
另外比如 build_runner
和 graphql
的版本之间存在 web_socket_channel
的冲突。
这些冲突要怎么解决呢?这里给大家展示使用 dependency_overrides
临时解决这些冲突。
如下图所示,可以看到在 dependency_overrides
下我强行使用了 analyzer: 1.1.0
和 web_socket_channel
,这样运行之后 analyzer
和 web_socket_channel
的版本会被强制指定,从而忽略冲突来解决无法运行的问题。
另外在我的
dependency_overrides
里可以看到很多带有#
的注解版本,这些版本都是在遇到冲突之后,为了成功运行一个个添加上去,之后在对应插件更新支持兼容后才注释掉。
添加了 dependency_overrides
之后运行会有 Warning
提示,这部分忽略就行了。
在完成上面两个步骤,项目应该就可以在 Flutter 2.0 上运行,那接下来就是把版本升级到空安全声明的支持,当然前提是你想要使用 null safety
。
升级到空安全声明,推荐使用官方的 dart migrate
命令,命令会生成一个可视化的界面,引导你将项目迁移到空安全声明,并且自动帮你覆盖代码。
如果你还有插件没有完全支持空安全声明,那么可以使用
dart migrate --skip-import-check
来完成迁移。
运行后可以看到一个链接,点击如图所示链接就可以打开引导界面,引导界面上可以看到每个文件会被修改位置和数量,你可以自己重新调整内容后点击刷新,或者直接点击 APPLY MIGRATION
按键,之后再到项目里进行修改。
相信我,修改后肯定会有一堆报错和警告,不要担心,这是正常的,接下来就是“体力活”了。
首先某些地方可能会被修改为如下图所示代码,你只需要对应修改回来就好,自动覆盖的脚本确实有些傻。
有时候某些 await
语法会被强行增加 as FutureOr
,如果你不需要改为原来的声明就可以。
还有比如 compute
方法中的 Function(_)
错误提示,只需要改为对应分参数传入,比如 Function(String? data)
就可以了。
有时候一些方法定义也会被强行修改,比如 redux
相关的这些修改可能也会影响运行问题,所以只需要把 as
部分去除就可以了。
而比如这类方法报错,一般就是提供的参数和使用参数对应不上,只需要添加上 ?
即可修复。
最后有时也会使用 !
来暂时完成适配,比如某个参数你确定不会为 null
,你可以在使用时通过 !
表示强行使用(就是任性不判空),比如下图就是对 _dragOffset
和 notification.scrollDelta
的强行修改对比。
可以看到这部分内容也是纯粹体力活,虽然自动覆盖的靠谱程度肯定不高,还是需要一定的人工修改,但是这个自动化过程大大提高了迁移的效率,而在代码覆盖之后,environment
的 sdk
也会自动修改为 >=2.12.0
。
空安全声明迁移完成!
最后,到这里你可能会发现,升级到 dart 1.12
之后,适配完 null safety
点 IDE 上的运行发现还是运行不起来,比如下图所示:
这是因为你还有没有迁移完成的依赖包,但是有时候依赖包不是一时半会就能兼容完成,这时候应该如何适配运行呢?
这时候就可以通过 flutter run --no-sound-null-safety
命令来运行调试项目,通过此命令运行的项目并不会使用空安全声明校验,然后通过输入 r
或者 R
等就可以完成 hotload
等调试操作。
如果需要 debug 代码或者性能调试,还可以通过 chrome
浏览器打开 http://localhost:9100
地址,然后把运行得到的 Observatory
地址如: http://127.0.0.1:62145/H1PrDXLbA3w=/
输入到 Connect 输入框,这样就可以打开 DartTools 进行调试。
最后不得不说, Flutter 2.0 算是 Flutter 新的起点,希望新的版本能给你们带来更稳定和更便捷的开发体验。