You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter跨Activity调用MethodChannel报MissingPluginException问题

问题描述

在MainActivity.kt中调用goToSecondActivity方法跳转至第二个Activity,尝试在SecondActivity中使用MethodChannel完成通信时功能异常,MethodCallHandler回调完全不触发,抛出如下报错:

MissingPluginException(No implementation found for method updatePosition on channel com.example.ble_poc/map_channel)

已确认代码中配置的通道名称完全一致,且对应方法逻辑已实现。

原有问题代码

MainActivtiy.kt

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.ble_poc/channel"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegister.registerGeneratedPlugins(FlutterEngine(this@MainActivity))
        MethodChannel(flutterEngine?.dartExecutor!!, CHANNEL).setMethodCallHandler { call, result ->
            if(call.method.equals("goToSecondActivity")){
                goToSecondActivity()
            } else {
                print("Result not implemented in MainActivity")
                result.notImplemented()
            }
        }
    }

    private fun goToSecondActivity() {
        startActivity(Intent(this@MainActivity, SecondActivity::class.java))
    }
}

SecondActivity.kt

class SecondActivity: FlutterActivity() {
    private val CHANNEL = "com.example.ble_poc/map_channel"

    private lateinit var mapView: MPIMapView
    private val venueDataString: String by lazy { readFileContentFromAssets("mappedin-demo-mall.json") }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegister.registerGeneratedPlugins(FlutterEngine(this@SecondActivity))
        MethodChannel(flutterEngine?.dartExecutor!!.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if(call.method.equals("updatePosition")){
                println("Update position call is triggered")
                val lat = call.argument<Double>("lat")
                val long = call.argument<Double>("long")
                val accuracy = call.argument<Double>("accuracy") ?: 7.170562529369844
                val floorLevel = call.argument<Int>("floor") ?: 0
                updatePosition(lat!!, long!!, accuracy, floorLevel)
            } else {
                print("Result not implemented in SecondActivity")
                result.notImplemented()
            }
        }
// ...

main.dart

static const CHANNEL = "com.example.ble_poc/channel";
static const MAP_CHANNEL = "com.example.ble_poc/map_channel";
static const platform = MethodChannel(CHANNEL);
static const map_platform = MethodChannel(MAP_CHANNEL);

void openMap() async {
  try {
    platform.invokeMethod('goToSecondActivity');
    Timer(const Duration(seconds: 4), () {
      map_platform.invokeMethod(
        "updatePosition",
        {
          "lat": 43.52023014,
          "long": -80.5352595,
        },
      );
    });
  } on PlatformException catch (e) {
    print(e.message);
  }
}
// ...
问题根因
  • 核心错误是在两个Activity的onCreate中手动新建了FlutterEngine实例。每个FlutterEngine对应独立的Dart运行环境,启动App时Dart代码只运行在系统默认初始化的引擎上,手动new的新引擎没有加载任何Dart代码,在新引擎上注册的MethodChannel自然永远收不到Dart侧的消息。
  • 手动调用GeneratedPluginRegister.registerGeneratedPlugins是多余操作,默认FlutterActivity生命周期会自动完成插件注册,重复手动注册反而可能引发引擎状态异常。
  • 用固定时长Timer延迟发送消息的逻辑不可靠,SecondActivity的MethodChannel可能还没完成绑定,消息就已经发出,同样会触发找不到实现的报错。
修复步骤
  • 移除所有手动新建FlutterEngine、手动调用插件注册的代码,不要自己创建新的Dart运行环境。
  • 所有MethodChannel绑定操作移到configureFlutterEngine生命周期回调中执行,这个回调返回的是已经和Dart侧连通的可用引擎,不会出现引擎未运行、空引用的问题。
  • 配置SecondActivity复用MainActivity正在运行的FlutterEngine,保证Dart侧和原生侧操作的是同一个引擎实例。
  • 移除固定延迟Timer逻辑,改成SecondActivity完成通道绑定后主动通知Dart侧,确认就绪后再发送位置更新消息。
  • 在AndroidManifest.xml中为SecondActivity补充正确的配置参数,保证页面启动模式、配置变更监听符合Flutter引擎要求。

修复后代码

MainActivity.kt

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.ble_poc/channel"
    // 给当前主引擎设置固定缓存id,供SecondActivity复用
    override fun getCachedEngineId(): String = "main_engine"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if(call.method == "goToSecondActivity"){
                goToSecondActivity()
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun goToSecondActivity() {
        // 跳转时指定复用id为main_engine的缓存引擎,不新建引擎
        startActivity(
            CachedEngineActivityIntentBuilder("main_engine")
                .build(this)
                .setClass(this, SecondActivity::class.java)
        )
    }
}

SecondActivity.kt

class SecondActivity: FlutterActivity() {
    private val CHANNEL = "com.example.ble_poc/map_channel"
    private lateinit var mapView: MPIMapView
    private val venueDataString: String by lazy { readFileContentFromAssets("mappedin-demo-mall.json") }

    // 指定复用id为main_engine的缓存引擎
    override fun getCachedEngineId(): String = "main_engine"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            when(call.method) {
                "updatePosition" -> {
                    println("Update position call is triggered")
                    val lat = call.argument<Double>("lat")
                    val long = call.argument<Double>("long")
                    val accuracy = call.argument<Double>("accuracy") ?: 7.170562529369844
                    val floorLevel = call.argument<Int>("floor") ?: 0
                    updatePosition(lat!!, long!!, accuracy, floorLevel)
                    result.success(null)
                }
                else -> result.notImplemented()
            }
        }
        // 通道绑定完成后,主动通知Dart侧页面就绪
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).invokeMethod("secondActivityReady", null)
    }

    // 原有地图初始化逻辑保持不变
    // ...
}

main.dart

static const CHANNEL = "com.example.ble_poc/channel";
static const MAP_CHANNEL = "com.example.ble_poc/map_channel";
static const platform = MethodChannel(CHANNEL);
static const map_platform = MethodChannel(MAP_CHANNEL);

void openMap() async {
  try {
    bool isReady = false;
    // 监听SecondActivity就绪通知
    map_platform.setMethodCallHandler((call) async {
      if(call.method == "secondActivityReady" && !isReady) {
        isReady = true;
        // 收到就绪通知后再发位置更新消息
        map_platform.invokeMethod(
          "updatePosition",
          {
            "lat": 43.52023014,
            "long": -80.5352595,
          },
        );
      }
    });
    await platform.invokeMethod('goToSecondActivity');
  } on PlatformException catch (e) {
    print(e.message);
  }
}
// ...

AndroidManifest.xml 补充配置

在manifest的application节点下补充SecondActivity的声明:

<activity
    android:name=".SecondActivity"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize"
/>
注意事项
  • 所有MethodChannel的绑定、销毁操作都要和FlutterEngine生命周期对齐,不要在onCreate里直接拿flutterEngine操作,避免空指针或者引擎未初始化的问题。
  • 除非有明确的多Dart运行环境需求,否则不要手动新建FlutterEngine,复用默认缓存的引擎可以避免90%以上的MethodChannel通信问题。
  • 跨组件、跨页面的MethodChannel通信不要依赖固定时长延迟,用就绪回调、状态监听的方式触发消息发送,避免时序问题。

内容的提问来源于stack exchange,提问作者Blue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 07:27:36