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
关键说明
- 异步回调处理:短信发送/送达状态是异步返回的,必须在广播接收器中调用
result.success()才能将结果回传给Flutter,原代码缺少这一步导致接收失败。 - 广播接收器注销:动态注册的广播接收器必须在页面销毁时注销,否则会造成内存泄漏。
- 送达状态扩展:若需获取送达状态,由于其触发时间晚于发送状态,建议使用
EventChannel实现实时推送,避免阻塞Flutter端方法调用。
内容的提问来源于stack exchange,提问作者Muhammad Hassan
相关产品推荐
相关产品推荐

