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

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消息服务中处理唤醒逻辑:

  1. 创建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) }
    }
}
  1. 在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:

  1. 创建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)
    }
}
  1. 修改AndroidManifest.xml指定Application类:
<application
    android:name=".MyApp"
    ...>
    <!-- 原有内容 -->
</application>
  1. Flutter端保持原代码不变,确保MethodChannel名称与Android端一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:27:32