Flutter 2.0 的發(fā)布帶來(lái)了很多的 break change ,特別是新增加的空聲明安全,相信不少大哥嘗鮮之后立馬反思自己“手賤” ,事實(shí)上舊項(xiàng)目升級(jí) Flutter 2.0 確實(shí)有很多兼容的點(diǎn),但是“吃螃蟹”其實(shí)我們可以逐步拆解,比如“先蒸熟了再吃”?
其實(shí)正如《 Dart 2.12 發(fā)布,穩(wěn)定空安全聲明和FFI版本》 里所說(shuō),升級(jí)到 Flutter 2.0 并不會(huì)強(qiáng)制要求你馬上使用空聲明安全 ,所以我們可以把整個(gè)升級(jí)適配過(guò)程拆解幾步來(lái)完成,最終完成 2.0 的升級(jí)適配。
1、針對(duì) API 的調(diào)整
首先你需要先將本地的 Flutter SDK 升級(jí)到 2.0 以上的版本,升級(jí)完成之后首先確保 Dart SDK 的 environment 小于 2.12.0 , 可以選中 2.10.0 之類的版本,如下所示的配置是不需要針對(duì)空聲明安全進(jìn)行適配,接下來(lái)我們就可以針對(duì) SDK API 的 break change 先進(jìn)行適配調(diào)整。
environment:
sdk: '>=2.10.0 <3.0.0'
首先你會(huì)應(yīng)該遇到最多的應(yīng)該是 List 對(duì)象的修改,因?yàn)?factory List 的函數(shù)已經(jīng)被 Deprecated ,所以你需要使用 [] 或者 List.filled 來(lái)替換你原有的實(shí)現(xiàn),從這開始就是“體力活”了。
常見的還有 runZoned 的 onError 參數(shù)也被 Deprecated ,需要使用 runZonedGuarded 來(lái)替代。
一般使用
runZoned的都是用于對(duì)Dart層做錯(cuò)誤信息收集。
Stack 控件的 overflow 參數(shù)也被 Deprecated ,需要替換為 clipBehavior,比如以前的 Overflow.visible 可以修改為 Clip.none ,默認(rèn)情況下是 Clip.hardEdge。
FlatButton 也被標(biāo)志為棄用,需要替換成 TextButton;類似的 RaisedButton 需要替換為 ElevatedButton 。
這里主要需要注意的是: FlatButton 和 RaisedButton 上的 padding、color 等方法現(xiàn)在需要使用 ButtonStyle 來(lái)設(shè)置。
類似的還有 Scaffold.of(builderContext).showSnackBar 方法需要替換為 ScaffoldMessenger.of(builderContext).showSnackBar 使用。
最后還有:
Scaffold的resizeToAvoidBottomPadding參數(shù)正式取消,需要使用resizeToAvoidBottomInset參數(shù)替代。Theme.of(context, shadowThemeOnly: true)的shadowThemeOnly參數(shù)正式取消。官方新增了
DateUtils到'package:flutter/material.dart'里,可能會(huì)與你的項(xiàng)目里的DateUtils命名沖突。
-
Localizations.localeOf(context, nullOk: true)和MediaQuery.of(context, nullOk: true)的nullOk參數(shù)正式取消。
大致上我遇到的 break change 或者棄用警告就是上面這些,調(diào)整完后在沒有打開空安全配置的情況下,是可以正常運(yùn)行的。
當(dāng)然你也可能遇到:修改完后依舊無(wú)法運(yùn)行的情況,因?yàn)檫€有第三方插件包依賴需要調(diào)整。
2、針對(duì)依賴倉(cāng)庫(kù)的調(diào)整
雖然 Flutter 2.0 沒有要求主項(xiàng)目一定使用空聲明安全,但是對(duì)于插件的適配要求卻比價(jià)嚴(yán)格,所以你仍可能需要升級(jí)一些 pub 倉(cāng)庫(kù)的依賴來(lái)完成適配。
前提是祈禱你使用插件包有適配
null-safety。
如圖所示,正常支持 null-safety 的包在 pub 官網(wǎng)上是有 Null safety 的標(biāo)簽或者 nullsafety 的預(yù)覽版本,這時(shí)候只要修改你的依賴版本,使用支持空聲明安全的插件版本就可以了。
完了嗎?明顯沒有!
因?yàn)榇罅康牟寮?jí)就可能帶來(lái)版本沖突,比如 analyzer 版本沖突,在 json_serializable 和 built_value_generator 中他們分別依賴了不同的 analyzer 版本,所以會(huì)有版本沖突問(wèn)題。
另外比如 build_runner 和 graphql 的版本之間存在 web_socket_channel 的沖突。
這些沖突要怎么解決呢?這里給大家展示使用 dependency_overrides 臨時(shí)解決這些沖突。
如下圖所示,可以看到在 dependency_overrides 下我強(qiáng)行使用了 analyzer: 1.1.0 和 web_socket_channel ,這樣運(yùn)行之后 analyzer 和 web_socket_channel 的版本會(huì)被強(qiáng)制指定,從而忽略沖突來(lái)解決無(wú)法運(yùn)行的問(wèn)題。
另外在我的
dependency_overrides里可以看到很多帶有#的注解版本,這些版本都是在遇到?jīng)_突之后,為了成功運(yùn)行一個(gè)個(gè)添加上去,之后在對(duì)應(yīng)插件更新支持兼容后才注釋掉。
添加了 dependency_overrides 之后運(yùn)行會(huì)有 Warning 提示,這部分忽略就行了。
3、針對(duì)空聲明安全的調(diào)整
在完成上面兩個(gè)步驟,項(xiàng)目應(yīng)該就可以在 Flutter 2.0 上運(yùn)行,那接下來(lái)就是把版本升級(jí)到空安全聲明的支持,當(dāng)然前提是你想要使用 null safety 。
升級(jí)到空安全聲明,推薦使用官方的 dart migrate 命令,命令會(huì)生成一個(gè)可視化的界面,引導(dǎo)你將項(xiàng)目遷移到空安全聲明,并且自動(dòng)幫你覆蓋代碼。
如果你還有插件沒有完全支持空安全聲明,那么可以使用
dart migrate --skip-import-check來(lái)完成遷移。
運(yùn)行后可以看到一個(gè)鏈接,點(diǎn)擊如圖所示鏈接就可以打開引導(dǎo)界面,引導(dǎo)界面上可以看到每個(gè)文件會(huì)被修改位置和數(shù)量,你可以自己重新調(diào)整內(nèi)容后點(diǎn)擊刷新,或者直接點(diǎn)擊 APPLY MIGRATION 按鍵,之后再到項(xiàng)目里進(jìn)行修改。
相信我,修改后肯定會(huì)有一堆報(bào)錯(cuò)和警告,不要擔(dān)心,這是正常的,接下來(lái)就是“體力活”了。
首先某些地方可能會(huì)被修改為如下圖所示代碼,你只需要對(duì)應(yīng)修改回來(lái)就好,自動(dòng)覆蓋的腳本確實(shí)有些傻。
有時(shí)候某些 await 語(yǔ)法會(huì)被強(qiáng)行增加 as FutureOr ,如果你不需要改為原來(lái)的聲明就可以。
還有比如 compute 方法中的 Function(_) 錯(cuò)誤提示,只需要改為對(duì)應(yīng)分參數(shù)傳入,比如 Function(String? data) 就可以了。
有時(shí)候一些方法定義也會(huì)被強(qiáng)行修改,比如 redux 相關(guān)的這些修改可能也會(huì)影響運(yùn)行問(wèn)題,所以只需要把 as 部分去除就可以了。
而比如這類方法報(bào)錯(cuò),一般就是提供的參數(shù)和使用參數(shù)對(duì)應(yīng)不上,只需要添加上 ? 即可修復(fù)。
最后有時(shí)也會(huì)使用 ! 來(lái)暫時(shí)完成適配,比如某個(gè)參數(shù)你確定不會(huì)為 null,你可以在使用時(shí)通過(guò) ! 表示強(qiáng)行使用(就是任性不判空),比如下圖就是對(duì) _dragOffset 和 notification.scrollDelta 的強(qiáng)行修改對(duì)比。
可以看到這部分內(nèi)容也是純粹體力活,雖然自動(dòng)覆蓋的靠譜程度肯定不高,還是需要一定的人工修改,但是這個(gè)自動(dòng)化過(guò)程大大提高了遷移的效率,而在代碼覆蓋之后,environment 的 sdk 也會(huì)自動(dòng)修改為 >=2.12.0 。
空安全聲明遷移完成!
4、針對(duì)遷移中運(yùn)行的調(diào)整
最后,到這里你可能會(huì)發(fā)現(xiàn),升級(jí)到 dart 1.12之后,適配完 null safety 點(diǎn) IDE 上的運(yùn)行發(fā)現(xiàn)還是運(yùn)行不起來(lái),比如下圖所示:
這是因?yàn)槟氵€有沒有遷移完成的依賴包,但是有時(shí)候依賴包不是一時(shí)半會(huì)就能兼容完成,這時(shí)候應(yīng)該如何適配運(yùn)行呢?
這時(shí)候就可以通過(guò) flutter run --no-sound-null-safety 命令來(lái)運(yùn)行調(diào)試項(xiàng)目,通過(guò)此命令運(yùn)行的項(xiàng)目并不會(huì)使用空安全聲明校驗(yàn),然后通過(guò)輸入 r 或者 R 等就可以完成 hotload 等調(diào)試操作。
如果需要 debug 代碼或者性能調(diào)試,還可以通過(guò) chrome 瀏覽器打開 http://localhost:9100 地址,然后把運(yùn)行得到的 Observatory 地址如: http://127.0.0.1:62145/H1PrDXLbA3w=/ 輸入到 Connect 輸入框,這樣就可以打開 DartTools 進(jìn)行調(diào)試。
最后不得不說(shuō), Flutter 2.0 算是 Flutter 新的起點(diǎn),希望新的版本能給你們帶來(lái)更穩(wěn)定和更便捷的開發(fā)體驗(yàn)。