[Flutter] 調(diào)用原生功能實(shí)現(xiàn)

“平臺(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和原生之間傳遞消息匈勋,如下:


屏幕快照 2019-09-17 上午10.31.18.png

在Flutter中調(diào)用原生方法時(shí),調(diào)用信息通過平臺(tái)通道傳遞到原生膳叨,原生收到調(diào)用信息后可以執(zhí)行指定的操作洽洁,如果需要返回?cái)?shù)據(jù),則原生會(huì)將數(shù)據(jù)再通過平臺(tái)通道傳遞給Flutter菲嘴。這里的消息傳遞是異步的饿自,這確保了用戶在消息傳遞時(shí)不會(huì)被掛起汰翠。

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

注意: 如果需要佛纫,方法調(diào)用(消息傳遞)可以是反向的,即宿主作為客戶端調(diào)用Dart中實(shí)現(xiàn)的API总放。 quick_actions插件就是一個(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)系。


屏幕快照 2019-09-17 上午10.35.43.png

自定義編解碼器

除了上面提到的MethodChannel哎榴,還可以使用BasicMessageChannel型豁,它支持使用自定義消息編解碼器進(jìn)行基本的異步消息傳遞。 此外尚蝌,可以使用專門的BinaryCodecStringCodecJSONMessageCodec類充尉,或創(chuàng)建自己的編解碼器飘言。

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

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

enum TargetPlatform {
  android,
  fuchsia,
  iOS,
}

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

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

由于不同平臺(tái)有它們各自的交互規(guī)范,F(xiàn)lutter Material庫(kù)中的一些組件都針對(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)糖耸。比如:

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

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

下面以一個(gè)獲取電池電量的插件來介紹一下洋侨,通過在Dart中通過 getBatteryLevel 調(diào)用 iOS device.batteryLevel API。

Flutter部分:

  • 導(dǎo)入import 'package:flutter/services.dart';
  • 創(chuàng)建通道名稱倦蚪,單個(gè)應(yīng)用使用的所有通道名稱必須是唯一的:
    static const platform = const MethodChannel('samples.flutter.io/battery');
  • 調(diào)用方法希坚,這里是異步的 final int result = await platform.invokeMethod('getBatteryLevel');

iOS部分:
在application didFinishLaunchingWithOptions:方法內(nèi)部創(chuàng)建一個(gè)FlutterMethodChannel,并添加一個(gè)處理方法审丘。 確保與在Flutter客戶端使用的通道名稱相同吏够。

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
  FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;

  FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
                                          methodChannelWithName:@"samples.flutter.io/battery"
                                          binaryMessenger:controller];

  [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
    // TODO
  }];

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

在AppDelegate類中添加以下新的方法:

- (int)getBatteryLevel {
  UIDevice* device = UIDevice.currentDevice;
  device.batteryMonitoringEnabled = YES;
  if (device.batteryState == UIDeviceBatteryStateUnknown) {
    return -1;
  } else {
    return (int)(device.batteryLevel * 100);
  }
}

最后,我們完成之前添加的setMethodCallHandler方法滩报。我們需要處理的平臺(tái)方法名為getBatteryLevel锅知,所以我們?cè)赾all參數(shù)中需要先判斷是否為getBatteryLevel。 這個(gè)平臺(tái)方法的實(shí)現(xiàn)只需調(diào)用我們?cè)谇耙徊街芯帉懙膇OS代碼脓钾,并使用result參數(shù)返回成功或錯(cuò)誤的響應(yīng)售睹。如果調(diào)用了未定義的API,我們也會(huì)通知返回:

[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
  if ([@"getBatteryLevel" isEqualToString:call.method]) {
    int batteryLevel = [self getBatteryLevel];

    if (batteryLevel == -1) {
      result([FlutterError errorWithCode:@"UNAVAILABLE"
                                 message:@"電池信息不可用"
                                 details:nil]);
    } else {
      result(@(batteryLevel));
    }
  } else {
    result(FlutterMethodNotImplemented);
  }
}];

至此可训,就可以了昌妹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市握截,隨后出現(xiàn)的幾起案子飞崖,更是在濱河造成了極大的恐慌,老刑警劉巖谨胞,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件固歪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡胯努,警方通過查閱死者的電腦和手機(jī)牢裳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叶沛,“玉大人蒲讯,你說我怎么就攤上這事』沂穑” “怎么了判帮?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)氓侧。 經(jīng)常有香客問我脊另,道長(zhǎng),這世上最難降的妖魔是什么约巷? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任偎痛,我火速辦了婚禮,結(jié)果婚禮上独郎,老公的妹妹穿的比我還像新娘踩麦。我一直安慰自己枚赡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布谓谦。 她就那樣靜靜地躺著贫橙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪反粥。 梳的紋絲不亂的頭發(fā)上卢肃,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音才顿,去河邊找鬼莫湘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛郑气,可吹牛的內(nèi)容都是我干的幅垮。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼尾组,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忙芒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讳侨,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤呵萨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后跨跨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甘桑,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年歹叮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铆帽。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咆耿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爹橱,到底是詐尸還是另有隱情萨螺,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布愧驱,位于F島的核電站慰技,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏组砚。R本人自食惡果不足惜吻商,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糟红。 院中可真熱鬧艾帐,春花似錦乌叶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捎稚,卻和暖如春乐横,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背今野。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工葡公, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腥泥。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓匾南,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛔外。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛆楞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容