Flutter實(shí)戰(zhàn) 插件開發(fā):平臺(tái)通道簡(jiǎn)介

2021-03-09 10:09 更新

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

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

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

#平臺(tái)通道

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

平臺(tái)通道

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

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

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

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

平臺(tái)通道使用標(biāo)準(zhǔn)消息編/解碼器對(duì)消息進(jìn)行編解碼,它可以高效的對(duì)消息進(jìn)行二進(jìn)制序列化與反序列化。由于 Dart 與原生平臺(tái)之間數(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ā)送和接收值時(shí),這些值在消息中的序列化和反序列化會(huì)自動(dòng)進(jìn)行。

#自定義編解碼器

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

#如何獲取平臺(tái)信息

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

  1. enum TargetPlatform {
  2. android,
  3. fuchsia,
  4. iOS,
  5. }

可以看到目前 Flutter 只支持這三個(gè)平臺(tái)。我們可以通過如下代碼判斷平臺(tái):

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

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

  1. debugDefaultTargetPlatformOverride=TargetPlatform.iOS;
  2. print(defaultTargetPlatform); // 會(huì)輸出TargetPlatform.iOS

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

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)