Flutter与Android混合开发及Platform Channel的使用

  1. 相对于单独开发Flutter应用,混合开发对于线上项目更具有实际意义,可以把风险控制到最低,也可以进行实战上线。所以介绍 集成已有项目

  2. 混合开发涉及原生Native和Flutter进行通信传输,还有插件编写,所以介绍 两端通信Flutter Platform Channel的使用

WanAndroid客户端简单Flutter版 Apk

集成已有项目

官方方案 | 闲鱼团队方案 | 头条团队方案

采用官方的实现方式,对个人和小团队相对简单易用,并没有实践闲鱼和头条等大项目的方式。个中利弊上述推荐均有提到。

开始

  1. 在已有项目根目录运行命令

    flutter create -t module my_flutter

不一定非在项目下创建,兼顾ios,位置路径寻址对即可

2.在项目的settings.gradle 文件添加如下代码

1// MyApp/settings.gradle 2include ':app' // assumed existing content 3setBinding(new Binding([gradle: this])) // new 4evaluate(new File( // new 5 settingsDir.parentFile, // new 6 'my_flutter/.android/include_flutter.groovy' // new 7)) // new

Binding飘红不予理会,强迫症的不用导包
'my_flutter/.android/include_flutter.groovy'为my_flutter文件路径,报错找不到可写项目全路径'ChannelFlutterAndroid/my_flutter/.android/include_flutter.groovy'

3.在运行模块app的build.gradle添加依赖

1// MyApp/app/build.gradle 2dependencies { 3 implementation project(':flutter') 4}

4.在原生Android端创建并添加flutterView

1val flutterView = Flutter.createView(this, lifecycle, "route1") 2 val layoutParams = FrameLayout.LayoutParams(-1, -1) 3 addContentView(flutterView, layoutParams)

5.在Flutter端入口操作

1void main() => runApp(_widgetForRoute(window.defaultRouteName)); 2 3Widget _widgetForRoute(String route) { 4 switch (route) { 5 case 'route1': 6 return SomeWidget(...); 7 default: 8 return Center( 9 child: Text('Unknown route: $route', textDirection: TextDirection.ltr), 10 ); 11 } 12}
  1. 至此,集成完毕

两端通信Flutter Platform Channel的使用

本文主要是介绍使用方式,闲鱼团队详尽的介绍了实现原理

Flutter提供 MethodChannelEventChannelBasicMessageChannel 三种方式

  1. 类似注册监听,发送的模式 原则
  2. 使用顺序:先注册,后发送,否则接收不到。尤其使用 MethodChannelEventChannel 不符合该原则会抛出异常,BasicMessageChannel方式只是收不到消息

方式一 MethodChannel

应用场景:Flutter端 调用 Native端

Flutter端代码:

1var result = await MethodChannel("com.simple.channelflutterandroid/method", 2 StandardMethodCodec()) 3 .invokeMethod("toast", {"msg": msg})

Android端代码:

1MethodChannel(flutterView, "com.simple.channelflutterandroid/method", 2 StandardMethodCodec.INSTANCE) 3 .setMethodCallHandler { methodCall, result -> 4 when (methodCall.method) { 5 "toast" -> { 6 //调用传来的参数"msg"对应的值 7 val msg = methodCall.argument<String>("msg") 8 //调用本地Toast的方法 9 Toast.makeText(cxt, msg, Toast.LENGTH_SHORT).show() 10 //回调给客户端 11 result.success("native android toast success") 12 } 13 "other" -> { 14 // ... 15 } 16 else -> { 17 // ... 18 } 19 } 20 }
  • 注意点1:两端需要对应一致的点
    方法名称:com.simple.channelflutterandroid/method,可以不采取包名,对应一致即可,不同的方式最好不要重复
    传参key:"msg"

  • 注意点2:以下为Flutter为例,Android同理
    StandardMethodCodec() 非必传,默认是 StandardMethodCodec(),是一种消息编解码器

    对于 MethodChannelEventChannel 两种方式,有两种编解码器,均实现自MethodCodec ,分别为 StandardMethodCodecJsonMethodCodec

    对于 BasicMessageChannel 方式,有四种编解码器,均实现自MessageCodec ,分别为 StandardMessageCodecJSONMessageCodecStringCodecBinaryCodec

  • 注意点3:setMethodCallHandler(),针对三种方式一一对应,属于监听
    MethodChannel - setMethodCallHandler()
    EventChannel - setStreamHandler()
    BasicMessageChannel - setMessageHandler()
    其中setStreamHandler()方式稍微特殊,具体查看上面提的闲鱼文章

  • 注意点4:FlutterView 实现 BinaryMessenger 接口

以上,以下两种方法不再赘述

方式二 EventChannel

应用场景:Native端 调用 Flutter端,方式稍微特殊

Flutter端代码:属于接收方

1EventChannel("com.simple.channelflutterandroid/event") 2 .receiveBroadcastStream() 3 .listen((event){ 4 print("It is Flutter - receiveBroadcastStream $event"); 5 })

注意 receiveBroadcastStream

Android端代码:属于发送方

1EventChannel(flutterView, "com.simple.channelflutterandroid/event") 2 .setStreamHandler(object : EventChannel.StreamHandler { 3 override fun onListen(o: Any?, eventSink: EventChannel.EventSink) { 4 eventSink.success("我是发送Native的消息") 5 } 6 7 override fun onCancel(o: Any?) { 8 // ... 9 } 10 })

方式三 BasicMessageChannel

应用场景:互相调用

两种使用方式,创建方式和格式不一样

第一种

Flutter端

1_basicMessageChannel = BasicMessageChannel("com.simple.channelflutterandroid/basic", 2 StringCodec()) 3 4 // 发送消息 5 _basicMessageChannel.send("我是Flutter发送的消息"); 6 7 // 接收消息 8 _basicMessageChannel.setMessageHandler((str){ 9 print("It is Flutter - receive str"); 10 });

Android端

1val basicMessageChannel = BasicMessageChannel<String>(flutterView, "com.simple.channelflutterandroid/basic", 2 StringCodec.INSTANCE) 3 4 // 发送消息 5 basicMessageChannel.send("我是Native发送的消息") 6 7 // 接收消息 8 basicMessageChannel.setMessageHandler { o, reply -> 9 println("It is Native - setMessageHandler $o") 10 reply.reply("It is reply from native") 11 }

其中StringCodec(),四种方式可选

第二种

Flutter端

1static const BASIC_BINARY_NAME = "com.simple.channelflutterandroid/basic/binary"; 2 3 // 发送消息 4 val res = await BinaryMessages.send(BASIC_BINARY_NAME, ByteData(256)) 5 6 // 接收消息 7 BinaryMessages.setMessageHandler(BASIC_BINARY_NAME, (byteData){ 8 println("It is Flutter - setMessageHandler $byteData") 9 });

Android端

1const val BASIC_BINARY_NAME = "com.simple.channelflutterandroid/basic/binary" 2 3 // 发送消息 4 flutterView.send(BASIC_BINARY_NAME,ByteBuffer.allocate(256)); 5 6 // 接收消息 7 flutterView.setMessageHandler(BASIC_BINARY_NAME) { byteBuffer, binaryReply -> 8 println("It is Native - setMessageHandler $byteBuffer") 9 binaryReply.reply(ByteBuffer.allocate(256)) 10 }

此组合可以进行图片的传递

help 在操作中使用此方式传输数据总报错,所以只传了默认ByteBuffer。还是姿势不对???目前未发现,求大神指教

如有错误之处,万望各位指出!谢谢

其他

  1. Native端接收方收到消息后都能进行回传信息,在Flutter进行异步接收
    MethodChannel:result.success("我是回传信息");
    EventChannel:eventSink.success("我是回传信息");
    BasicMessageChannel:binaryReply.reply(-);- Flutter端:ByteData;Android端:ByteBuffer

Q&A

以上均为理想情况,过程中还是存在许多问题,以下提供参考

**Q:**使用命令行flutter create创建的project或者module,文件android/ios为隐藏打点开头的.android/.ios文件
**A:**所以有的时候会出现问题,寻找不到文件的情况

Q: flutter create module 和project的区别
A: ?? 目前没发现

**Q:**couldn't locate lint-gradle-api-26.1.2.jar for flutter project
A: https://stackoverflow.com/questions/52945041/couldnt-locate-lint-gradle-api-26-1-2-jar-for-flutter-project

Q: Could not resolve all files for configuration ':app:androidApis'.
Failed to transform file 'android.jar' to match attributes {artifactType=android-mockable-jar, returnDefaultValues=false} using transform MockableJarTransform
A:https://github.com/anggrayudi/android-hidden-api/issues/46

Q: Flutter Error: Navigator operation requested with a context that does not include a Navigator
A: https://github.com/flutter/flutter/issues/15919

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )