Flutter通过MethodChannel检测通话状态时BroadcastReceiver调用问题
问题原因及解决方案
你遇到的问题核心是两个逻辑误区:一是基础的广播监听缺少必要的权限和注册配置,二是试图主动触发系统广播回调,不符合安卓广播的运行逻辑,以下是具体修复方案:
- 广播接收器的
onReceive是系统接收到目标广播时自动触发的,不需要也不支持开发者主动调用触发,要获取通话状态要么监听系统回调,要么直接调用系统API主动查询。 - 原始代码无法弹Toast的核心原因大概率是没有申请动态权限,安卓6.0及以上版本
READ_PHONE_STATE属于敏感权限,必须用户手动授权后才能收到通话状态广播。
具体修复步骤
1. 配置权限与广播注册
在AndroidManifest.xml中添加如下配置:
<!-- 通话状态监听必要权限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_CALL_LOG" /> <application ...> <!-- 注册通话状态广播接收器,也可以选择在代码中动态注册 --> <receiver android:name=".CallReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver> </application>
2. 修正广播接收器与MethodChannel对接逻辑
调整后的CallReceiver代码
class CallReceiver: BroadcastReceiver() { // 缓存最新通话状态,也可以选择直接在主动查询时调用系统API读取最新值 var currentPhoneState: String = "Nothing Detected" override fun onReceive(context: Context?, intent: Intent?) { // 提前做空判断避免崩溃,不要直接用!!强转 intent ?: return context ?: return val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE) ?: return currentPhoneState = when(state) { TelephonyManager.EXTRA_STATE_OFFHOOK -> { showToastMsg(context, "通话已接通") "通话已接通" } TelephonyManager.EXTRA_STATE_IDLE -> { showToastMsg(context, "通话已结束") "通话已结束" } TelephonyManager.EXTRA_STATE_RINGING -> { showToastMsg(context, "来电响铃中") "来电响铃中" } else -> "无通话状态" } // 状态变化时主动同步给Flutter侧 MainActivity.methodChannel?.invokeMethod("onCallStateChanged", currentPhoneState) } private fun showToastMsg(c: Context, msg: String) { val toast = Toast.makeText(c, msg, Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() } }
MainActivity中MethodChannel实现
class MainActivity : FlutterActivity() { companion object { var methodChannel: MethodChannel? = null private const val CHANNEL = "com.yourAppName/call_state" private lateinit var callReceiver: CallReceiver } override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) callReceiver = CallReceiver() // 动态注册广播,如果已经在Manifest静态注册可以省略这一步 val filter = IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED) registerReceiver(callReceiver, filter) methodChannel?.setMethodCallHandler { call, result -> when (call.method) { // Flutter主动查询当前通话状态 "getCurrentCallState" -> { val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val state = when(telephonyManager.callState) { TelephonyManager.CALL_STATE_IDLE -> "通话已结束" TelephonyManager.CALL_STATE_RINGING -> "来电响铃中" TelephonyManager.CALL_STATE_OFFHOOK -> "通话已接通" else -> "无通话状态" } result.success(state) } // 申请通话权限 "requestCallPermission" -> { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED ) { result.success(true) } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 101) result.success(false) } } else -> result.notImplemented() } } } override fun onDestroy() { super.onDestroy() unregisterReceiver(callReceiver) } }
3. Flutter侧调用示例
const platform = MethodChannel('com.yourAppName/call_state'); // 进入应用后先申请权限 await platform.invokeMethod('requestCallPermission'); // 主动查询当前通话状态 String currentState = await platform.invokeMethod('getCurrentCallState'); // 监听通话状态变化 platform.setMethodCallHandler((call) async { if (call.method == 'onCallStateChanged') { debugPrint('当前通话状态:${call.arguments}'); } });
内容的提问来源于stack exchange,提问作者Nouradawy
相关产品推荐
相关产品推荐

