Flutter和Android原生之间如何通信
作者:互联网
Flutter使用了一个灵活的系统,允许您调用特定平台的API,Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:
- 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。
- 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。
平台通道(platform channel)
既然Flutter是通过平台通道(platform channel)实现Flutter和原生端的数据传递的。那么先看下官网的架构图
由图可以看出,在客户端,MethodChannel (API)可以发送与方法调用相对应的消息。 在宿主平台上MethodChannel 在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法调用并返回结果。
注意:使用平台通道在客户端(Flutter UI)和宿主(平台)之间传递消息,消息和响应是异步传递的,以确保用户界面保持响应(不会挂起)。
Flutter中定义了几种不同的channel:
根据上图可以看出几种channel 之间的区别
BasicMessageChannel:
通过异步传递message与平台进行通信
/// A named channel for communicating with platform plugins using asynchronous
/// message passing.
EventChannel:
通过流的方式与平台进行通信
/// A named channel for communicating with platform plugins using event streams.
MethodChannel:
通过异步方法调用的方式与平台进行通信
/// A named channel for communicating with platform plugins using asynchronous
/// method calls.
OptionalMethodChannel:
继承于MethodChannel 忽略了平台
/// A [MethodChannel] that ignores missing platform plugins.
暂时拿MethodChannel进行深入分析
根据MethodChannel构造方法知道,MethodChannel对象的创建需要两个参数 name跟MethodCodec。
name是MethodChannel的唯一标识,可以理解成channel名字。
codec是用于方法调用和封装结果的编解码器,决定了我们能传递什么类型的数据。
标准的编解码器有如下规则:
接下来先学习下MethodChannel的使用,边用边分析,Flutter和native间的通信,分为 Flutter主动发送 和 native主动发送 两种情况。
Flutter主动发送给原生
官网例子:https://github.com/flutter/flutter/tree/master/examples/platform_channel
在dart文件中的实现:
static const MethodChannel methodChannel =
MethodChannel('samples.flutter.io/battery');
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level: $result%.';
} on PlatformException {
batteryLevel = 'Failed to get battery level.';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
在native端
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package com.example.platformchannel;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";
private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), BATTERY_CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
}
);
}
private int getBatteryLevel() {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
}
}
以上就是从Flutter端主动发起与native端的通信,dart通过await methodChannel.invokeMethod(‘getBatteryLevel’)发送消息,native端通过MethodChannel中MethodCallHandler的onMethodCall进行接收flutter的通信,并通过result.success进行回传信息。
有几点需要注意
- dart中methodChannel 声明的时候的 name要保证与native端的一致,且唯一。
- dart中methodChannel.invokeMethod(‘getBatteryLevel’),在native端要进行判断,只有方法名匹配才给予响应, if (call.method.equals(“getBatteryLevel”))。
这里flutter通过 invokeMethod与native进行通信
查看invokeMethod()方法, method为 MethodCall的标识, arguments为参数,注意这里的参数必须要遵守上面的规则(默认情况下不能直接传自定义类,但是我们可以将其转为Json之后再传递,也可以去改造 MethodCode,以此进行复杂数据结构的传递)。
注:可以看到,其是一个 async标记的方法,返回值为Future。那么我们在接受这个方法的返回值的时候,就必须要使用 await进行修饰。要调用使用 await,必须在有 async标记的函数中运行。具体调用和使用的方式可以看官网的例子。在这我们先继续深入。
BinaryMessages.send()
接下来_sendPlatformMessage()——window.sendPlatformMessage()
最终调用native方法与原生进行通信的。
在flutter engine中查看源码
看最关键的方法: dart_state->window()->client()->HandlePlatformMessage()
一步一步跟下来 到了 这里g_handle_platform_message_method
接下来就是 在FlutterJNI 与 FlutterNativeView 之间进行绑定了
这里就可以通过JNI调用Android 端了。
原生主动发送给Flutter
/**
* native data to dart
*/
private void native2Dart() {
/**
* 数据流的通信(event streams)
*/
EventChannel eventChannel = new EventChannel(getFlutterView(), EVENT_CHANNEL);
EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventSink eventSink) {
Log.e("plateform_channel", "arguments: " + arguments.toString());
eventSink.success(data);
}
@Override
public void onCancel(Object arguments) {
Log.e("plateform_channel", "arguments: " + arguments.toString());
}
};
eventChannel.setStreamHandler(streamHandler);
}
Flutter端:
static const EventChannel eventChannel =
EventChannel(FlutterChannel.CHANNEL_RECEIVE_DATA);
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream(['arg1', 'arg2']).listen(_onEvent,
one rror: _onError);
}
void _onEvent(Object event) {
var animal = json.decode(event);
print(AnimalsRoot.fromJson(animal).animals.cat.name);
setState(() {
_receive_data = '$event';
});
}
void _onError(Object error) {
setState(() {
_receive_data = 'Receive failed';
});
}
用图表示其中的关联就是
这里有我学习Flutter过程中的一个Demo,会持续更新Demo的内容,对Flutter 有兴趣的朋友可以一起学习。
https://github.com/CodingForAndroid/flutter_new
标签:原生,flutter,MethodChannel,io,import,Android,Flutter,channel 来源: https://blog.csdn.net/u011733020/article/details/89262132