FlutterPlugin的探索

本文主要是介紹FlutterPlugin,涉及到原理和使用飞崖。

Flutter Plugin提供Android或者iOS的底層封裝烂叔,在Flutter層提供組件功能,使Flutter可以較方便的調(diào)取Native的模塊固歪。很多平臺(tái)相關(guān)性或者對(duì)于Flutter實(shí)現(xiàn)起來比較復(fù)雜的部分蒜鸡,都可以封裝成Plugin胯努。

那么flutter和native如何相互調(diào)用呢,原理如下


消息在client和host之間通過平臺(tái)通道(platform channels)來進(jìn)行的逢防,之間的通訊都是異步的叶沛。

我們先介紹下MethodChannel的實(shí)現(xiàn)原理,使用方式以Android端為例:

//1忘朝、注冊(cè)通道
    MethodChannel channel = new MethodChannel(getFlutterView(),"flutter/channel");

//2灰署、設(shè)置回調(diào),被call回調(diào)
    channel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
      @Override
      public void onMethodCall(MethodCall call, MethodChannel.Result result) {  
              //通知到flutter端
              result.success(“返回值”);
      }
    });
    
//3局嘁、主動(dòng)call flutter的方法
    channel.invokeMethod("callFlutter", "params", new MethodChannel.Result() {
      @Override
      public void success(Object result) {
        //呼叫成功
      }

      @Override
      public void error(String errorCode, String errorMessage, Object errorDetails) {
        //呼叫出現(xiàn)異常
      }

      @Override
      public void notImplemented() {
        //flutter沒有對(duì)應(yīng)的實(shí)現(xiàn)方法
      }
    });

其實(shí)MethodChannel中的構(gòu)造函數(shù)第一個(gè)參數(shù)就是BinaryMessenger溉箕,這個(gè)BinaryMessenger是在DartExecuter中初始化的,而BinaryMessenger的實(shí)現(xiàn)類中的send函數(shù)最終是對(duì)DartMessenger的一層包裝悦昵,所以我們看消息是如何發(fā)送出去的肴茄,直接看DartMessengersend函數(shù)

  @Override
  public void send(
      @NonNull String channel,
      @Nullable ByteBuffer message,
      @Nullable BinaryMessenger.BinaryReply callback
  ) {
    Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
    int replyId = 0;
    if (callback != null) {
      replyId = nextReplyId++;
      pendingReplies.put(replyId, callback);
    }
    if (message == null) {
      flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
    } else {
      flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
    }
  }

如果有方法回調(diào)callback,就會(huì)生成一個(gè)replyId,然后把方法回調(diào)和replyId加入到一個(gè)map但指,如果沒有就直接發(fā)送消息了寡痰。
如果消息體為空,就發(fā)送一個(gè)空消息棋凳,如果有消息內(nèi)容氓癌,就把消息發(fā)送過去。還會(huì)攜帶一個(gè)replyId贫橙,這個(gè)會(huì)在回調(diào)的時(shí)候有用。發(fā)送消息是通過flutterJni分發(fā)方法反粥,最終調(diào)到了c++層面卢肃,通過c++的dart虛擬機(jī),把消息傳遞給了flutter才顿。

如何收到flutter端的消息呢
同樣的接受消息也是在DartExecutor莫湘,通過onAttachToJNI會(huì)建立通道關(guān)聯(lián),同樣的消息會(huì)經(jīng)過DartMessenger郑气,如果是收到原生調(diào)用flutter以后的回復(fù)幅垮,會(huì)調(diào)用

  @Override
  public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
    Log.v(TAG, "Received message reply from Dart.");
    BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId);
    if (callback != null) {
      try {
        Log.v(TAG, "Invoking registered callback for reply from Dart.");
        callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
      }
    }
  }

首先根據(jù)replyId找到剛才發(fā)送消息時(shí)保存的callback,找到了尾组,就把reply轉(zhuǎn)化為bytebuff調(diào)用出去忙芒。BinaryReply會(huì)將消息回調(diào)回去。
如果是從flutter主動(dòng)調(diào)動(dòng)的消息稍微負(fù)責(zé)一些讳侨,也是類似的原理呵萨,只不過多了一步根據(jù)通道名字找到對(duì)象的處理類。

//三個(gè)參數(shù)跨跨,通道名字潮峦,消息的字節(jié),從flutter端傳遞過來的replyId,
  public void handleMessageFromDart(
      @NonNull final String channel,
      @Nullable byte[] message,
      final int replyId
  ) {
    Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
    
    //根據(jù)通道名字找到對(duì)象的處理類"
    BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
    if (handler != null) {
      try {
        Log.v(TAG, "Deferring to registered handler to process message.");
        
       //解碼數(shù)據(jù)并調(diào)用onMessage傳遞消息 忱嘹,注意一下這個(gè)Reply
        final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
        handler.onMessage(buffer, new Reply(flutterJNI, replyId));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message listener", ex);
        //異常處理
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      }
    } else {
      Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
      //未實(shí)現(xiàn)通道處理
      flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
    }
  }

像Flutter官方提供的shared_preferences嘱腥,就是通過通道來實(shí)現(xiàn)的。

FlutterPlugin還有另外一個(gè)用法拘悦,就是直接在Flutter端由Native渲染齿兔。比如視頻播放插件video_player。
通常有兩種做法窄做,一種是PlatformView,另外一種是Texture(俗稱外接紋理)愧驱。其中PlatformView區(qū)分Android和iOS,在Android平上上叫做 AndroidView椭盏,而在iOS平臺(tái)组砚,叫UIKitView。
前面提到的MethodChannel可以向flutter傳輸數(shù)據(jù)掏颊,但是如果將一個(gè)視頻或者圖片的數(shù)據(jù)傳到flutter會(huì)很繁重糟红,所以Flutter提供了一種基于Texture的數(shù)據(jù)共享機(jī)制,而以上兩種方式原理都是基于Texture。

Texture https://api.flutter.dev/flutter/widgets/Texture-class.html

下圖是視頻插件的實(shí)現(xiàn)原理圖


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末乌叶,一起剝皮案震驚了整個(gè)濱河市盆偿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌准浴,老刑警劉巖事扭,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乐横,居然都是意外死亡求橄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門葡公,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罐农,“玉大人,你說我怎么就攤上這事催什『鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵蒲凶,是天一觀的道長气筋。 經(jīng)常有香客問我,道長旋圆,這世上最難降的妖魔是什么裆悄? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮臂聋,結(jié)果婚禮上光稼,老公的妹妹穿的比我還像新娘或南。我一直安慰自己,他們只是感情好艾君,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布采够。 她就那樣靜靜地躺著,像睡著了一般冰垄。 火紅的嫁衣襯著肌膚如雪蹬癌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天虹茶,我揣著相機(jī)與錄音逝薪,去河邊找鬼。 笑死蝴罪,一個(gè)胖子當(dāng)著我的面吹牛董济,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播要门,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼虏肾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了欢搜?” 一聲冷哼從身側(cè)響起封豪,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炒瘟,沒想到半個(gè)月后吹埠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疮装,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年藻雌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩个。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驯杜,靈堂內(nèi)的尸體忽然破棺而出受啥,到底是詐尸還是另有隱情,我是刑警寧澤鸽心,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布滚局,位于F島的核電站,受9級(jí)特大地震影響顽频,放射性物質(zhì)發(fā)生泄漏藤肢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一糯景、第九天 我趴在偏房一處隱蔽的房頂上張望嘁圈。 院中可真熱鬧省骂,春花似錦、人聲如沸最住。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涨缚。三九已至轧粟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間脓魏,已是汗流浹背兰吟。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茂翔,地道東北人混蔼。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像檩电,于是被迫代替她去往敵國和親拄丰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • Flutter Plugin 資料 [TOC] 前言 在Flutter中俐末,如果我們需要打印日志料按,如果不進(jìn)行自定義,...
    zcwfeng閱讀 5,395評(píng)論 3 3
  • 概述 調(diào)用原生功能 嵌入原有項(xiàng)目 Flutter模塊調(diào)試 一卓箫、調(diào)用原生功能 1.1载矿、Camera某些應(yīng)用程序可能需...
    IIronMan閱讀 1,111評(píng)論 1 7
  • 本文已授權(quán)「玉剛說」微信公眾號(hào)獨(dú)家發(fā)布 Flutter使用了一個(gè)靈活的系統(tǒng),允許開發(fā)者調(diào)用特定平臺(tái)的API烹卒,無論在...
    juexingzhe閱讀 2,596評(píng)論 1 12
  • 久違的晴天闷盔,家長會(huì)。 家長大會(huì)開好到教室時(shí)旅急,離放學(xué)已經(jīng)沒多少時(shí)間了逢勾。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22
  • 創(chuàng)業(yè)是很多人的夢(mèng)想藐吮,多少人為了理想和不甘選擇了創(chuàng)業(yè)來實(shí)現(xiàn)自我價(jià)值溺拱,我就是其中一個(gè)。 創(chuàng)業(yè)后谣辞,我由女人變成了超人迫摔,什...
    亦寶寶閱讀 1,812評(píng)論 4 1