Android 集成 Flutter 及通信交互详解

栏目: IOS · Android · 发布时间: 6年前

内容简介:前不久开源了用Flutter开发的一个音视频类App客户端,欢迎大家star, fork。:warning: 本篇博客涉及的源码全部开源在Github,地址:

前不久开源了用Flutter开发的一个音视频类App客户端,欢迎大家star, fork。

:warning: 项目地址: github.com/songxiaolia…

:warning: 本篇博客涉及的源码全部开源在Github,地址: github.com/songxiaolia…

目前现有的跨平台开发解决方案基本分为两种开发模式:

(1)纯跨平台语言开发模式

(2)Native + Hybrid 混合开发模式

在纯跨平台开发方案带来的高效开发效率的同时,混合开发也为原生App提供了更方便更快捷的功能实现。例如,React Native 热更新,跨平台双端UI视图等。

了解React Native的朋友,对 Android & RN 的开发模式肯定不会陌生,在之前的文章中,我也介绍了如何将RN实践在Android原生App中,详细内容大家可以查看 《Android 集成 React Native、原生视图加载RN组件模块分析》 。本篇博客将围绕跨平台开发框架 Flutter,详细介绍如何集成在现有Android原生项目,以及双端的通信实现流程。

效果图

Android 集成 Flutter 及通信交互详解

一、Android 集成 Flutter 实现流程

闲鱼、头条 在 Android 集成 Flutter 模块都有自己的实现方案:闲鱼团队方案 &头条团队方案

我们以 官方方案 方式为主。

1)创建 flutter module 模块

官方提供了如下命令,用来创建 flutter module:

flutter create -t module flutter_module (module名称)复制代码

2)将 flutter module 模块添加到当前项目

打开项目根目录的 settings.gradle 文件,添加如下代码片段:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        "flutter_in_android/.android/include_flutter.groovy"
))复制代码

打开 app / build.gradle 文件,在 dependencies 下添加 flutter 依赖:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
 
    ......
 
    implementation project(':flutter')
}复制代码

以上配置完成后,Flutter就已经集成在当前Android工程项目中了。

二、Flutter 视图界面展示

Flutter的视图展示有两种实现方式:

(1)创建 FlutterView 视图组件,以 View 的方式添加到当前原生视图布局

官方依赖库中提供了 createView 的方法,方便开发者快速创建 Flutter 视图组件,并嵌入在当前原生布局:

/**
 * 此 Activity 中向 Flutter 端发送消息
 * create by Songlcy 2019-02-15
 */
public class FlutterContainerActy extends AppCompatActivity {
 
    private ViewGroup.LayoutParams layoutParams;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flutter);
        // 1. 通过Flutter.createView创建FlutterView组件方式
        FlutterView flutterView = Flutter.createView(this, getLifecycle(), "flutterView");
        layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        // 2. 将Flutter 视图添加到原生布局中
        addContentView(flutterView, layoutParams);
    }
}复制代码

上述代码中,我们通过 Flutter.createView 创建 Flutter 视图组件 FlutterView ,createView方法接收三个参数

@NonNull final Activity activity: Activity实例
@NonNull final Lifecycle lifecycle: 定义具有Android生命周期的对象
final String initialRoute: 初始化的视图路由名称复制代码

所以我们可以根据 initialRoute 来动态加载不同的 Flutter 视图组件:

import 'dart:ui'; // 引入后可以使用window对象
 
@override
Widget build(BuildContext context) {
  switch(window.defaultRouteName) {
 
    case "flutterView":     
        return Scaffold(...);
 
    ......
 
    default:
      return Center(
        child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
      );
  }
}复制代码

(2)启动 FlutterActivity 界面

在很多场景下,我们需要从原生界面跳转到Flutter视图界面,所以我们可以直接启动FlutterActivity来实现:

Intent intent = new Intent(MainActivity.this, FlutterActy.class);startActivity(intent);复制代码

三、Android 与 Flutter 通信方式

React Native跨平台开发框架是通过 RCTBatchedBridge 实现 js 与 Native 的交互,Flutter与Native的通信机制与RN的实现比较相似,只是没有了Bridge的桥接层,通过Channel直接与原生交互。官方在Channel通信的实现上同样采用了以字符串为唯一协议的方式,来同时构建通信交互信号。实现的具体方式和RN也同样类似,Native | Flutter 端实现监听回调,注册即可。

(1)MethodChannel

使用场景:Flutter端向Native端发送通知

实现方式:

Native端

new MethodChannel(getFlutterView(), "com.xxx").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        // methodCall.method 对应 Flutter端invokeMethod方法的第一个参数
        if(methodCall.method.equals("123")) {
            // 获取Flutter传递的参数
            String msg = methodCall.<String>argument("msg");
            // 回传给Flutter
            result.success(msg);
        }
    }
});复制代码

上述代码中我们创建了MethodChannel实例,并调用 setMethodCallHandler 注册监听回调。从源码中,可以看到MethodChannel构造函数接收两个参数

public MethodChannel(BinaryMessenger messenger, String name) {
     this(messenger, name, StandardMethodCodec.INSTANCE);
}
 
public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
 ......
}复制代码

name 就是双发通信的唯一标识,我们可以简单理解为钥匙即可。

MethodCodec有两种实现:

  • JSONMethodCodec

JSONMethodCodec的编解码依赖于JSONMessageCodec,当其在编码MethodCall时,会先将MethodCall转化为字典{"method":method,"args":args}。其在编码调用结果时,会将其转化为一个数组,调用成功为[result],调用失败为[code,message,detail]。再使用JSONMessageCodec将字典或数组转化为二进制数据。

  • StandardMethodCodec

MethodCodec的默认实现,StandardMethodCodec的编解码依赖于StandardMessageCodec,当其编码MethodCall时,会将method和args依次使用StandardMessageCodec编码,写入二进制数据容器。其在编码方法的调用结果时,若调用成功,会先向二进制数据容器写入数值0(代表调用成功),再写入StandardMessageCodec编码后的result。而调用失败,则先向容器写入数据1(代表调用失败),再依次写入StandardMessageCodec编码后的code,message和detail。

Flutter端

import 'package:flutter/services.dart';
 
static const methodPlugin = const MethodChannel('com.xxx');
String callbackResult = await methodPlugin.invokeMethod('123', { "msg": "456" });复制代码

在Flutter同样需要创建MethodChannel实例,并将通信钥匙作为参数传入,要与原生端保持一致。然后调用invokeMethod方法向原生端发送通信请求。第一个参数表示要调用原生端的哪个方法,第二个参数为 可选参数 ,即传递给Native端的数据参数。

(2)EventChannel

使用场景:Native端向Flutter端发送通知

实现方式:

Native端

new EventChannel(getFlutterView(), "com.xxx").setStreamHandler(new EventChannel.StreamHandler() {
 
    @Override
    public void onListen(Object o, EventChannel.EventSink eventSink) {
        eventSink.success("msg");
    }
 
    @Override
    public void onCancel(Object o) {
        // 做一些注销操作
    }
});复制代码

和 MethodChannel 类似,EventChannel 也是通过 new 创建对象实例,并设置 StreamHandler 类型的监听回调。其中 onCancel 代表对面不再接收,这里我们可以做注销的逻辑操作。onListen 代表通信已经建立完毕,Native可以向Flutter发送数据。onListen 方法中携带了 EventSink 参数,后续Native发送数据都是经过 EventSink 的 success、error 方法。

Flutter端

import 'package:flutter/services.dart';
 
static const eventPlugin = const EventChannel('com.xxx');
 
@override
void initState() {
  super.initState();
  _streamSubscription = eventPlugin.receiveBroadcastStream()
      .listen(_onData, onError: _onError, onDone: _onDone, cancelOnError: true);
}
 
void _onData(Object event) {
  // 接收数据
  setState(() {
    eventVal = event;
  });
}
 
void _onError(Object error) {
  // 发生错误时被回调
  setState((){
    eventVal = "错误";
  });
}
 
void _onDone() {
  //结束时调用
}
 
@override
void dispose() {
  super.dispose();
  if(_streamSubscription != null) {
    _streamSubscription.cancel();
  }
}复制代码

同样与 MethodChannel 类似,首先是创建 EventChannel 实例,然后在 initState 生命周期中调用 receiveBroadcastStream方法的listen。listen 返回的是 StreamSubscription 对象。此处有点类似Android中的BroadcastReceiver广播。listen方法源码如下:

StreamSubscription<T> listen(void onData(T event),
      {Function onError, void onDone(), bool cancelOnError});复制代码

可以看到,onData 为必需参数,onError、onDone、cancelOnError 为可选。顾名思义,onData 即为收到原生端发送数据的回调,onError为接收数据失败,onDone为接收数据结束,cancelOnError是一个bool类型参数,标识在发生错误时,时候自动取消通信。以上即可实现Native端向Flutter发送通知。

总结

Platform Channel 作为原生端与 Flutter 端建立通信渠道的方式,在混合开发模式中起到了至关重要的作用,很多地方都会涉及,例如编写 Plugin 等等。不仅能够帮助我们更深入的了解 Flutter 与 Native 之间的交互流程,在性能优化、问题分析上都可以得到延伸。


以上所述就是小编给大家介绍的《Android 集成 Flutter 及通信交互详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ethnography and Virtual Worlds

Ethnography and Virtual Worlds

Tom Boellstorff、Bonnie Nardi、Celia Pearce、T. L. Taylor / Princeton University Press / 2012-9-16 / GBP 21.00

"Ethnography and Virtual Worlds" is the only book of its kind - a concise, comprehensive, and practical guide for students, teachers, designers, and scholars interested in using ethnographic methods t......一起来看看 《Ethnography and Virtual Worlds》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具