BasicMessageChannel 无法接收消息

843 阅读2分钟

作为Flutter新手,使用BasicMessageChannel从Android端发送消息给Flutter,却发现无法收到消息,百思不解,折腾了不少时间,最终看了下FlutterActivity源码才解决,很有必要记录下。

场景说明

Flutter以module形式嵌入到现有Android工程中,有一个需求,从Android端开启一个Flutter页面时,将一些基本信息传给Flutter。于是选择使用BasicMessageChannel从Android端向Flutter发送消息。

android端发送

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)

    val bmc = BasicMessageChannel(flutterEngine.dartExecutor.binaryMessenger,
        "basic_msg_channel", StandardMessageCodec.INSTANCE)

    val map = HashMap<String, String>()
    map.put("a", "1")
    map.put("b", "2")

    bmc.send(map)
}

Flutter端接收消息

@override
void initState() {
    super.initState();
    const msgChannel = const BasicMessageChannel('basic_msg_channel',
        StandardMessageCodec());
    msgChannel.setMessageHandler((message) => Future(() async{
        print(message["a"]);
        return "";
    }));
}

预热

刚开始使用预热模式,在Application中事先创建FlutterEngine并缓存使用,这种情况下可以保证首次打开Flutter页面不出现黑屏。事先预热情况下,上述发送和接收消息都是正常的。

非预热

不事先预热,每次启动SubActivity时创建FlutterEngine,此时在Flutter端无法接收到Android端发送的消息,怎么回事?

首先看看FlutterEngine的创建时机,查看FlutterActivity的onCreate方法:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    switchLaunchThemeForNormalTheme();

    super.onCreate(savedInstanceState);

    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onActivityCreated(savedInstanceState);

    configureWindowForTransparency();
    setContentView(createFlutterView());
    configureStatusBarForFullscreenFlutterExperience();
}

这里创建了一个FlutterActivityAndFragmentDelegate,继续查看delegate.onAttach(this)方法,会发现在这里创建了FlutterEngine,并在最后回调了configureFlutterEngine方法,于是在子类中可以借助新创建的FlutterEngine创建BasicMessageChannel。

这里比较下和预热模式的区别,onCreate中创建了FlutterEngine,但是没有执行DartEntryPoint,很可能的原因就在于此。继续查看FlutterActivity的onStart方法会发现,里边调用了delegate.onStart(),进而调用了doInitialFlutterViewRun,这个方法是关键,看下源码:

 private void doInitialFlutterViewRun() {
    ……
    // Configure the Dart entrypoint and execute it.
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            host.getAppBundlePath(), host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }

这里忽略了前边的一系列if判断,最后看到这里执行了DartEntrypoint。于是发现Android端在configureFlutterEngine中发送消息时,dart代码并未执行,可能channel通道并未建立起来,所以后来Flutter页面起来后,始终无法接收消息。

于是将Android端发送消息的代码移到子类的onStart方法中,一切正常!