PS:逐渐体会到关键少数原则的重要性,接下来就是付诸实践了,另外科创50ETF明天开始限额销售,可以适当关注或入手一点。
前面几篇文章介绍了 Navigator 组件、Flex 布局、图片加载、Widget 生命周期、混合开发等 Flutter 开发基础知识, 链接如下:
Flutter系列之Navigator使用详解
Flutter系列之Flex布局详解
Flutter系列之图片加载详解
Flutter系列之Widget生命周期
Flutter系列之混合开发Android篇
下面介绍一下 Flutter 混合开发中 Platform Channel 的使用,主要内容如下:
平台通道介绍
平台数据类型对照
BasicMessageChannel
MethodChannel
EventChannel
Platform Channel 是一个异步消息通道,消息在发送之前会编码成二进制消息,接收到的二进制消息会解码成 Dart 值,其传递的消息类型只能是对应的解编码器支持的值,所有的解编码器都支持空消息,其 Native 与 Flutter 通信架构如下图所示:
Flutter 中定义了三种不同类型的 PlatformChannel,主要有三种如下:
BasicMessageChannel:用于数据传递;
MethodChannel:用于传递方法调用;
EventChannel:用于传递事件;
其构造方法都需指定一个通道标识、解编码器以及 BinaryMessenger,BinaryMessenger 是一个 Flutter 与平台的通信工具,用来传递二进制数据、设置对应的消息处理器等。
解编码器有两种分别是 MethodCodec 和 MessageCodec,前者对应方法后者对应消息,BasicMessageChannel 使用的是 MessageCodec,MethodChannel 和 EventChannel 使用的是 MethodCodec。
Platform Channel 提供不同的消息解码机制,如 StandardMessageCodec 提供基本数据类型的解编码、JSONMessageCodec 支持 Json 的解编码等,在平台之间通信时都会自动转换,各平台数据类型对照如下:
BasicMessageChannel 主要用来数据传递,包括二进制数据,借助 BasicMessageChannel 可以实现 MethodChannel 和 EventChannel 的功能,这里用 BasicMessageChannel 实现 Android 项目使用 Flutter 资源文件的案例,关键流程如下:
Flutter 端获得图片资源对应的二进制数据,这里使用 BinaryCodec,则数据格式为 ByteData;
使用 BasicMessageChannel 发送图片对应的数据;
在 Android 端使用 ByteBuffer 接收,并将其转换成 ByteArray,然后解析成 Bitmap 显示出来。
Flutter 端关键代码如下:
1// 创建BasicMessageChannel 2_basicMessageChannel = BasicMessageChannel("com.manu.image", BinaryCodec()); 3 4// 获取assets中的图片对应的ByteData数据 5rootBundle.load('images/miao.jpg').then((value) => { 6 _sendStringMessage(value) 7}); 8 9// 发送图片数据10_sendStringMessage(ByteData byteData) async {11 await _basicMessageChannel.send(byteData);12}
Android 端关键代码如下:
1override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 2 super.configureFlutterEngine(flutterEngine) 3 Log.i(tag, "configureFlutterEngine") 4 // 设置消息处理器 5 BasicMessageChannel( 6 flutterEngine.dartExecutor, "com.manu.image", BinaryCodec.INSTANCE 7 ).setMessageHandler { message, reply -> 8 Log.i(tag, "configureFlutterEngine > message:$message") 9 // 数据转换:ByteBuffer->ByteArray10 val byteBuffer = message as ByteBuffer11 imageByteArray = ByteArray(byteBuffer.capacity())12 byteBuffer.get(imageByteArray)13 }1415 // 用于设置Flutter跳转Android的方法处理器16 MethodChannel(flutterEngine.dartExecutor, channel).setMethodCallHandler { call, result ->17 Log.i(tag, "configureFlutterEngine > method:${call.method}")18 if ("startBasicMessageChannelActivity" == call.method) {19 // 携带图片数据20 BasicMessageChannelActivity.startBasicMessageChannelActivity(this,imageByteArray)21 }22 }23}2425// 显示来自Flutter assets中的图片26val imageByteArray = intent.getByteArrayExtra("key_image")27val bitmap = BitmapFactory.decodeByteArray(imageByteArray,0,imageByteArray.size)28imageView.setImageBitmap(bitmap)
另外,BasicMessageChannel 结合 BinaryCodec 是支持大内存数据块的传递的。
MethodChannel 主要用来方法的传递,自然可以传递 Native 方法和 Dart 方法,即可以通过 MethodChannel 在 Flutter 中调用 Android 原生方法,在 Android 中调用 Dart 方法,互相调用都是通过 MethodChannel 的 invokeMethod 方法调用的,通信时必须使用相同的通道标识符,具体如下:
Flutter调用Android方法
下面通过 MethodChannel 实现从 Flutter 跳转到 Android 原生界面 MainActivity,Android 端如下:
1/** 2 * @desc FlutterActivity 3 * @author jzman 4 */ 5val tag = AgentActivity::class.java.simpleName; 6 7class AgentActivity : FlutterActivity() { 8 val tag = AgentActivity::class.java.simpleName; 9 private val channel = "com.manu.startMainActivity"10 private var platform: MethodChannel? = null;1112 override fun configureFlutterEngine(flutterEngine: FlutterEngine) {13 super.configureFlutterEngine(flutterEngine)14 Log.d(tag,"configureFlutterEngine")15 platform = MethodChannel(flutterEngine.dartExecutor, channel)16 // 设置方法处理器17 platform!!.setMethodCallHandler(StartMethodCallHandler(this@AgentActivity))18 }1920 companion object{21 /**22 * 重新创建NewEngineIntentBuilder才能保证生效23 */24 fun withNewEngine(): MNewEngineIntentBuilder? {25 return MNewEngineIntentBuilder(AgentActivity::class.java)26 }27 }2829 /**30 * 自定义NewEngineIntentBuilder31 */32 class MNewEngineIntentBuilder(activityClass: Class
如上还可以使用 MethodChannel.Result 对象向Flutter回调执行结果,Flutter 端如下:
1/// State 2class _PageState extends State
Android调用Dart方法
下面通过 MethodChannel 调用 Flutter 中的 Dart 方法 getName,Android 端代码如下:
1/** 2 * @desc MainActivity 3 * @author jzman 4 */ 5class MainActivity : FlutterActivity() { 6 private val tag = MainActivity::class.java.simpleName; 7 private val channel = "com.manu.startMainActivity" 8 private var methodChannel: MethodChannel? = null 9 override fun onCreate(savedInstanceState: Bundle?) {10 super.onCreate(savedInstanceState)11 setContentView(R.layout.activity_main)1213 btnGetDart.setOnClickListener {14 getDartMethod()15 }16 }1718 override fun configureFlutterEngine(flutterEngine: FlutterEngine) {19 super.configureFlutterEngine(flutterEngine)20 Log.i(tag,"configureFlutterEngine")21 methodChannel = MethodChannel(flutterEngine.dartExecutor,channel)22 }2324 private fun getDartMethod(){25 methodChannel?.invokeMethod("getName",null, object :MethodChannel.Result{26 override fun success(result: Any?) {27 Log.i(tag,"success: "+result.toString())28 Toast.makeText(this@MainActivity,result.toString(),Toast.LENGTH_LONG).show()29 }3031 override fun error(errorCode: String,errorMessage: String?,errorDetails: Any?) {32 Log.i(tag,"error")33 }3435 override fun notImplemented() {36 Log.i(tag,"notImplemented")37 }38 })39 }4041 companion object{42 fun startMainActivity(context: Context) {43 val intent = Intent(context, MainActivity::class.java)44 context.startActivity(intent)45 }46 }47}
Flutter 端如下:
1/// State 2class _PageState extends State
EventChannel 主要用于 Flutter 到原生之间的单向调用,其使用方式类似 Android 中的广播,原生界面负责 Event 的发送,Flutter 端注册监听即可,不多说直接看代码,Android 端代码如下:
1/// Android 2class MFlutterFragment : FlutterFragment() { 3 // 这里用Fragment,Activity也一样 4 override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 5 super.configureFlutterEngine(flutterEngine) 6 Log.d(tag,"configureFlutterEngine") 7 EventChannel(flutterEngine.dartExecutor,"com.manu.event").setStreamHandler(object: 8 EventChannel.StreamHandler{ 9 override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {10 Log.i(tag,"configureFlutterEngine > onListen")11 // EventSink发送事件通知12 events?.success("event message")13 }1415 override fun onCancel(arguments: Any?) {16 Log.i(tag,"configureFlutterEngine > onCancel")17 }18 })19 }2021 companion object{22 fun withNewEngine(): NewEngineFragmentBuilder? {23 return MNewEngineIntentBuilder(24 MFlutterFragment::class.java25 )26 }27 }2829 class MNewEngineIntentBuilder(activityClass: Class
Flutter 端如下:
1/// State 2class EventState extends State
以上就是 Flutter 平台通道的使用,可以在公众号回复关键字【Channel】获取源码。
推荐阅读:Wireshark分析验证TCP协议