Flutter与Native如何对话?
概念参考Flutter中文网
Flutter与Native间通信,是通过平台通道向Native(Android/IOS)发送消息.Navtive通过平台通道接收到消息,然后Native处理消息,然后将响应消息返回给Flutter.这样就完成了Flutter与Native的一次对话.
可以想象为:通俗的来讲就是Flutter拨打Native的电话号码,平台通道就相当于基站(BTS),通过电话号码向Native发送信号进行呼叫,呼叫成功后Native接通电话,然后Flutter可以向Native指定定义好的消息,Navtive给出响应.响应完毕后自动挂断.完成一次通话.
消息和响应是以异步.
既然是传递消息肯定有类型限制,不能什么消息都传递. 可以传递的消息类型如下:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
当你发送和接收值时,会自动进行序列化和反序列化
如何实现通信?
本篇以Android为例实现一个语音识别的插件(使用百度语音的SDK)
Flutter要与Navtive通信,就需要构建通道(MethodChannel),构建通道完毕后,还需要知道一个电话号码(与Native定义好的一个唯一的通道名,电话号码也是唯一的)比如“asr_plugin”,这是唯一的通道名
class AsrPlugin { //通过MethodChannel 调用原生的方法 static const MethodChannel _channel = const MethodChannel('asr_plugin'); } |
上述代码,已经建立好通道了,并且尝试连接Native.要想连接Native,Native则要接受通道,接受的通道名就是Flutter定义好的通道名,这样才能与Native完整的建立通道
public static void registerWith(Registrar registrar) { //确保通道名称一致 final MethodChannel channel = new MethodChannel(registrar.messenger(), "asr_plugin"); } |
完成上述代码,Flutter已经连接上了Native,这时Flutter只要发送消息,就可以操作Native了.
代码如下,Flutter向Native发送消息,分别是识别语音、停止、取消、销毁
注意:需要将方法设置为异步的
async
发送和接受响应以确保界面保持响应
static Future<String> start({Map params}) async { return _channel.invokeMethod("start", params ?? {}); } /// 与native通信的方法 调用native 的停止录音 static Future<String> stop() async { return _channel.invokeMethod("stop"); } /// 与native通信的方法 调用native 的取消录音 static Future<String> cancel() async { return _channel.invokeMethod("cancel"); } static Future<String> release() async { return _channel.invokeMethod("release"); } |
Native如何接受消息呢? 需要实现MethodCallHandler接口,onMethodCall方法中可以接受到Flutter发送到消息.
final MethodChannel channel = new MethodChannel(registrar.messenger(), "asr_plugin"); //设置方法处理 MethodCallHandler MethodChannel 是flutter调用原生的方法 channel.setMethodCallHandler(this); @Override public void onMethodCall(MethodCall call, Result result) { //需要初始化权限 initPermission(); if (call.method.equals("getPlatformVersion")) { result.success("Android " + android.os.Build.VERSION.RELEASE); } else if (call.method.equals("start")) { start(call, result); } else if (call.method.equals("stop")) { stop(call, result); } else if (call.method.equals("cancel")) { cancel(call, result); } else if (call.method.equals("release")) { release(call, result); } else { result.notImplemented(); } } |
还有一个问题,如果将Native识别到语音.返回给Flutter呢? onMethodCall(MethodCall call, Result result)
在onMethodCall方法中有一个Result
对象,通过Result返回给Flutter
成功的返回mResult.success(o);
失败的返回 mResult.error(s, s1, o);
Flutter处理响应:
AsrPlugin.start().then((text) { print("------------start:" + text); if (text != null && text.length > 0) { setState(() { _result = text; }); } }).catchError((e) { print("------------catch:" + e.toString()); }); |
实现结果如下,已经识别出了语音.
Native如何集成Flutter?
-
创建flutter module
-
添加flutter module依赖
-
Java/object-c 调用flutter module
-
flutter 作为原生开发的独立的页面
-
flutter 作为原生页面的一部分
Add Flutter to existing apps 此处为官方的文档,解释的非常详细,如果英语好的话可以直接看官方的文档.
这里简单介绍一下集成的步骤
通过命令行的方式创建 Flutter module
> flutter create -t module flutter_module
运行完上面的命令就会生成一个名字为flutter_module的module项目,然后将这个module放到原生项目同级的目录下.
原生项目的配置:
setting.gradle 添加如下代码
setBinding(new Binding([gradle: this])) // newevaluate(new File( // new settingsDir.parentFile, // new 'flutter_hybrid/.android/include_flutter.groovy' // new )) |
注意flutter_hybrid
需要改成你用命令创建的module的名字如:flutter_module
app.gradle中配置如下
android { ...... compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 } } dependencies { implementation project(':flutter') } |
build 一下项目就将Flutter module 集成进来了
打开Flutter module
需要修改 main.dart
定义好跳转的Route页面
import 'dart:ui'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'list': return _listWidget(); case 'item': return _itemWidget(); case 'page': return _pageWidget(); } } Widget _listWidget() { return Container( child: ListView.builder( itemBuilder: (context, index) { return _itemWidget(); }, itemCount: 10, ), ); } Widget _itemWidget() { return Container( child: Text(//text 必须要有 textDirection TextDirection.ltr 否则会报错 'This is Flutter route item attach new', textDirection: TextDirection.ltr, ), color: Color(0x00fff122), ); } Widget _pageWidget() { return MyApp(); } |
原生项目中如何调用flutter页面?
- 将flutter页面作为某个view的一部分 ,通过定义好的Route名称来加载某个widget,同时需要将lifecycle生命周期传递进去
val createView = Flutter.createView(this, lifecycle, "item") fl_load.addView(createView) |
- 将flutter页面作为独立的页面
val beginTransaction = supportFragmentManager.beginTransaction() beginTransaction.replace(R.id.fl_only, Flutter.createFragment("page")) beginTransaction.commit() |
如何如何调试和热重载flutter module
如何热重载flutter module?
当打开flutter module时,并没有运行在当前的module,而是运行在原生的项目中,如果改动了module中的UI 如何热重载呢?在上面的官方文档中同样有详细的讲解
在当前的module中,点击Terminal 输入如下命令 ,就可以实现flutter module的热重载
flutter attach |
本篇文章主要讲解了flutter与native通信和flutter module作为native的部分界面
文章作者: JakePrim
文章链接: https://jakeprim.cn/2019/07/04/flutter-native-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 JakePrim技术研究院!