Flutter笔记(二)
一、Android 集成 Flutter 实现流程
闲鱼、头条 在 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 之间的交互流程,在性能优化、问题分析上都可以得到延伸。
---------------------
作者:Songlcy
来源:CSDN
原文:https://blog.csdn.net/u013718120/article/details/86679147
版权声明:本文为博主原创文章,转载请附上博文链接!
Flutter笔记(二)相关推荐
- 一个Android菜鸟入门Flutter 笔记(二)
1. 网络编程与JSON解析 默认的HttpClient请求网络 get() async {//创建网络调用示例,设置通用请求行为(超时时间)var httpClient = HttpClient() ...
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7851 ...
- oracle直查和call哪个更快,让oracle跑的更快1读书笔记二
当前位置:我的异常网» 数据库 » <>读书笔记二 <>读书笔记二 www.myexceptions.net 网友分享于:2013-08-23 浏览:9次 <> ...
- 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
游戏开发笔记二十七 Direct3D 11入门级知识介绍 作者:毛星云 邮箱: happylifemxy@163.com 期待着与志同道合的朋友们相互交流 上一节里我们介绍了在迈入Dire ...
- [转载]dorado学习笔记(二)
原文地址:dorado学习笔记(二)作者:傻掛 ·isFirst, isLast在什么情况下使用?在遍历dataset的时候会用到 ·dorado执行的顺序,首先由jsp发送请求,调用相关的ViewM ...
- PyTorch学习笔记(二)——回归
PyTorch学习笔记(二)--回归 本文主要是用PyTorch来实现一个简单的回归任务. 编辑器:spyder 1.引入相应的包及生成伪数据 import torch import torch.nn ...
- tensorflow学习笔记二——建立一个简单的神经网络拟合二次函数
tensorflow学习笔记二--建立一个简单的神经网络 2016-09-23 16:04 2973人阅读 评论(2) 收藏 举报 分类: tensorflow(4) 目录(?)[+] 本笔记目的 ...
- 趣谈网络协议笔记-二(第十九讲)
趣谈网络协议笔记-二(第十九讲) HttpDNS:网络世界的地址簿也会指错路 自勉 勿谓言之不预也 -- 向为祖国牺牲的先烈致敬! 引用 dns缓存刷新时间是多久?dns本地缓存时间介绍 - 东大网管 ...
- 趣谈网络协议笔记-二(第十八讲)
趣谈网络协议笔记-二(第十八讲) DNS协议:网络世界的地址簿 自勉 勿谓言之不预也 -- 向为祖国牺牲的先烈致敬! 正文 DNS用于域名解析,但也不仅仅是用于域名解析,不仅仅是将域名转换成IP. 在 ...
- 趣谈网络协议笔记-二(第十七讲)
趣谈网络协议笔记-二(第十七讲) P2P协议:我下小电影,99%急死你 自勉 逃离舒适区! 正文 一. P2P协议 整个篇章讲的就是这两个协议之间的区别.P2P协议就是迅雷下载数据时所用的协议, 众所 ...
最新文章
- 深copy 和 浅copy 解析
- 数字身份的一些应用和方案
- python 装饰器是啥?
- oracle插入回车换行符
- Sublime Text C# 编译(csharp.sublime-build)
- 利用SAN做数字化世界的基石
- 经过多次试验后第一个成功地实现 HTTPService 与 MXML 之间传递数据,ArrayCollection 与DataGrid 之间成功绑定...
- SQL语法 之 基本查询
- CAD转GIS工具软件下载
- php 查看本机ip,查看本机ip地址用什么命令
- 不要放弃!“软考论文”一点也不难
- qq音乐linux版本下载地址,Linux版QQ音乐Cocomusic 2.0.2的安装及使用报告
- android 播放pcm的软件,应用AudioTrack播放PCM音频数据(android)
- 白城师范学院计算机科学学院官网,计算机科学学院2017-2018学年度第二学期奖学金公示...
- CentOS7安装kangle和easypanel
- 论文《Reasoning With Neural Tensor Networks for Knowledge Base Completion》的学习笔记
- HTML-CSS前端大作业一站式教育机构响应式前端网页网站模板
- LeetCode久不久来一题系列之Add Two Numbers
- storm throw 口袋妖怪_~~~~~~SOS!SOS!SSSSSSSOS!!!~~~那位大侠能给贴一个全招式的英文对...
- mac 下载软件无法将程序拖移至app 出现错误
热门文章
- GMQ交易所为区块链之下的商业未来做准备
- 我们常说的十三薪、十五薪这种,能百分之百发下来吗?它和年终奖有什么区别?...
- [经历分享]Mac安装Windows10失败/计算机意外地重新启动或遇到错误/无限蓝屏critical process died/尝试访问启动磁盘设置时出错
- php随机生成昵称,PHP生成随机用户名和密码的实现代码
- 苹果cms静态html报404,苹果cms伪静态常见几种问题设置教程
- Oracle round 函数(四舍五入)
- 发明专利申请到授权流程
- 初识~OTN 光传送网(Optical Transport Network)
- JS动态生成正则表达式
- [Swift]判断和监听设备屏幕方向