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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:06:04