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
相关产品推荐
相关产品推荐

