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

Flutter Android端MethodChannel报MissingPluginException问题排查

Flutter Android应用MethodChannel发送SMS遇MissingPluginException问题

错误信息

E/flutter (10616): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method sendSMS on channel channel_name)
E/flutter (10616): #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:332:7)
E/flutter (10616): <asynchronous suspension>
E/flutter (10616): #1      SmsService.sendSms (package:muteify/services/sms_service.dart:8:30)
E/flutter (10616): <asynchronous suspension>
E/flutter (10616): #2      phoneStateBackgroundCallbackHandler (package:muteify/services/phone_state_bg_helper.dart:16:19)
E/flutter (10616): <asynchronous suspension>

Flutter端Dart代码

import 'package:flutter/services.dart';

const platform = MethodChannel('channel_name');

class SmsService {
  Future<String?> sendSms(String phone, String message) async {
    try {
      final String? result = await platform.invokeMethod<String?>('sendSMS', {
        'phone': phone,
        'message': message,
      });
      print("SMS result:  $result");
      return result;
    } on PlatformException catch (e) {
      return "Failed to send SMS: '${e.message}'.";
    }
  }
}

Android端MainActivity.kt代码

@file:Suppress("DEPRECATION")

package com.example.muteify

import android.telephony.SmsManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result

class MainActivity : FlutterActivity() {
    private val channel = "channel_name"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { call, result ->
            if (call.method == "sendSMS") {
                val customerPhone = call.argument<String>("phone")
                val customerMessage = call.argument<String>("message")
                if (customerPhone != null && customerMessage != null) {
                    sendSMS(customerPhone, customerMessage, result)
                } else {
                    result.error("INVALID_ARGUMENT", "Phone number or message is null", null)
                }
            }
            else {
                result.notImplemented()
            }
        }
    }

    private fun sendSMS(phone: String, message: String, result: Result) {
        return try {
            val smsManager: SmsManager = SmsManager.getDefault()
            smsManager.sendTextMessage(phone, null, message, null, null)
            result.success("SMS sent successfully")
        } catch (e: Exception) {
            result.error("SMS_SEND_FAILED", "Failed to send SMS: ${e.message}", null)
        }
    }
}

AndroidManifest.xml配置

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <application
        android:label="muteify"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <receiver android:name="me.sodipto.phone_state_background.PhoneStateBackgroundServiceReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
    <!-- Required to query activities that can process text, see:
         https://developer.android.com/training/package-visibility and
         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>
</manifest>

已尝试的解决措施

  • 执行flutter clean并重新构建APK
  • 验证Flutter与Android代码中的channel_name一致
  • 确认MethodChannel在configureFlutterEngine内初始化
  • 在多台设备上测试,问题仍存在

预期行为

应用应能通过MethodChannel成功发送SMS,即使在后台运行时也不会抛出MissingPluginException异常。

Flutter Doctor结果

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.3, on Pop!_OS 22.04 LTS
    6.9.3-76060903-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2024.1)
[✓] VS Code (version 1.93.1)
[✓] Connected device (3 available)
[✓] Network resources

• No issues found!

问题

导致该MissingPluginException异常的原因是什么?如何解决该问题?是否在MethodChannel配置或Android清单文件设置中存在遗漏?


解决分析

核心原因

从错误栈可以看到,MethodChannel调用是在phoneStateBackgroundCallbackHandler这个后台回调函数中触发的。你当前只在MainActivity的FlutterEngine中注册了MethodChannel,但后台回调运行在独立的Flutter Isolate(或插件创建的独立Flutter引擎实例)中,这个隔离环境并没有注册对应的channel_name通道,导致找不到方法实现。

解决方法

方案1:在后台引擎中注册MethodChannel

如果使用的phone_state_background插件允许自定义后台Flutter引擎的初始化逻辑,需要在后台引擎启动时重复注册MethodChannel:

  1. 找到插件中初始化Flutter引擎的代码(通常是在广播接收器或后台服务中)
  2. 添加和MainActivity中一致的MethodChannel注册逻辑:
// 假设在后台服务的引擎初始化处
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "channel_name").setMethodCallHandler { call, result ->
    // 完全复用MainActivity中的处理逻辑,包括sendSMS方法
}

方案2:绕过MethodChannel,直接在原生后台处理SMS

既然是在广播接收器的后台逻辑中需要发送SMS,完全可以跳过Flutter层,直接在Android原生的广播接收器中调用sendSMS方法:

  1. 修改PhoneStateBackgroundServiceReceiver的代码,添加发送SMS的逻辑
  2. 不需要再通过Flutter的MethodChannel调用,避免跨引擎的通道问题

额外检查项

  • 确保SEND_SMS权限在Android 6.0+设备上完成运行时动态申请,Manifest声明只是静态权限,动态权限缺失会导致发送失败,但也可能间接引发异常
  • 确认后台服务/广播接收器的进程和主应用进程一致,避免跨进程通信的问题(默认情况下是一致的,除非配置了android:process属性)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:27:33