Flutter接收FCM消息调用Android原生代码报MissingPluginException
问题:FCM后台消息中调用Android原生方法报MissingPluginException
错误信息
E/flutter (16352): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method wakeUpApp on channel com.diesetelecom.smartdiese.androidChannel) E/flutter (16352): #0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:332:7) E/flutter (16352): <asynchronous suspension>
已尝试卸载应用、flutter clean、flutter pub get、flutter run,问题依旧。仅在FCM后台消息处理函数中调用原生方法时报错,前台场景调用正常。
相关代码
Flutter端(main.dart)
@pragma('vm:entry-point') Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { ... const MethodChannel androidChannel = MethodChannel('com.diesetelecom.smartdiese.androidChannel'); androidChannel.invokeMethod("wakeUpApp"); } Future<void> main() async { ... FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); ... await AssetsManager.initAssets(); await dotenv.load(); runApp(const App()); }
Android端(MainActivity.kt)
package com.diesetelecom.smart_diese import android.content.Context import android.content.Intent import android.media.AudioManager import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import android.util.Log class MainActivity: FlutterActivity() { private val CHANNEL = "androidChannel" override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "switchAudioOutput") { val audioManager: AudioManager = getApplicationContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager audioManager.setMode(AudioManager.MODE_IN_CALL) audioManager.setSpeakerphoneOn(!audioManager.isSpeakerphoneOn) result.success(audioManager.isSpeakerphoneOn) } else if(call.method == "wakeUpApp") { Log.d("ActivityMain", "This is a small test text") result.success(true) } else { result.notImplemented() } } } }
问题原因
FCM的firebaseMessagingBackgroundHandler运行在独立的后台Isolate中,这个Isolate没有关联到MainActivity初始化的Flutter主Engine。而MainActivity里注册的MethodChannel是绑定在主Engine上的,后台Isolate无法访问该通道,因此抛出MissingPluginException。前台调用时处于主Engine的上下文,所以正常工作。
解决方案
方案一:自定义FirebaseMessagingService直接处理(推荐,逻辑更直接)
跳过Flutter后台Handler,直接在Android原生的Firebase消息服务中处理唤醒逻辑:
- 创建
MyFirebaseMessagingService.kt:
package com.diesetelecom.smart_diese import android.content.Intent import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 唤醒App的逻辑 val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) } launchIntent?.let { startActivity(it) } } }
- 在
AndroidManifest.xml中注册该服务:
<application ...> <!-- 原有内容 --> <service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application>
方案二:在Application类中注册全局MethodChannel
如果需要保留Flutter后台Handler的逻辑,可在Application类中初始化独立的Flutter Engine并注册MethodChannel:
- 创建
MyApp.kt:
package com.diesetelecom.smart_diese import android.app.Application import android.content.Intent import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngineCache import io.flutter.embedding.engine.dart.DartExecutor import io.flutter.plugin.common.MethodChannel class MyApp : Application() { private val CHANNEL = "com.diesetelecom.smartdiese.androidChannel" lateinit var backgroundFlutterEngine: FlutterEngine override fun onCreate() { super.onCreate() // 初始化后台Flutter Engine backgroundFlutterEngine = FlutterEngine(this) backgroundFlutterEngine.dartExecutor.executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ) // 注册MethodChannel MethodChannel(backgroundFlutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when(call.method) { "wakeUpApp" -> { val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) } launchIntent?.let { startActivity(it) } result.success(true) } else -> result.notImplemented() } } // 缓存Engine供后台Isolate使用 FlutterEngineCache.getInstance().put("background_engine", backgroundFlutterEngine) } }
- 修改
AndroidManifest.xml指定Application类:
<application android:name=".MyApp" ...> <!-- 原有内容 --> </application>
- Flutter端保持原代码不变,确保MethodChannel名称与Android端一致。
内容的提问来源于stack exchange,提问作者Joel Nogues
相关产品推荐
相关产品推荐

