一、Flutter2.0兼容版(假Flutter2.0)

直接升级Flutter2.0,跑一跑工程修改升级几个有问题的第三方库就可以了。

只要你的dart版本最低不大于:>=2.12.0就好了

  1. environment:
  2. sdk: ">=2.10.0 <3.0.0"


升级Fultter 2.0SDK可以去官网下载Sdk,也可以直接通过命令升级

  1. //升级Flutter
  2. flutter upgrade
  3. //查看flutter version
  4. flutter --version


但是,这毕竟是个假2.0,就这样一笔带过吧~

二、放大招,上真Flutter 2.0

附上官方文档:https://dart.dev/null-safety/migration-guide

2.1 升级Flutter到2.0,和前面的是一样的
  

首先检查当前Flutter版本

  1. flutter version


如果在flutter 2.0以下,将flutter升级到2.0。使用命令flutter upgrade在原有1.0上升级或者去官网下载flutter 2.0 SDK解压配置环境等。

Flutter升级到2.0以后,flutter并没有强制你的应用就必须马上使用空安全,这样的话我们不需要修改在pubspec.yaml中的sdk设置在2.12.0以上

  1. //❌错误配置
  2. environment:
  3. sdk: '>=2.12.0 <3.0.0'
  4. //✅正确配置
  5. environment:
  6. sdk: '>=2.10.0 <3.0.0'


如果设置>=2.12.0,那么Dart分析器将会去检查空安全,那么恭喜你会看到一片红海。

2.2 检测哪些依赖库支持空安全

官方是的升级说明呢:因为第三方库肯定是有依赖关系的,如图
image.png


  官网的建议是:我们强烈建议按顺序迁移代码,首先迁移依赖图的叶子。例如,如果包 C 依赖于包 B,而包 B 又依赖于包 A,那么 A 应该先迁移到空安全,然后是 B,然后是 C。

但是这样的话,貌似很不好操作,有时候第三方库虽然依赖某个库,但是我们项目又没有,不可能我一个个又给它加到pubspec.yaml文件中,这不现实。

莫急~ 我们就不按官方来了,开始我们的骚操作吧。

. 首先,我们要检查依赖库是否支持空安全
  使用以下命令获取包依赖项的迁移状态,它将告诉你哪些库是支持空安全的,如下图2.3.1:

  1. dart pub outdated --mode=null-safety


image.png
  
上图Current列代表你项目的当前版本,Latest代表最新的版本,绿色代表这个依赖库已经支持空安全了,比个二✌️,红色的就GG了,不支持空安全。当然现在在pub.dev上的库基本上都支持空安全了。还有不支持的,那你也可以放弃使用了,因为它估计基本不维护了😅。

2.3 迁移第三方库到空安全版本
  

因为我们用“dart pub upgrade —mode=null-safety”,检测第三方库支持空安全的情况。发现很多库暂时还没支持,怎么办呢?那我们可不可以先升级支持空安全的库呢?那当然是没问题的。看到下图2.3.1:

image.png

实际上,它也告诉我们通过“dart pub update —null-safety —dry-run”命令去输出原因并升级。

咱试一试~~

如图

image.png


它解释了有哪几个库不支持空安全,然后告诉我们可以用以下命令升级支持空安全的第三方库:

  1. dart pub upgrade --nullsafety flustars uuid fluro photo_manager json_annotation video_player webview_flutter json_serializable dio photo_view video_thumbnail path_provider device_info shared_preferences cached_network_image flutter_rating_bar extended_text cupertino_icons build_runner graphql_flutter firebase_database rxdart flutter_keyboard_visibility connectivity flutter_screenutil flutter_svg url_launcher amplitude_flutter intl firebase_core smartlook event_bus firebase_auth permission_handler app_review test back_button_interceptor

运行以上的命令结果告诉我,依赖冲突:

  1. Because client depends on euma_calendar_v1 0.0.23 which depends on intl ^0.16.1, intl ^0.16.1 is required.
  2. So, because client depends on intl >=0.17.0-nullsafety.2, version solving failed.


因为不同库依赖的intl版本不一致导致了冲突,那么我们得解决它才能继续往下走,如何解决?很简单

在pubspec.yaml文件中dependency_overrides下添加支持空安全的intl版本,给它强指定!

  1. environment:
  2. sdk: ">=2.12.0 <3.0.0"
  3. dependency_overrides:
  4. intl: 0.17.0
  5. ...
  6. dependencies:
  7. flutter:
  8. sdk: flutter
  9. flustars: ^2.0.1
  10. ...


这里我们使用dependency_overrides来强行指定依赖库版本。以为这样世界就该安静了,可还是太年轻,接着运行上面的upgrade命令,又给我报了另一个依赖错误:

  1. Because every version of euma_calendar_v1 depends on flustars ^0.3.3 and client depends on flustars >=2.0.0, euma_calendar_v1 is forbidden.
  2. So, because client depends on euma_calendar_v1 0.0.23, version solving failed.

说flustars这个库冲突了

  1. dependency_overrides:
  2. intl: 0.17.0
  3. flustars: 2.0.1


在我依葫芦画瓢N个之后,终于支持空安全的第三方库全部升级好了

  1. dependency_overrides:
  2. # intl: 0.17.0
  3. # flustars: 2.0.1
  4. # path_provider: 2.0.2
  5. # crypto: 3.0.1
  6. # convert: 3.0.0
  7. # json_serializable: 4.1.3
  8. # json_annotation: 4.0.1
  9. # dio: 4.0.0
  10. # timezone: 0.7.0
  11. # sqflite: 2.0.0+3
  12. # file: 6.1.1
  13. # flutter_cache_manager: 3.1.0
  14. # archive: 3.1.2

这里这些强指定的库都注释掉了,因为这里其实是一个临时存储类似的概念,先强指定,为了升级第三方库。等所有的第三库都升级成功了之后,这里就可以慢慢干掉了。我都干完了~

之后你还可以用“dart pub outdated —mode=null-safety”来检测一下是否所有库都已经升级到空安全版本,如果有一些pub.dex库没有支持空安全,那么我们就寻找替代的库。如果是自己的私有第三方库,那就自己先升级第三方库支持空安全,和本篇文章是大同小异的。
全部升级好了会提示

如图:

image.png


2.4 迁移项目代码到空安全
  

前期准备工作包括Dart升级,第三方库升级我们都做好了,接下来就来到了最重要的环节,使用以下命令迁移项目代码到空安全:

  1. //优先使用
  2. dart migrate
  3. //上面命令报错了的话,使用
  4. //说明你还有插件没有完全支持空安全声明,使用以下命令迁移
  5. dart migrate --skip-import-check


运行命令后,会提供给你一个连接,点击连接进入一个迁移前后对比的网页,

如图
image.png

应该会有惊喜又名惊吓,几百条改动。你可以在这里查看和修改,也可以直接APPLY MIGRATION接受迁移改动,这样的话,迁移的代码改动就到工程了。

你以为这样就皆大欢喜了吗?放心好了,Flutter从不讲武德,还是会有很多爆红的,这你就得一处处去修改了。这里列几个常见的问题吧

List 对象的修改

因为 factory List 的函数已经被 Deprecated ,所以你需要使用 [] 或者 List.filled 来替换你原有的实现,从这开始就是“体力活”了。

  1. List list = List(); => List list = [];


runZoned 的废弃

runZoned 的 onError 参数也被 Deprecated ,需要使用 runZonedGuarded 来替代
(runZoned一般都是用于对Dart层做错误信息收集用的)

  1. Before:
  2. R runZoned<R>(R body(),
  3. {Map<Object?, Object?>? zoneValues,
  4. ZoneSpecification? zoneSpecification,
  5. @Deprecated("Use runZonedGuarded instead") Function? onError})
  6. After:
  7. R? runZonedGuarded<R>(R body(), void onError(Object error, StackTrace stack),
  8. {Map<Object?, Object?>? zoneValues, ZoneSpecification? zoneSpecification})

Stack 的修改

Stack 控件的 overflow 参数也被 Deprecated ,需要替换为 clipBehavior,比如以前的 Overflow.visible 可以修改为 Clip.none ,默认情况下是 Clip.hardEdge
image.png

FlatButton的废弃

FlatButton 也被标志为弃用,需要替换成 TextButton;(padding、color等参数需要使用ButtonStyle来设置)

image.png

image.png

InterceptorsWrapper的改动

5、Dio的新版本InterceptorsWrapper和以前的不一样了需要做相应的改动

大概主要就这些了,其他的还有一些零零碎碎其实占主力军的,是一些加?或者其他判断可空非空逻辑,这得看具体逻辑做相应修改了,因为dart tool在做迁移的时候可能比较笨,没有很友好的转化,但是编译器检测出来了。就给爆红了。这块基本是体力活和干死脑细胞运动。慢慢来吧~ 等爆红全部消除的时候,来到下一节。
(这里注意的是:有可能编译期静态检测空安全并没有啥问题了,但是运行期有报错说null啥啥啥的问题,基本是空安全的问题,说明有得地方还是没覆盖到,在去逐个改吧,碰上了就改下)

2.5 空安全跑起来
  

看似经历了上面几个步骤,感觉没啥问题了,可以跑一跑了吧。
其实用”dart analyze”和”dart test” , dart的分析和测试命令来检测是否项目真正适配了空安全,这里略过,大家可以试试,一般是Warning,大家看着改吧,不影响运行。

到这,大家可以在Android Studio或者命令行运行项目看一看耗死我们无数个脑细胞的玩意到底能不能跑了。

如果跑起来了呢,那么恭喜恭喜~ 没跑起来多半是有一些依赖库,或者是自己私有库还没完全支持空安全。也不用急着马上升级才能跑。Dart还是留了后手,有一种混合模式可以跑起来

命令行方式:

  1. dart no-sound-null-safety run
  2. flutter run no-sound-null-safety

Android Studio方式:
image.png

那么这种的话就有个弊端,因为有时候Android Studio对编译跑iOS不是很友好,有时候跑不起了,跑得又慢就可以用xcode。那样快很多,这时候的话就没办法用Xcode跑了。所以,还是最好全迁空安全。

使用“–no-sound-null-safety”,我验证了能用命令行打包和运行。

因为我自己本身也是前边有私有库,没有吧库全部迁移到空安全版本,也就是说有几个库暂时不支持空安全,所有我就加了这个参数跑。后来也吧私有库升级了,就可以去掉这个参数了。

PS: 这里提一个全迁后Android打包遇到的问题,其实不是全迁的问题。后来查到是因为龟儿子将gradle从gradle-5.6.2-all升级了gradle-6.5-bin的问题,后来两种gradle版本都解决了。

遇到的问题:
类似于

  1. FAILURE: Build failed with an exception.
  2. * What went wrong:
  3. Execution failed for task ':app:lintVitalRelease'.
  4. > Could not resolve all artifacts for configuration ':app:debugRuntimeClasspath'.
  5. > Failed to transform libs.jar to match attributes {artifactType=processed-jar, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
  6. > Execution failed for JetifyTransform: /Users/michaelbui/Projects/counter/build/app/intermediates/flutter/debug/libs.jar.
  7. > Failed to transform '/Users/michaelbui/Projects/counter/build/app/intermediates/flutter/debug/libs.jar' using Jetifier. Reason: FileNotFoundException, message: /Users/michaelbui/Projects/counter/build/app/intermediates/flutter/debug/libs.jar (No such file or directory). (Run with --stacktrace for more details.)
  8. Please file a bug at http://issuetracker.google.com/issues/new?component=460323.
  9. * Try:
  10. 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.
  11. * Get more help at https://help.gradle.org


解决方案:
第一种:不做修改将gradle版本降回gradle-5.6.2-all

第二种:在app/build.gradle中加入以下代码可解决:github issue链接:https://github.com/flutter/flutter/issues/58247

  1. android{
  2. lintOptions {
  3. checkReleaseBuilds false
  4. }
  5. }


三、结语
  Flutter2.0 空安全迁移是迁移完了,后面可以妥妥的升级SDK了。但是运行后报奇奇怪怪问题就再说了,遇到了就解决掉O(∩_∩)O哈哈

申明:禁用于商业用途,如若转载,请附带原文链接。https://www.jianshu.com/p/e2a5fedb4e22蟹蟹~

作者:天上飘的是浮云
链接:http://events.jianshu.io/p/a9d49fe637ba