Flutter實戰(zhàn) 插件開發(fā):平臺通道簡介

2021-03-09 10:09 更新

“平臺特定”或“特定平臺”中的平臺指的就是Flutter應(yīng)用程序運行的平臺,如 Android 或 IOS。我們知道一個完整的 Flutter 應(yīng)用程序?qū)嶋H上包括原生代碼和Flutter代碼兩部分。由于 Flutter 本身只是一個 UI 系統(tǒng),它本身是無法提供一些系統(tǒng)能力,比如使用藍牙、相機、GPS 等,因此要在 Flutter APP 中調(diào)用這些能力就必須和原生平臺進行通信。為此,F(xiàn)lutter 中提供了一個平臺通道(platform channel),用于 Flutter 和原生平臺的通信。平臺通道正是 Flutter 和原生之間通信的橋梁,它也是 Flutter 插件的底層基礎(chǔ)設(shè)施。

Flutter 使用了一個靈活的系統(tǒng),允許您調(diào)用特定平臺的 API,無論在 Android 上的 Java 或 Kotlin 代碼中,還是 iOS 上的 ObjectiveC 或 Swift 代碼中均可用。 Flutter 與原生之間的通信依賴靈活的消息傳遞方式:

  • 應(yīng)用的 Flutter 部分通過平臺通道(platform channel)將消息發(fā)送到其應(yīng)用程序的所在的宿主(iOS 或 Android)應(yīng)用(原生應(yīng)用)。
  • 宿主監(jiān)聽平臺通道,并接收該消息。然后它會調(diào)用該平臺的 API,并將響應(yīng)發(fā)送回客戶端,即應(yīng)用程序的 Flutter 部分。

#平臺通道

使用平臺通道在 Flutter(client)和原生(host)之間傳遞消息,如下圖所示:

平臺通道

當(dāng)在Flutter中調(diào)用原生方法時,調(diào)用信息通過平臺通道傳遞到原生,原生收到調(diào)用信息后方可執(zhí)行指定的操作,如需返回數(shù)據(jù),則原生會將數(shù)據(jù)再通過平臺通道傳遞給 Flutter。值得注意的是消息傳遞是異步的,這確保了用戶界面在消息傳遞時不會被掛起。

在客戶端,MethodChannel API (opens new window)可以發(fā)送與方法調(diào)用相對應(yīng)的消息。 在宿主平臺上,MethodChannelAndroid API (opens new window)FlutterMethodChannel iOS API (opens new window)可以接收方法調(diào)用并返回結(jié)果。這些類可以幫助我們用很少的代碼就能開發(fā)平臺插件。

注意: 如果需要,方法調(diào)用(消息傳遞)可以是反向的,即宿主作為客戶端調(diào)用 Dart 中實現(xiàn)的 API。 quick_actions (opens new window)插件就是一個具體的例子。

#平臺通道數(shù)據(jù)類型支持

平臺通道使用標(biāo)準(zhǔn)消息編/解碼器對消息進行編解碼,它可以高效的對消息進行二進制序列化與反序列化。由于 Dart 與原生平臺之間數(shù)據(jù)類型有所差異,下面我們列出數(shù)據(jù)類型之間的映射關(guān)系。

Dart Android iOS
null null nil (NSNull when nested)
bool java.lang.Boolean NSNumber numberWithBool:
int java.lang.Integer NSNumber numberWithInt:
int, 如果不足32位 java.lang.Long NSNumber numberWithLong:
int, 如果不足64位 java.math.BigInteger FlutterStandardBigInteger
double java.lang.Double NSNumber numberWithDouble:
String java.lang.String NSString
Uint8List byte[] FlutterStandardTypedData typedDataWithBytes:
Int32List int[] FlutterStandardTypedData typedDataWithInt32:
Int64List long[] FlutterStandardTypedData typedDataWithInt64:
Float64List double[] FlutterStandardTypedData typedDataWithFloat64:
List java.util.ArrayList NSArray
Map java.util.HashMap NSDictionary

當(dāng)在發(fā)送和接收值時,這些值在消息中的序列化和反序列化會自動進行。

#自定義編解碼器

除了上面提到的MethodChannel,還可以使用BasicMessageChannel (opens new window),它支持使用自定義消息編解碼器進行基本的異步消息傳遞。 此外,可以使用專門的BinaryCodec (opens new window)、StringCodec (opens new window)JSONMessageCodec (opens new window)類,或創(chuàng)建自己的編解碼器。

#如何獲取平臺信息

Flutter 中提供了一個全局變量defaultTargetPlatform來獲取當(dāng)前應(yīng)用的平臺信息,defaultTargetPlatform定義在"platform.dart"中,它的類型是TargetPlatform,這是一個枚舉類,定義如下:

enum TargetPlatform {
  android,
  fuchsia,
  iOS,
}

可以看到目前 Flutter 只支持這三個平臺。我們可以通過如下代碼判斷平臺:

if(defaultTargetPlatform==TargetPlatform.android){
  // 是安卓系統(tǒng),do something
  ...
}
...

由于不同平臺有它們各自的交互規(guī)范,F(xiàn)lutter Material 庫中的一些組件都針對相應(yīng)的平臺做了一些適配,比如路由組件MaterialPageRoute,它在 android 和 ios 中會應(yīng)用各自平臺規(guī)范的切換動畫。那如果我們想讓我們的 APP 在所有平臺都表現(xiàn)一致,比如希望在所有平臺路由切換動畫都按照 ios 平臺一致的左右滑動切換風(fēng)格該怎么做?Flutter 中提供了一種覆蓋默認平臺的機制,我們可以通過顯式指定debugDefaultTargetPlatformOverride全局變量的值來指定應(yīng)用平臺。比如:

debugDefaultTargetPlatformOverride=TargetPlatform.iOS;
print(defaultTargetPlatform); // 會輸出TargetPlatform.iOS

上面代碼即在 Android 中運行后,F(xiàn)lutter APP 就會認為是當(dāng)前系統(tǒng)是 iOS,Material 組件庫中所有組件交互方式都會和 iOS 平臺對齊,defaultTargetPlatform的值也會變?yōu)?code>TargetPlatform.iOS。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號