使用MethodChannel实现本地和flutter之间的通信

在使用MethodChannel的时候也需要分几种情形,不同情形处理的细节不太一样。

第一种情形,假设先启动一个普通的MainActivity,然后再点击按钮,启动一个默认FlutterActivity的

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.view.FlutterMain;

public class MainActivity extends AppCompatActivity {
    private static final String CHANNEL_NATIVE = "com.example.flutter/native";
    private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        FlutterMain.startInitialization(getApplicationContext());
        prepareFlutterEngine();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first_native);
        Button btnOpen = findViewById(R.id.button001);
        btnOpen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                		startActivity(
//				FlutterActivity.createDefaultIntent(this)
                                FirstFlutterActivity
						.withCachedEngine("my_engine_id")
						.build(MainActivity.this)
		);
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            TextView textView = findViewById(R.id.textView001);
            textView.setText(data.getStringExtra("message"));
        }
    }

    void prepareFlutterEngine(){
        // Instantiate a FlutterEngine.
        FlutterEngine flutterEngine = new FlutterEngine(getApplication());
        flutterEngine.getNavigationChannel().setInitialRoute("route1");
//        // Start executing Dart code to pre-warm the FlutterEngine.
        flutterEngine.getDartExecutor().executeDartEntrypoint(
                DartExecutor.DartEntrypoint.createDefault()
        );
//        // Cache the FlutterEngine to be used by FlutterActivity.
        FlutterEngineCache
                .getInstance()
                .put("my_engine_id", flutterEngine);
        configureFlutterEngine(flutterEngine);
    }

    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        Log.d("FirstNativeActivity","configureFlutterEngine");
        GeneratedPluginRegistrant.registerWith(flutterEngine);//重要,注册plugin,如果不注册,可能会无法正常通信
        MethodChannel mc = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NATIVE); //此处名称应与Flutter端保持一致
        mc.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
                switch (call.method){
                    case "backAction":
                        Log.d("ldw","flutter 页面中 backAction被触发");
                        onBackPressed();
                        result.success("成功通过虚拟按键返回第一个原生页面");
                        break;
                    default :
                        Log.d("ldw","notImplemented");
                        result.notImplemented();
                        break;
                }
            }
        });
    }
}

然后在flutter中需要写一下点击事件,通过handler传递给MainActivity来处理

void main() => runApp(_widgetForRoute(window.defaultRouteName));
Widget _widgetForRoute(String url) {
  // route名称
  String route ="默认";
  route = url.indexOf('?') == -1 ? url : url.substring(0, url.indexOf('?'));
  print('defaultRouteName:$url');
// 参数Json字符串
  String paramsJson =
  url.indexOf('?') == -1 ? '{}' : url.substring(url.indexOf('?') + 1);
  Map mapJson = json.decode(paramsJson);
  String message = "默认message";
  message = mapJson["message"];
// 解析参数
  switch (route) {
    case 'route1':
      return MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text('Flutter页面'),
          ),
          body: ContentWidget(route: route,message: message,),
        ),
      );
    default:
      return Center(
        child: Text('sorry Unknown route: $route',style: TextStyle(color: Colors.red), textDirection: TextDirection.ltr),
      );
  }
}

class ContentWidget extends StatefulWidget{
  ContentWidget({Key key, this.route,this.message}) : super(key: key);
  String route,message;
  _ContentWidgetState createState() => new _ContentWidgetState();
}
class _ContentWidgetState extends State{
//初始化MethodChannel
  static const nativeChannel = const MethodChannel('com.example.flutter/native');
Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
      child: Stack(
        children: [
          Positioned(
            top: 100,
            left: 0,
            right: 0,
            height: 100,
            child: Text(widget.message,textAlign: TextAlign.center,),
          ),
          Positioned(
            top: 200,
            left: 100,
            right: 100,
            height: 100,
            child: RaisedButton(
                child: Text('打开上一个原生页面'),
                onPressed: (){
                  //触发
                    returnLastNativePage(nativeChannel);
                }
            ),
          ),
        ],
      ),

    );
  }
}

Future returnLastNativePage(MethodChannel channel) async{
  //参数
//  const channel = const MethodChannel('com.example.flutter/native');
//  static const flutterChannel = const MethodChannel('com.example.flutter/flutter');
  Map para = {'message':'嗨,本文案来自Flutter页面,回到第一个原生页面将看到我'};
  final String result = await channel.invokeMethod('backAction',para);
  print('这是在flutter中打印的'+ result);
}

第二种情形,启动的第一个MainActivity便是flutter的入口,继承自FlutterActivity,那么只要在MainActivity中重写即可

import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodChannel

class MainActivity extends FlutterActivity() {
    @override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        Log.d("FirstNativeActivity","configureFlutterEngine");
        MethodChannel mc = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NATIVE); //此处名称应与Flutter端保持一致
        mc.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
                switch (call.method){
                    case "backAction":
                        Log.d("ldw","backAction");
                        onBackPressed();
                        result.success("成功通过虚拟按键返回第一个原生页面");
                        break;
                    default :
                        Log.d("ldw","notImplemented");
                        result.notImplemented();
                        break;
                }
            }
        });
    } 

}

然后再flutter中触发backAction等事件即可

第三种情形,假设先启动一个普通的MainAcitivity,然后再点击按钮,启动一个自定义的FlutterActivity的,比如叫FirstFlutterActivity,且要指定一个route页面

则可以这么写

import android.util.Log;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class FirstFlutterActivity extends FlutterActivity {
    private static final String CHANNEL_NATIVE = "com.example.flutter/native";
    private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        Log.d("ldw","configureFlutterEngine:"+flutterEngine.toString());
        super.configureFlutterEngine(flutterEngine);
        FlutterEngineCache.getInstance().put("my_engine_id",flutterEngine);
        MethodChannel  mc = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NATIVE); //此处名称应与Flutter端保持一致
        mc.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
                switch (call.method){
                    case "backAction":
                        finish();
                        result.success("成功通过虚拟按键返回第一个原生页面");
                        break;
                    default :
                        result.notImplemented();
                        break;
                }
            }
        });
    }
}

然后在MainActivity中启动这个自定义的FirstFlutterActivity

Button btnOpen = findViewById(R.id.button001);
btnOpen.setOnClickListener(new View.OnClickListener() {
       @Override
      public void onClick(View view) {
            Intent intent = new Intent(FirstNativeActivity.this,FirstFlutterActivity.class);
                intent.putExtra("message","嗨,我是测试内容");//表示指定打开哪个route,传递给FlutterActivity使用
                intent.putExtra("route","route1?{\"message\":\"" + "我是测试内容" + "\"}");
                startActivityForResult(intent, Activity.RESULT_FIRST_USER);
            }
        });

其中

intent.putExtra("message","嗨,我是测试内容");

是指定了要打开的页面,不传这个值,会打开默认的route 即 "/"

不过改方式是通过阅读源码,看到源码中是这么使用的,在第三种方式中,我还没找到更好的打开指定route的方式

你可能感兴趣的:(android,flutter,app,flutter)