手把手教你将项目迁移到Flutter2.0 空安全

Posted 一叶飘舟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手教你将项目迁移到Flutter2.0 空安全相关的知识,希望对你有一定的参考价值。

前言

  因为Flutter2.0已经出来很久了,空安全(Null-Safety)也说了好一阵了。但是就Flutter这个鬼德性,不敢动呀!虽然已上线的项目Flutter SDK已经跑在Flutter 2.0之上了,有问题的第三方库也已经更新了。但是它重点宣传的Null-safety没敢动。

  试了试“dart migrate --skip-import-check”命令来自动将项目迁移到空安全上,命令运行完,打开生成的链接,一万个草泥马飘过,几百个Change。哥惹不起,默默x掉了窗口。看着窗外,冷静了几分钟。不禁笑出了声,还好哥机智~
预知详情,请看下图:

    这是一次失败的尝试,让我耿耿于怀。以偶这个暴脾气,非得给你整个底掉儿~
  命运就是这样,机会如期而至。需要弄个新App,功能差不多定制版。全套代码就复制过来了。这不得跟你空安全掰掰手腕,完全没有线上p0的恐惧感~

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

  这种搞法就是既然Flutter升级了,那我需要使用2.0的SDK。但是呢,我又怕p0事故不想整空安全,那怎么办?

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

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

environment:
  sdk: ">=2.10.0 <3.0.0"

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

//升级Flutter
flutter upgrade

//查看flutter version
flutter --version

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

二、放大招,上真Flutter 2.0

  首先,我当然不是一马当先,上来就升级,搞搞搞,搞炸它~
毕竟我也是摸着官文过活,附上官方文档:https://dart.dev/null-safety/migration-guide

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

  首先检查当前Flutter版本

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以上

//❌错误配置
environment:
  sdk: '>=2.12.0 <3.0.0'

//✅正确配置
environment:
  sdk: '>=2.10.0 <3.0.0'

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

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

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

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

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

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

. 首先,我们要检查依赖库是否支持空安全

  使用以下命令获取包依赖项的迁移状态,它将告诉你哪些库是支持空安全的,如下图:

dart pub outdated --mode=null-safety

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

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

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

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

咱试一试~~

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

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

OKOK 咱耐着性子继续来试一试!
运行以上的命令结果告诉我,依赖冲突:

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

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

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

environment:
  sdk: ">=2.12.0 <3.0.0"

dependency_overrides:
  intl: 0.17.0
  ...

dependencies:
  flutter:
    sdk: flutter
  flustars: ^2.0.1
  ...

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

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.
So, because client depends on euma_calendar_v1 0.0.23, version solving failed.

说flustars这个库冲突了,欧拉,我们再依葫芦画瓢吧,

dependency_overrides:
  intl: 0.17.0
  flustars: 2.0.1

在我依葫芦画瓢N个之后,终于支持空安全的第三方库全部升级好了,大家不要被N吓到了,夸张手法

dependency_overrides:
#  intl: 0.17.0
#  flustars: 2.0.1
#  path_provider: 2.0.2
#  crypto: 3.0.1
#  convert: 3.0.0
#  json_serializable: 4.1.3
#  json_annotation: 4.0.1
#  dio: 4.0.0
#  timezone: 0.7.0
#  sqflite: 2.0.0+3
#  file: 6.1.1
#  flutter_cache_manager: 3.1.0
#  archive: 3.1.2

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

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

2.4 迁移项目代码到空安全

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

//优先使用
dart migrate

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

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

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

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

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

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

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

Before:
R runZoned<R>(R body(),
        Map<Object?, Object?>? zoneValues,
        ZoneSpecification? zoneSpecification,
        @Deprecated("Use runZonedGuarded instead") Function? onError)

After:
R? runZonedGuarded<R>(R body(), void onError(Object error, StackTrace stack),
                Map<Object?, Object?>? zoneValues, ZoneSpecification? zoneSpecification)

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

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

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

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

2.5 空安全跑起来

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

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

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

命令行方式:

dart –no-sound-null-safety run
flutter run –no-sound-null-safety

Android Studio方式:

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

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

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

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

遇到的问题:

类似于

FAILURE: Build failed with an exception.                                
                                                                        
* What went wrong:                                                      
Execution failed for task ':app:lintVitalRelease'.                      
> Could not resolve all artifacts for configuration ':app:debugRuntimeClasspath'.
   > Failed to transform libs.jar to match attributes artifactType=processed-jar, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime.
      > Execution failed for JetifyTransform: /Users/michaelbui/Projects/counter/build/app/intermediates/flutter/debug/libs.jar.
         > 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.)
           Please file a bug at http://issuetracker.google.com/issues/new?component=460323.
                                                                        
* Try:                                                                  
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.
                                                                        
* 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

android
    lintOptions 
        checkReleaseBuilds false
    

三、结语

  Flutter2.0 空安全迁移是迁移完了,后面可以升级SDK了。但是运行后报奇奇怪怪问题就再说了,遇到了就解决掉.

以上是关于手把手教你将项目迁移到Flutter2.0 空安全的主要内容,如果未能解决你的问题,请参考以下文章

手把手教你从http免费迁移到https

手把手教你将小程序项目跑起来真自律小程序

手把手教你将H5游戏打包为快游戏

5G核心网手把手教你将Open5gs托管到k8s(KubeSphere)

5G核心网手把手教你将Open5gs托管到k8s(KubeSphere)

5G核心网手把手教你将Open5gs托管到k8s(KubeSphere)