Flutter 和Android 的互動之 MethodChannel
阿新 • • 發佈:2020-12-19
技術標籤:Flutter 原生互動MethodChannel
Flutter 和 Android 的互動網上的博文非常多,包括Flutter中文網上面關於MethodChannel 的內容,都已經過時了。比如Fluter 中文網上面寫道的Android客戶端整合如下:
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common. MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}
上面整合的是 io.flutter.app.FlutterActivity,通過 getFlutterView() 和 字串來 構造 MethodChannel ,然後設定來自於 Flutter 呼叫的監聽。
現在我們整合新的 Flutter SDK ,繼承的Activity是 io.flutter.embedding.android.FlutterActivity,此FlutterActivity已經不存在 getFlutterView()
方法了,所以Android 和 Flutter的互動也要改變。
整合的流程如下:
1.Android 客戶端的程式碼如下:
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodChannel;
public class FlutterAppActivity extends FlutterActivity {
private final static String CHANNEL_NATIVE = "com.zhujiangtao.flutter";
private MethodChannel mMethodChannel;
public static void enter(Context context) {
Intent intent = new NewEngineIntentBuilder(FlutterAppActivity.class)
.initialRoute("zhujiangtao?msg=test&id=10010")
.build(context);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化 MethodChannel
mMethodChannel = new MethodChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), CHANNEL_NATIVE);
// Flutter 呼叫 android 的方法會執行到此回撥
mMethodChannel.setMethodCallHandler((call, result) -> {
Log.e("xxxxx", "method = " + call.method);
switch (call.method) {
case "callNative":
Toast.makeText(FlutterAppActivity.this, call.argument("arg1"), Toast.LENGTH_LONG).show();
callFlutter();
// 將結果回撥給 Flutter
result.success("我是來自Native的回撥");
break;
}
});
}
private void callFlutter() {
// Android 端呼叫 Flutter 的方法
mMethodChannel.invokeMethod("callFlutter", "name=zhujiangtao", new MethodChannel.Result() {
@Override
public void success(@Nullable Object result) { // Flutter 回撥過來的結果
if (result != null) {
Toast.makeText(FlutterAppActivity.this, result.toString(), Toast.LENGTH_LONG).show();
}
}
@Override
public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
}
@Override
public void notImplemented() {
}
});
}
}
裡面清晰的註釋了,Android 是如何呼叫 Flutter 和 Flutter 是怎麼呼叫Android的。
2. AndroidManifest.xml 中註冊且處理跳轉到Flutter頁面黑屏問題
<!--就是之前寫的Activity-->
<activity android:name=".ui.FlutterAppActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<!--解決android進入Flutter的黑屏問題-->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/flutter_splash_bg" />
</activity>
3. Flutter 端的程式碼呼叫原生方法和原生呼叫Flutter的回撥
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:my_flutter/pages/list_view.dart';
class MyMethodChannel extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return MyMethodState();
}
}
class MyMethodState extends State<MyMethodChannel>{
String _content;
// 這裡面的 “com.zhujiangtao.flutter”要和 Java 程式碼中 初始化 MethodChannel的值保持一致
static MethodChannel _methodChannel = MethodChannel('com.zhujiangtao.flutter');
@override
void initState() {
_methodChannel.setMethodCallHandler(_methodChannelHandler);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("TestMethodChannel"),),
body: Center(
child: Column(
children: <Widget>[
Text('$_content'),
RaisedButton(
onPressed: callNative,
child: Text("callNative"),
),
RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => TestListView()));
},
child: Text('ListView'),
),
],
),
),
);
}
/// Flutter 呼叫原生
Future<void> callNative() async {
print("----------------callNative--------------------");
var res = await _methodChannel.invokeMethod("callNative", {"arg1": "I am from Flutter"});
//Android收到呼叫之後返回的資料
setState(() {
_content = res;
});
}
/// 原生 呼叫 Flutter的結果回撥
Future<String> _methodChannelHandler(MethodCall call) async{
String result = "";
print("---------------_methodChannelHandler------------------------ method = ${call.method}");
switch(call.method){
case "callFlutter":
setState(() {
_content = call.arguments.toString();
});
result = "Flutter 收到 Android發來的訊息";
break;
}
return result;
}
}
裡面也是 初始化 MethodChannel ,然後邏輯和原生的差不多;
invokeMethod :原生和Flutter都是呼叫此方法來和對方通訊;
setMethodCallHandler:都是結果的回撥。
以上就是 Flutter 和 原生 的互動過程。