Fiutter- 混合開(kāi)發(fā)與原生Android交互

前言

FlutterGoogle開(kāi)源的構(gòu)建用戶界面(UI)工具包僧凰,幫助開(kāi)發(fā)者通過(guò)一套代碼庫(kù)高效構(gòu)建多平臺(tái)精美應(yīng)用,支持移動(dòng)继效、Web症杏、桌面和嵌入式平臺(tái)。Flutter 開(kāi)源瑞信、免費(fèi)厉颤,擁有寬松的開(kāi)源協(xié)議,適合商業(yè)項(xiàng)目凡简。目前逼友,Flutter已推出穩(wěn)定的2.0版本精肃。也是目前最火的跨平臺(tái)開(kāi)發(fā)工具之一

header-illustration.png

創(chuàng)建AndroidView

Flutter中的Android項(xiàng)目使用AndroidStudio打開(kāi),然后在app的包名下新建一個(gè)View實(shí)現(xiàn)io.flutter.plugin.platform.PlatformView接口帜乞,使用PlatformView就可以將AndroidView嵌入到Flutter視圖中去司抱,由于需要進(jìn)行視圖對(duì)象創(chuàng)建所以在構(gòu)造函數(shù)添加context

  • getView 返回你需要嵌入的AndroidView
  • dispose 調(diào)用此方法后,PlatformView 對(duì)象將不可用黎烈。調(diào)用此方法后习柠,實(shí)現(xiàn) PlatformView 的插件必須清除對(duì) View對(duì)象和 PlatformView 的所有引用。 如果不這樣做將導(dǎo)致內(nèi)存泄漏照棋。
import android.content.Context
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView

class CustomerView(context: Context):PlatformView {

    val textView: TextView = TextView(context).apply {
        text = "Test View in Android "
    }

    override fun getView() = textView

    override fun dispose() {

    }
}

注冊(cè)AndroidView

新建一個(gè)類繼承自PlatformViewFactory资溃,在其中創(chuàng)建我們的View

import android.content.Context
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class CustomerViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE){

    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        return CustomerView(context)
    }

}

新建一個(gè)類繼承自FlutterPlugin

import io.flutter.embedding.engine.plugins.FlutterPlugin

class CustomerViewPlugin : FlutterPlugin {

    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        binding.platformViewRegistry.registerViewFactory("plugins.flutter.io/my_custom_platform_view",CustomerViewFactory())
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {

    }

}

MainActivity中添加上述的Plugin,registerViewFactory中的viewTypeId參數(shù)是一個(gè)唯一標(biāo)識(shí)字符串,后續(xù)將引用在flutter視圖中

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine.plugins.add(CustomerViewPlugin())
    }
}

Flutter中引用AndroidView

class _MyHomePageState extends State<MyHomePage> {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: MyCustomerPlatformView(), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class MyCustomerPlatformView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (defaultTargetPlatform == TargetPlatform.android) {
      return AndroidView(viewType: ("plugins.flutter.io/my_custom_platform_view"));
    } else {
      return Text("No support this View");
    }
  }
}
搜狗截圖20211102112139.png

Flutter與原生之間相互交互

上述案例中我們只是簡(jiǎn)單地額嵌入了一個(gè)原生View必怜,這種只適用于一個(gè)靜態(tài)頁(yè)面的處理肉拓,如果需要頁(yè)面之間動(dòng)態(tài)交互,則需要添加一些額外的配置梳庆,交互無(wú)非就是你可以調(diào)用我的功能暖途,我可以調(diào)用你的功能

MethodChannel

用于兩端的相互調(diào)用,并且可以返回結(jié)果膏执,Native調(diào)用Flutter時(shí)需要在主線程中進(jìn)行

Flutter發(fā)送數(shù)據(jù)/調(diào)用Native

  1. 在Flutter中創(chuàng)建MethodChannel
var channel = MethodChannel("samples.flutter.dev/callNative");

2.在Flutter中通過(guò)channel發(fā)送數(shù)據(jù)給到Native驻售,通過(guò)invokeMethod函數(shù)發(fā)送到Native,然后當(dāng)返回信息時(shí)將其進(jìn)行顯示

Container(
        alignment: Alignment.center,
        child: GestureDetector(
          child: Text('Click to call Native'),
          onTap: () async {
            String result = await channel.invokeMethod("callNative", {"id": "1", "value": "Mike"});
            showDialog(context: context, builder: (context){
              return AlertDialog(title: Text("提示"),content: Text(result));
            }
            );
          },
        ),
      )

3.在Android中定義相關(guān)的接受,onMethodCall可以接受到此channel對(duì)應(yīng)的調(diào)用,兩端之間channel之間的關(guān)聯(lián)是通過(guò)name,也就是這里給的samples.flutter.dev/NativeChannel,result.success()是本次調(diào)用反饋的結(jié)果

class NativeMethodChannel(messenger: BinaryMessenger) : MethodChannel.MethodCallHandler {

    val channel = MethodChannel(messenger, "samples.flutter.dev/NativeChannel")

    init {
        channel.setMethodCallHandler(this)
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        if (call.method == "callNative") {
            val value = call.argument<String>("value")
            result.success("Received it: value is $value")
        }
    }
}

4.在NativeMainActivity中對(duì)NativeMethodChannel進(jìn)行注冊(cè)更米,這樣它才會(huì)持續(xù)監(jiān)聽(tīng)

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        NativeMethodChannel(flutterEngine.dartExecutor.binaryMessenger)
    }
channel.png

Android發(fā)送數(shù)據(jù)/調(diào)用Flutter

Android

            channel.invokeMethod("callFlutter","張三",object:MethodChannel.Result{
                override fun success(result: Any?) {
                    Log.e("Mike","result $result")
                }

                override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {

                }

                override fun notImplemented() {

                }

            })

Flutter端接收

  @override
  void initState() {
    super.initState();
    channel.setMethodCallHandler((call) {
        print("flutter called by native ${call.arguments}");
        return Future.value("res");
    });
  }

BasicMessageChannel
EventChannel

他們的功能以及使用方式與MethodChannel相似

MethodChannel欺栗,BasicMessageChannel,EventChannel的區(qū)別與選擇

  • MethodChannel 使用異步的方式與原生進(jìn)行交流征峦,用于比如需要調(diào)用原生的某些功能迟几,但是原生需要耗時(shí)返回的情況,這種事有返回值的調(diào)用栏笆,支持?jǐn)?shù)據(jù)雙向傳遞
  • EventChannel 是用來(lái)返回監(jiān)聽(tīng)各個(gè)階段的狀態(tài)类腮,沒(méi)有返回值,并且只支持單向蛉加,只支持原生傳遞數(shù)據(jù)給Flutter,可以用來(lái)監(jiān)聽(tīng)某些特殊原生功能的狀態(tài)
  • BasicMessageChannel 用于傳遞字符串和半結(jié)構(gòu)化的消息

歡迎關(guān)注Mike的簡(jiǎn)書(shū)

Android 知識(shí)整理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚜枢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子针饥,更是在濱河造成了極大的恐慌厂抽,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丁眼,死亡現(xiàn)場(chǎng)離奇詭異筷凤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)户盯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門嵌施,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)饲化,“玉大人,你說(shuō)我怎么就攤上這事吗伤〕钥浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵足淆,是天一觀的道長(zhǎng)巢块。 經(jīng)常有香客問(wèn)我,道長(zhǎng)巧号,這世上最難降的妖魔是什么族奢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮丹鸿,結(jié)果婚禮上越走,老公的妹妹穿的比我還像新娘。我一直安慰自己靠欢,他們只是感情好廊敌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著门怪,像睡著了一般骡澈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掷空,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天肋殴,我揣著相機(jī)與錄音,去河邊找鬼坦弟。 笑死护锤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酿傍。 我是一名探鬼主播蔽豺,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拧粪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起沧侥,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤可霎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宴杀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體癣朗,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年旺罢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旷余。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绢记。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖正卧,靈堂內(nèi)的尸體忽然破棺而出蠢熄,到底是詐尸還是另有隱情,我是刑警寧澤炉旷,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布签孔,位于F島的核電站,受9級(jí)特大地震影響窘行,放射性物質(zhì)發(fā)生泄漏饥追。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一罐盔、第九天 我趴在偏房一處隱蔽的房頂上張望但绕。 院中可真熱鬧,春花似錦惶看、人聲如沸捏顺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)草丧。三九已至,卻和暖如春莹桅,著一層夾襖步出監(jiān)牢的瞬間昌执,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工诈泼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懂拾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓铐达,卻偏偏與公主長(zhǎng)得像岖赋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓮孙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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