flutter Native 通信之FlutterBridge

為什么會(huì)開(kāi)發(fā)這個(gè)框架

在flutter和Native混合開(kāi)發(fā)的過(guò)程中我們難免會(huì)遇到flutter和Native相互通信的場(chǎng)景豪硅,這時(shí)我們就會(huì)用到flutter提供的 Flutter Platform Channel能力。大部分情況我們使用的都是 MethodChannel挺物,一般我們會(huì)這樣是用懒浮。

flutter中使用methodchannel
  //聲明 methodchannel
  static const MethodChannel LUXURY_METHOD_CHANNEL = MethodChannel('flutter_native_channel');


    //注冊(cè)方法監(jiān)聽(tīng)
    MethodChannelHolder.LUXURY_METHOD_CHANNEL.setMethodCallHandler((MethodCall methodCall) async {
     switch (methodCall.method) {
      case "methodA": 
        ......;
        break;
      case "methodB": 
        ......;
        break;
    }
    });
    
    //調(diào)用 方法
 var result = await MethodChannelHolder.LUXURY_METHOD_CHANNEL.invokeMethod(MethodHolder.COMMON_GOTO_HOME, {"isAll": path.isNotEmpty? "0": isAll});
原生中使用
    //聲明 methodchannel
    val LUXURY_METHOD_CHANNEL = MethodChannel(dartExecutor,"flutter_native_channel")
    
    //注冊(cè)方法監(jiān)聽(tīng)
    MethodChannelHolder.LUXURY_METHOD_CHANNEL.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
            when {
                "methodA" -> {
                   .....
                }
                "methodB" -> {
                    .....
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
        
    //調(diào)用 方法
    MethodChannelHolder.LUXURY_METHOD_CHANNEL.invokeMethod("nativeCall/bbb", hashMapOf("cc" to "dd"),object :MethodChannel.Result{
                override fun notImplemented() {
                    LogUtil.e("原生 調(diào)用 flutter 收到 回調(diào) notImplemented")
                }

                override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {
                    LogUtil.e("原生 調(diào)用 flutter 收到 回調(diào) error = $errorMessage")
                }

                override fun success(result: Any?) {
                    LogUtil.e("原生 調(diào)用 flutter 收到 回調(diào) success result=${result}")
                }

            })

那么我們直接使用MethodChannel會(huì)有哪些不方便或者問(wèn)題呢?

  1. 使用前必須要手動(dòng)聲明一個(gè)MethodChannel识藤,這也太麻煩了砚著。(手動(dòng)狗頭)
  2. 方法注冊(cè)的位置被限定死,必須要在 MethodCallHandler的 onMethodCall 中聲明蹋岩,而且沒(méi)有辦法反注冊(cè)赖草。
  3. Native端的調(diào)用和回調(diào)必須保證在主線程。

基于這些問(wèn)題于是就有了flutter_bridge.

如何封裝

1. 解決“必須要手動(dòng)聲明一個(gè)MethodChannel問(wèn)題”

我們會(huì)在框架初始化的時(shí)候會(huì)自動(dòng)創(chuàng)建一個(gè)MethodChannel剪个,這樣我們就不用自己創(chuàng)建MethodChannel了秧骑,也不用想channel的命名了,哈哈哈

//flutter
class FlutterBridge {
  static const String CHANNEL_NAME = "flutterBridge/core";
  MethodChannel _channel = new MethodChannel(CHANNEL_NAME);

  FlutterBridge._() {
    _channel.setMethodCallHandler(onMethodCall);
  }
}

//native
fun initChannel(messenger: BinaryMessenger) {
    channel = MethodChannel(messenger, CHANNEL_NAME)
    channel.setMethodCallHandler(this)
}

2. 解決“方法注冊(cè)的位置被限定死扣囊,而且沒(méi)有辦法反注冊(cè)”

我們注冊(cè)方法時(shí)是將方法名稱(chēng)和方法體存放到一個(gè)map中乎折,當(dāng)有方法被調(diào)用時(shí)會(huì)從map中找到對(duì)應(yīng)方法體并執(zhí)行,反注冊(cè)則是從map中移除該方法侵歇。

//flutter---
var _methodMap = HashMap<String, MethodHandler>();

// 注冊(cè)方法
void registerHandler(String methodName, MethodHandler methodHandle) {
_methodMap[methodName] = methodHandle;
}

// 反注冊(cè)方法
MethodHandler unregisterHandler(String methodName) {
return _methodMap.remove(methodName);
}
  
//native---
private val methodMap = hashMapOf<String, MethodHandler>()

/**
 * 注冊(cè)方法
 */
fun registerHandler(methodName: String, methodHandler: MethodHandler) {
    methodMap[methodName] = methodHandler
}

/**
 * 反 注冊(cè)方法
 */
fun unRegisterHandler(methodName: String): MethodHandler? {
    return methodMap.remove(methodName)
}

3. 解決“Native端的調(diào)用和回調(diào)必須保證在主線程”

我們會(huì)在調(diào)用和回調(diào)時(shí)判斷當(dāng)前線程骂澄,如果非主線程,則切換到主線程在進(jìn)行調(diào)用或回調(diào)惕虑。這樣開(kāi)發(fā)者就不用擔(dān)心線程切換問(wèn)題了

//調(diào)用 
    fun <R> callFlutter(
        methodName: String,
        params: Map<String, Any?> = HashMap(),
        callBack: HandleCallBack<R> = DefaultHandleCallBack<R>()
    ) {

        if (HandlerUtils.isMainThread()) {
            callFlutterInner(methodName, params, callBack)
        } else {
            HandlerUtils.getMainHandler().post {
                callFlutterInner(methodName, params, callBack)
            }
        }

    }
//回調(diào)
    fun success(result: Any?) {
        if (HandlerUtils.isMainThread()) {
            resultOrigin.success(result)
        } else {
            HandlerUtils.getMainHandler().post {
                resultOrigin.success(result)
            }
        }
    }

使用(更多使用可以前往github

flutter

//方法注冊(cè)
FlutterBridge.instance.registerHandler("getFlutterMap", (params) {
      print('getFlutterMap ${params.toString()}');
      return {
        "aa": "bb",
        "cc": 1,
        "dd": [1, 2, 3],
        "ee": true
      };
    });

 //方法調(diào)用
 MaterialButton(
      onPressed: () async {
        var map = await FlutterBridge.instance.callNative<Map>("callNativeReturnMap", params: {
          "aa": "bb",
          "cc": 1,
          "dd": [1, 2, 3],
          "ee": true
        });
        result = map.toString();
        setState(() {});
      },
      child: Text("調(diào)用原生方法-帶入?yún)?返回值是map"),
    )

原生

//方法注冊(cè)
FlutterBridge.instance.registerHandler("callNativeReturnMap",
    object : MethodHandlerHaveReturn<Map<String, Any>> {
        override fun onMethodCall(params: Map<String, Any?>): Map<String, Any> {

            Log.e("flutterBridge","callNativeReturnMap params =${params.toString()}")

            return hashMapOf(
                "aa" to "bb",
                "cc" to 1,
                "dd" to arrayListOf(1, 2, 3),
                "ee" to true
            )
        }
    })
//方法調(diào)用
 findViewById<View>(R.id.btn_map).setOnClickListener {
    FlutterBridge.instance.callFlutter(
        "getFlutterMap",
        params = hashMapOf(
            "aa" to "bb",
            "cc" to 1,
            "dd" to arrayListOf(1, 2, 3),
            "ee" to true
        ),
        callBack = object : HandleCallBack<Map<String, Any?>> {
            override fun callSuccess(result: Map<String, Any?>?) {
                tv.text = "調(diào)用flutter方法-帶入?yún)?返回Map result=${result.toString()}"
            }

        })

}

操作演示

flutter-native.gif
native-flutter.gif

GitHub地址

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坟冲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子溃蔫,更是在濱河造成了極大的恐慌健提,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伟叛,死亡現(xiàn)場(chǎng)離奇詭異私痹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)紊遵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)账千,“玉大人,你說(shuō)我怎么就攤上這事暗膜≡茸啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵桦山,是天一觀的道長(zhǎng)攒射。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恒水,這世上最難降的妖魔是什么会放? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮钉凌,結(jié)果婚禮上咧最,老公的妹妹穿的比我還像新娘。我一直安慰自己御雕,他們只是感情好矢沿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著酸纲,像睡著了一般捣鲸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闽坡,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天栽惶,我揣著相機(jī)與錄音,去河邊找鬼疾嗅。 笑死外厂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晒杈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了掖棉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤膀估,失蹤者是張志新(化名)和其女友劉穎幔亥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體玖像,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捐寥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笤昨。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖握恳,靈堂內(nèi)的尸體忽然破棺而出瞒窒,到底是詐尸還是另有隱情,我是刑警寧澤乡洼,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布崇裁,位于F島的核電站,受9級(jí)特大地震影響束昵,放射性物質(zhì)發(fā)生泄漏拔稳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一锹雏、第九天 我趴在偏房一處隱蔽的房頂上張望巴比。 院中可真熱鬧,春花似錦礁遵、人聲如沸轻绞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)政勃。三九已至,卻和暖如春兼砖,著一層夾襖步出監(jiān)牢的瞬間奸远,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工掖鱼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留然走,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓戏挡,卻偏偏與公主長(zhǎng)得像芍瑞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褐墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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