Fiutter- 混合开发与原生Android交互

前言

FlutterGoogle开源的构建用户界面(UI)工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动、Web、桌面和嵌入式平台。Flutter 开源、免费,拥有宽松的开源协议,适合商业项目。目前,Flutter已推出稳定的2.0版本。也是目前最火的跨平台开发工具之一

header-illustration.png

创建AndroidView

Flutter中的Android项目使用AndroidStudio打开,然后在app的包名下新建一个View实现io.flutter.plugin.platform.PlatformView接口,使用PlatformView就可以将AndroidView嵌入到Flutter视图中去,由于需要进行视图对象创建所以在构造函数添加context

  • getView 返回你需要嵌入的AndroidView
  • dispose 调用此方法后,PlatformView 对象将不可用。调用此方法后,实现 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,在其中创建我们的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参数是一个唯一标识字符串,后续将引用在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,这种只适用于一个静态页面的处理,如果需要页面之间动态交互,则需要添加一些额外的配置,交互无非就是你可以调用我的功能,我可以调用你的功能

MethodChannel

用于两端的相互调用,并且可以返回结果,Native调用Flutter时需要在主线程中进行

Flutter发送数据/调用Native

  1. 在Flutter中创建MethodChannel
var channel = MethodChannel("samples.flutter.dev/callNative");

2.在Flutter中通过channel发送数据给到Native,通过invokeMethod函数发送到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之间的关联是通过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进行注册,这样它才会持续监听

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

Android发送数据/调用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的区别与选择

  • MethodChannel 使用异步的方式与原生进行交流,用于比如需要调用原生的某些功能,但是原生需要耗时返回的情况,这种事有返回值的调用,支持数据双向传递
  • EventChannel 是用来返回监听各个阶段的状态,没有返回值,并且只支持单向,只支持原生传递数据给Flutter,可以用来监听某些特殊原生功能的状态
  • BasicMessageChannel 用于传递字符串和半结构化的消息

欢迎关注Mike的简书

Android 知识整理

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355

推荐阅读更多精彩内容