0%

Flutter Web Migration - Package跨平台兼容性

打開Flutter web開發的方法並不困難,但在將手機app轉換(migration)到web app時會遇到許多轉換問題。在Flutter Engage的發佈會上官方有特別展示web migration要注意的地方。而使用Flutter開發跨平台應用程式時,第一個要考量到的就是package的跨平台兼容性。

使用pub.dev確認package兼容性

為了確保使用到的package在所有的平台都能正常的執行,專案在評估採用package時就必須確認是否兼容所有要發佈的平台,或是未來可能會發佈的平台。

剛起頭的專案在pub.dev尋找可採用的package時,就可以邊從資訊頁上方找到平台支援資訊。如果是從mobile轉移到web,就建議要掃過所有使用到的package,當然也可以直接把web app在debug模式跑起來就知道哪些不能用了。

dart:io不支援web的解決方法

dart:io可以協助處理File、Socket、HTTP與其他I/O任務,官方的Web FAQdart:io api都有特別寫到dart:io是不支援web app的。自己的經驗有遇過以下兩種情況有使用到dart:io須要特別注意:

1. 使用http處理http request

有些專案會使用dart:io的HttpClient處理跟Http server之間的request與response。但因為dart:io不支援web平台,所以官方建議使用http進行跨平台的http處理,在開發時也可以參考官方的Networking Cookbook有詳細的介紹。

2. 使用universal_platform檢查運行平台

一般跨平台專案會使用dart:io.Platform判斷當前的運行平台,但dart:io.Platform並不支援web,所以在運行於web環境時會出現Unsupported operation: Platfor._operationSystem錯誤。

1
2
3
4
5
6
7
8
9
import 'dart:io' show Platform;

if (Platform.isAndroid) {
// Do something on Android
} else if (Platform.isIOS) {
// Do something on iOS
} else {
// I want do something on web, but I only get Unsupported operation: Platform._operatingSystem
}

考量到web的情境下,另一個方法可以使用kIsWeb再搭配Theme.of與TargetPlatform就可以達到避開使用dart:io.Platform又能夠在建立widget時判斷當下的運行平台。

1
2
3
4
5
6
7
8
9
10
import 'package:flutter/foundation.dart' show kIsWeb, TargetPlatform;

final platform = Theme.of(context).platform;
if (kIsWeb) {
// Do something on Web
} else if (platform == TargetPlatform.android) {
// Do something on Android
} else if (platform == TargetPlatform.iOS) {
// Do something on iOS
}

但比較適合的方法為採用conditional import來解決。當dart:io能被import時採用dart:io.Platform判斷運行平台,無法被import的情況下判定為web。這種方式因為已經有被實作過了(universal_platform),所以可以考慮不用再自己實作。

使用conditional import在不同平台上運行不同程式片段

如果真的有一個重要的功能,但又不支援web該怎麼辦?像是上面提到只在mobile使用dart:io判斷運行平台,或是須要在mobile上用dart:io的HttpClient處理proxy問題,然後在web單純使用http處理與server的溝通。

若無法確保package跨平台兼容,相同feature在不同平台上要執行不同程式片段時,較簡單的方法是使用上述提到的平台判斷。例如使用universal_platform判斷當下運行的平台後,再執行於不同平台要執行的函式或是widget。

1
2
3
4
5
6
7
8
9
10
11
import 'package:universal_platform/universal_platform.dart';
import 'dart:js' // web platform need this, but it will cause Not Found Error on Android/iOS


if (UniversalPlatform.isWeb) {
// Do something or render widget on Web
} else if (UniversalPlatform.isAndroid) {
// Do something or render widget on Android
} else if (UniversalPlatform.isIOS) {
// Do something or render widget on iOS
}

但如果功能複雜度高且程式碼又很長的話,程式片段會變很長易讀性也會變差。另外若使用到只有web能用的package,也會造成在其他平台compile階段出現錯誤。這時會建議將不同平台要執行的程式片段拆成不同dart,並使用conditional import在開頭就決定要import哪個dart進來使用。

import “web_support_func.dart” if (dart.library.io) “non_web_support_func.dart”

以上是進行web migration馬上會遇到的跨平台兼容問題,除了專案本身使用到的第三方package可能不支援web平台外,要特別注意因為dart:io不支援web引發的http request還有platform判斷問題。如果真的有feature要在不同平台執行不同程式片段時,建議使用conditional import來設計程式碼。