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

Flutter调用Android(Kotlin)发送短信后如何获取返回结果?

问题解决:Flutter通过MethodChannel获取Kotlin端短信发送及送达状态

问题分析

核心问题是Kotlin端未主动调用result.success()将状态回传给Flutter。短信发送的状态回调(广播接收器)是异步触发的,原代码在调用smsManager.sendTextMessage()后直接结束方法,未将广播中获取的状态通过MethodChannel返回,导致Flutter端的then或await无法接收到结果。

解决方案

1. 修改Kotlin端代码(MainActivity.kt)

需要保存MethodChannel的Result对象,在广播接收器获取到发送/送达状态后,将封装好的Map通过result.success()返回给Flutter,同时记得注销动态注册的广播接收器避免内存泄漏。

package com.example.my_flutter_app

import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.telephony.SmsManager
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.content.ContextWrapper
import android.app.PendingIntent
import android.util.Log

class MainActivity : FlutterActivity() {
    private val CHANNEL = "samples.flutter.dev/smscall"
    private var smsResult: MethodChannel.Result? = null
    private lateinit var sentReceiver: BroadcastReceiver
    private lateinit var deliveredReceiver: BroadcastReceiver
    private val SENT = "SMS_SENT"
    private val DELIVERED = "SMS_DELIVERED"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "sendSMS") {
                // 保存Result对象用于后续回调
                smsResult = result

                val sentinelPhoneNumber = call.argument<String>("phoneno")
                val message = call.argument<String>("text") ?: ""

                // 初始化PendingIntent,适配Android版本
                val sentPI = PendingIntent.getBroadcast(
                    ContextWrapper(applicationContext),
                    0,
                    Intent(SENT),
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
                )
                val deliveredPI = PendingIntent.getBroadcast(
                    ContextWrapper(applicationContext),
                    0,
                    Intent(DELIVERED),
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
                )

                // 注册发送状态广播接收器
                sentReceiver = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {
                        val statusMap = mutableMapOf<String, Any>()
                        when (resultCode) {
                            Activity.RESULT_OK -> {
                                statusMap["sentStatus"] = true
                                statusMap["sentMessage"] = "短信发送成功"
                                Log.e("SMS", "短信发送成功")
                            }
                            SmsManager.RESULT_ERROR_GENERIC_FAILURE -> {
                                statusMap["sentStatus"] = false
                                statusMap["sentMessage"] = "发送失败:通用错误"
                            }
                            SmsManager.RESULT_ERROR_NO_SERVICE -> {
                                statusMap["sentStatus"] = false
                                statusMap["sentMessage"] = "发送失败:无网络服务"
                            }
                            SmsManager.RESULT_ERROR_NULL_PDU -> {
                                statusMap["sentStatus"] = false
                                statusMap["sentMessage"] = "发送失败:PDU为空"
                            }
                            SmsManager.RESULT_ERROR_RADIO_OFF -> {
                                statusMap["sentStatus"] = false
                                statusMap["sentMessage"] = "发送失败:无线电关闭"
                            }
                            else -> {
                                statusMap["sentStatus"] = false
                                statusMap["sentMessage"] = "发送失败:未知错误"
                            }
                        }
                        // 返回发送状态给Flutter
                        smsResult?.success(statusMap)
                        // 注销当前接收器
                        context.unregisterReceiver(this)
                    }
                }
                registerReceiver(sentReceiver, IntentFilter(SENT))

                // 注册送达状态广播接收器
                deliveredReceiver = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {
                        val deliveredMap = mutableMapOf<String, Any>()
                        when (resultCode) {
                            Activity.RESULT_OK -> {
                                deliveredMap["deliveredStatus"] = true
                                deliveredMap["deliveredMessage"] = "短信已送达"
                                Log.e("SMS", "短信已送达")
                            }
                            Activity.RESULT_CANCELED -> {
                                deliveredMap["deliveredStatus"] = false
                                deliveredMap["deliveredMessage"] = "短信未送达"
                            }
                        }
                        // 若需单独返回送达状态,可改用EventChannel实时推送
                        // smsResult?.success(deliveredMap)
                        context.unregisterReceiver(this)
                    }
                }
                registerReceiver(deliveredReceiver, IntentFilter(DELIVERED))

                // 执行短信发送
                val smsManager = SmsManager.getDefault()
                smsManager.sendTextMessage(sentinelPhoneNumber, null, message, sentPI, deliveredPI)

            } else {
                result.notImplemented()
            }
        }
    }

    // 页面销毁时注销接收器,避免内存泄漏
    override fun onDestroy() {
        super.onDestroy()
        try {
            unregisterReceiver(sentReceiver)
            unregisterReceiver(deliveredReceiver)
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
        }
    }
}

2. 修改Flutter端代码(main.dart)

在_sendSMS方法中接收返回的Map并处理结果:

// Send SMS Via Native Android
static const platform = MethodChannel('samples.flutter.dev/smscall');

Future<void> _sendSMS(String phoneNo, String msgText) async {
  try {
    final Map<String, dynamic> result = await platform.invokeMethod(
      'sendSMS', 
      {'phoneno': phoneNo, 'text': msgText}
    ) as Map<String, dynamic>;
    
    // 处理发送状态
    print("发送状态:${result['sentStatus']},信息:${result['sentMessage']}");
    
    // 若需监听送达状态,建议使用EventChannel实现实时推送(因送达事件触发晚于发送事件)
  } on PlatformException catch (e) {
    print("发送失败:'${e.message}'.");
  }
}
// Send SMS Via Native Android

关键说明

  1. 异步回调处理:短信发送/送达状态是异步返回的,必须在广播接收器中调用result.success()才能将结果回传给Flutter,原代码缺少这一步导致接收失败。
  2. 广播接收器注销:动态注册的广播接收器必须在页面销毁时注销,否则会造成内存泄漏。
  3. 送达状态扩展:若需获取送达状态,由于其触发时间晚于发送状态,建议使用EventChannel实现实时推送,避免阻塞Flutter端方法调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:05:33