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

前言

FlutterGoogle開源的構建用戶界面(UI)工具包,幫助開發(fā)者通過一套代碼庫高效構建多平臺精美應用,支持移動、Web、桌面和嵌入式平臺。Flutter 開源、免費,擁有寬松的開源協(xié)議,適合商業(yè)項目。目前,Flutter已推出穩(wěn)定的2.0版本。也是目前最火的跨平臺開發(fā)工具之一

header-illustration.png

創(chuàng)建AndroidView

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

  • getView 返回你需要嵌入的AndroidView
  • dispose 調用此方法后,PlatformView 對象將不可用。調用此方法后,實現(xiàn) PlatformView 的插件必須清除對 View對象和 PlatformView 的所有引用。 如果不這樣做將導致內存泄漏。
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() {

    }
}

注冊AndroidView

新建一個類繼承自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)
    }

}

新建一個類繼承自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ù)是一個唯一標識字符串,后續(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與原生之間相互交互

上述案例中我們只是簡單地額嵌入了一個原生View,這種只適用于一個靜態(tài)頁面的處理,如果需要頁面之間動態(tài)交互,則需要添加一些額外的配置,交互無非就是你可以調用我的功能,我可以調用你的功能

MethodChannel

用于兩端的相互調用,并且可以返回結果,Native調用Flutter時需要在主線程中進行

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

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

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

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中定義相關的接受,onMethodCall可以接受到此channel對應的調用,兩端之間channel之間的關聯(lián)是通過name,也就是這里給的samples.flutter.dev/NativeChannel,result.success()是本次調用反饋的結果

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中對NativeMethodChannel進行注冊,這樣它才會持續(xù)監(jiān)聽

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

Android發(fā)送數(shù)據(jù)/調用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 使用異步的方式與原生進行交流,用于比如需要調用原生的某些功能,但是原生需要耗時返回的情況,這種事有返回值的調用,支持數(shù)據(jù)雙向傳遞
  • EventChannel 是用來返回監(jiān)聽各個階段的狀態(tài),沒有返回值,并且只支持單向,只支持原生傳遞數(shù)據(jù)給Flutter,可以用來監(jiān)聽某些特殊原生功能的狀態(tài)
  • BasicMessageChannel 用于傳遞字符串和半結構化的消息

歡迎關注Mike的簡書

Android 知識整理

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容