前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >纯Flutter工程如何实现Flutter与原生互相通信

纯Flutter工程如何实现Flutter与原生互相通信

原创
作者头像
brzhang
发布2020-05-28 19:38:30
1.9K0
发布2020-05-28 19:38:30
举报
文章被收录于专栏:玩转全栈玩转全栈

大多数同学都知道Flutter与原生通信MethodChannel或者EventChannel。这两个Channel在我之前的文章中有讲到区别和共同点,我们知道本质上都是MethodChannel。

我们还知道,在开发插件的过程中,免不了要使用这两个哥们来帮我们进行原生与Flutter互通。

今天,我们遇到的问题是,我们一个纯粹的flutter工程,如果,需要在Flutter中调用原生,或者在原生中取调用到flutter中的代码,我们该如何做。

首先,我们来看第一个问题:

如何在Flutter中调用原生代码

代码语言:javascript
复制
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) {
                        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();
                        }
                    }
                });
    }
}

以上是官方给出的一个例子,我们在onMethodCall中实现需要的逻辑即可,所以,我们在flutter中就可以

代码语言:javascript
复制
// Get battery level.
  String _batteryLevel = 'Unknown battery level.';

  Future<Null> _getBatteryLevel() async {
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

已这样的方式调用原生代码了。

那么有没有想过,为啥这样就可以使得Flutter调用原生了呢?

我们看一下MethodChannel的构造方法,第一个参数是一个BinaryMessenger,而,我们在原生中构造的那个MethodChannel

传入的第一个参数是getFlutterView,其实就是FlutterView了,看源码可以知道,FlutterView实际上是实现了BinaryMessenger

这个接口的。所以,沟通两者的桥梁就是这个BinaryMessenger了,话句话说,Flutter能和原生通信,纯属于BinaryMessenger

功劳

代码语言:dart
复制
/**
   * Creates a new channel associated with the specified {@link BinaryMessenger} and with the
   * specified name and the standard {@link MethodCodec}.
   *
   * @param messenger a {@link BinaryMessenger}.
   * @param name a channel name String.
   */
  public MethodChannel(BinaryMessenger messenger, String name) {
    this(messenger, name, StandardMethodCodec.INSTANCE);
  }

那么,反过来呢?

如何在原生中去调用Flutter端的代码?

不用想,桥梁应该还是BinaryMessenger无疑,但是,这次有谁来搭这个通道呢?应该是Flutter端搭建这个通道,因为刚才Flutter调用原生的时候,是原生来准备这个调用环境的。因此。我们在Flutter端这么做。

代码语言:javascript
复制
MethodChannel methodChannel = new MethodChannel('intl:intl-globle-notify');
methodChannel.setMethodCallHandler((MethodCall call) async {
  if (call.method == "onLoginSuccess") {
    userInfoNotifier.getUserInfo();
  } else if (call.method == "onAuthSuccess") {
    userInfoNotifier.getUserInfo();
  }
});

啦搭建这个通道,随后,在原生中,我们应该在哪里去连接上这个通道呢?

其实无所谓在哪里,只要你能找到这个BinaryMessenger即可,在哪里找呢,在MainActivity extends FlutterActivity 这个Activity的 configureFlutterEngine 方法中。

代码语言:javascript
复制
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    super.configureFlutterEngine(flutterEngine);
    flutterEngine.getPlugins().add(new ITLoginPlugin());
    methodChannel = new MethodChannel(flutterEngine.getDartExecutor(),"intl:intl-globle-notify");
}

为什么是这里,以为这里比较方便拿到 这个BinaryMesenger,如果你找到其他地方比较方便拿到这个BinaryMesenger,也可以在其他地方初始化。

好事者(比如说我自己)就问了,这个BinaryMesenger是同一个的吗?从目前来看,是的。都应该是这个

代码语言:javascript
复制
BinaryMessenger get defaultBinaryMessenger {
  assert(() {
    if (ServicesBinding.instance == null) {
      throw FlutterError(
        'ServicesBinding.defaultBinaryMessenger was accessed before the '
        'binding was initialized.\n'
        "If you're running an application and need to access the binary "
        'messenger before `runApp()` has been called (for example, during '
        'plugin initialization), then you need to explicitly call the '
        '`WidgetsFlutterBinding.ensureInitialized()` first.\n'
        "If you're running a test, you can call the "
        '`TestWidgetsFlutterBinding.ensureInitialized()` as the first line in '
        "your test's `main()` method to initialize the binding."
      );
    }
    return true;
  }());
  return ServicesBinding.instance.defaultBinaryMessenger;
}

所以,今天,我们就学会了:

1、如何在Flutter中调用原生代码。

2、如何在原生中调用Flutter代码。

总结一下,如果觉得业务逻辑有点多,完全可以将代码逻辑放在一个插件中。

代码语言:javascript
复制
flutterEngine.getPlugins().add(newITLoginPlugin());

类似于这样了,对于插件的编写,相信有一堆的文章知道你如何办。插件中,很显然通道的打通都是靠那个BinaryMessenger。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何在Flutter中调用原生代码
  • 如何在原生中去调用Flutter端的代码?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档