更多關注微信公衆號:Flutter入門java
Flutter與原生之間的通訊依賴靈活的消息傳遞方式:android
- MethodChannel // Flutter與原生方法相互調用,用於方法掉用
- BasicMessageChannel // Flutter與原生相互發送消息,用於數據傳遞
- EventChannel // 原生髮送消息,Flutter接收,用於數據流通訊
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: |
int, if 64 bits not enough | Java.lang.BigInteger | FlutterStandardBigInteger |
double | Java.lang.Double | NSNumber numberWithDouble |
String | java.lang.String | NSString |
Unit8List | 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調用Flutter方法:git
Android:github
//初始化,傳遞1. flutterView(MainActivity中getFlutter獲取),2. name常量,Flutter中使用同名常量
MethodChannel methodChannel = new MethodChannel(flutterView, 「testflutter」);
複製代碼
private void invokeFlutterMethod() {
if (this.mMethodChannel != null) {
this.mMethodChannel.invokeMethod("flutterMethod", "native參數", new MethodChannel.Result() {
@Override
public void success(Object o) {
Toast.makeText(mContext, o.toString(), Toast.LENGTH_LONG).show();
}
@Override
public void error(String s, String s1, Object o) {
}
@Override
public void notImplemented() {
}
});
}
}
複製代碼
經過MethodChannel調用invokeMethod("方法名","傳遞參數",[Flutter返回參數回調,非必須]);web
Flutter:微信
static const methodChannel = const MethodChannel('testflutter');
複製代碼
methodChannel.setMethodCallHandler(_addNativeMethod);
複製代碼
Future<dynamic> _addNativeMethod(MethodCall methodCall) async {
switch (methodCall.method) {
case 'flutterMethod':
setState(() {
_calledFromNative = 'flutter method called from native with param ' + methodCall.arguments;
});
return 'flutter method called from native with param ' + methodCall.arguments;
break;
}
}
//其中,return返回的數據在Android的回調中接收
複製代碼
Flutter調用Android方法:markdown
Android:數據結構
MethodChannel methodChannel = new MethodChannel(flutterView, METHOD_CHANNEL);
methodChannel.setMethodCallHandler(plugin);
複製代碼
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
// Flutter調用Native的方法
if (methodCall.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVALIABLE", "battery level unavaliable", null);
}
} else {
result.notImplemented();
}
}
//在onMethodCall中監聽Flutter調用什麼名字的方法(此處getBatterLevel),經過result返回方法的執行結果。
複製代碼
Flutter:異步
static const methodChannel = const MethodChannel('testflutter');
複製代碼
//方法通道的方法是異步的
Future<Null> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level $result .';
} on PlatformException catch (e) {
batteryLevel = 'Battery level unknown ${e.message}';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
複製代碼
Android給Flutter發消息:async
Android:
BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, "messageChannel", StandardMessageCodec.INSTANCE);
複製代碼
private void sendMessageToFlutter() {
if (this.mBasicMessageChannel != null) {
this.mBasicMessageChannel.send("Message From Native");
}
}
複製代碼
Flutter:
static const basicMessageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
複製代碼
void _listenMessageFromNative() {
basicMessageChannel.setMessageHandler(_receiveMessageFromNative);
}
複製代碼
//Flutter接收Native發來的消息
Future<dynamic> _receiveMessageFromNative(Object result) async {
setState(() {
_messageFromNative = result.toString();
});
}
複製代碼
Flutter給Android發消息:
Android:
BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, "messageChannel", StandardMessageCodec.INSTANCE);
messageChannel.setMessageHandler(plugin);
複製代碼
@Override
public void onMessage(Object o, BasicMessageChannel.Reply reply) {
Toast.makeText(mContext, o.toString(), Toast.LENGTH_LONG).show();
reply.reply(o.toString()+" back from native");
}
//reply返回數據給Flutter
複製代碼
Flutter:
static const basicMessageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
複製代碼
Future<dynamic> _sendMessageToNative(String message) async {
String reply = await basicMessageChannel.send(message);
print(reply);
setState(() {
_replayFromNative = reply;
});
return reply;
}
複製代碼
Android:
EventChannel eventChannel = new EventChannel(flutterView, EVENT_CHANNEL);
eventChannel.setStreamHandler(plugin);
複製代碼
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
BroadcastReceiver chargingBroadcastReceiver = createChargingBroadcaseReceiver(eventSink);
mContext.registerReceiver(chargingBroadcastReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object o) {
}
private BroadcastReceiver createChargingBroadcaseReceiver(EventChannel.EventSink eventSink) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
eventSink.error("UNAVALIABLE", "charging status is unavailable", null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING;
eventSink.success(isCharging ? "charging" : "disCharging");
}
}
};
}
複製代碼
Flutter:
static const _eventChannel = const EventChannel('charging');
複製代碼
void listenNativeEvent() {
_eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
//接收返回的數據
void _onEvent(Object object) {
String s = "Battery is ${object == 'charging' ? '' : 'dis'}Charging";
setState(() {
_batteryStatus = s;
});
}
複製代碼
Android:
public class MyTextview implements PlatformView {
TextView t;
public MyTextview(Context context, MessageCodec<Object> messenger, int id, Map<String, Object> params){
TextView textView = new TextView(context);
//獲取參數,是否有傳遞參數過來
if (params.containsKey("text")){
textView.setText(params.get("text").toString());
}
this.t = textView;
}
@Override
public View getView() {
return t;
}
@Override
public void dispose() {
}
}
複製代碼
public class TextViewFactory extends PlatformViewFactory {
private MessageCodec<Object> messageCodec;
public TextViewFactory(MessageCodec<Object> createArgsCodec) {
super(createArgsCodec);
this.messageCodec = createArgsCodec;
}
@Override
public PlatformView create(Context context, int i, Object o) {
return new MyTextview(context, messageCodec, i, (Map<String, Object>) o);
}
}
複製代碼
registrar.platformViewRegistry().registerViewFactory("TextView", new TextViewFactory(new StandardMessageCodec()));
//起名叫TextView,給Flutter用作viewType
複製代碼
Flutter:
AndroidView(
viewType: 'TextView',
creationParams: {'text': 'TTTeeeXXXttt'},
creationParamsCodec: new StandardMessageCodec(),
),//其中creationParams,creationParamsCodec必須同時存在或不存在
複製代碼
以上,正文結束;
官方還有一些其餘建議
Hosted packages(發佈到pub.dartlang.org)
$flutter packages pub publish --dry-run
$flutter packages pub publish
複製代碼
在yaml文件和其餘dependencies同樣使用。
Git packages(遠端)
代碼上傳到Git,並打一個tag
yaml文件引用
dependencies:
flutter_remote_package:
git:
url: git@gitlab....
ref: 0.0.1 //能夠是commit、branch、tag
複製代碼
本地
在Flutter App根目錄下建立plugins文件夾,把插件移動到plugins下。
dependencies:
flutter_plugin_batterylevel:
path: plugins/flutter_plugin_batterylevel
複製代碼
以上限於在建立工程的時候,使用的是plugins建立的,有時候會在本身的Android或iOS工程內部開發,就不這麼方便分離發佈了。
有時候須要到UI thread執行channelMethod,在Android上須要post一個Runnable到Android UI線程。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run(){
// call the desired channel message here.
}
})
複製代碼
所謂的「傳View」的本質是傳遞紋理ID,咱們只須要明白Flutter是經過Presentation實現了外接紋理,在建立Presentation時,傳入FlutterView對應的Context和建立出來的一個虛擬顯示屏對象,使得Flutter能夠直接經過ID找到並使用Native建立出來的紋理數據。
事件處理,從Native傳遞到Flutter這一階段Flutter按照本身的規則處理事件,若是AndroidView獲取到了事件,事件會被封裝成相應的Native端的事件經過方法通道傳回Native,Native再處理事件。
對於可能出現的滑動時間衝突,能夠參考官方註釋:
/// For example, with the following setup vertical drags will not be dispatched to the Android view as the vertical drag gesture is claimed by the parent [GestureDetector].
///
/// GestureDetector(
/// onVerticalDragStart: (DragStartDetails d) {},
/// child: AndroidView(
/// viewType: 'webview',
/// gestureRecognizers: <OneSequenceGestureRecognizer>[],
/// ),
/// )
///
/// To get the [AndroidView] to claim the vertical drag gestures we can pass a vertical drag gesture recognizer in [gestureRecognizers] e.g:
///
/// GestureDetector(
/// onVerticalDragStart: (DragStartDetails d) {},
/// child: SizedBox(
/// width: 200.0,
/// height: 100.0,
/// child: AndroidView(
/// viewType: 'webview',
/// gestureRecognizers: <OneSequenceGestureRecognizer>[new VerticalDragGestureRecognizer()],
/// ),
/// ),
/// )
複製代碼
[github]github.com/damengzai/f…
參考:
在Flutter中嵌入Native組件的正確姿式是... ——閒魚技術