Android双卡设备中PhoneStateListener适配改造咨询(音乐播放器场景)
嘿,这个双卡设备的通话监听问题我碰过好多次了——你原来的代码只监听了默认SIM卡的状态,副卡来电完全不会触发回调,所以才失效。下面给你两种适配方案,覆盖新老版本系统:
方案1:兼容Android 8.0及以下的多SIM监听
Android 8.0之前没有官方的双卡API,但可以通过反射获取所有SIM卡的subscriptionId,给每个卡单独注册通话状态监听。
首先修正你的监听类(顺便把拼错的CallListner改成CallListener),再添加获取所有SIM卡ID的方法:
class CallListener : PhoneStateListener() { // 用计数器跟踪活跃通话数,避免双卡同时通话时误恢复播放 private var activeCallCount = 0 override fun onCallStateChanged(state: Int, incomingNumber: String?) { super.onCallStateChanged(state, incomingNumber) when (state) { TelephonyManager.CALL_STATE_IDLE -> { // 通话结束,计数器减1,确保所有通话都结束才恢复 activeCallCount = max(0, activeCallCount - 1) if (activeCallCount == 0) { Controls.playPauseControl("play") } } TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> { if (state == TelephonyManager.CALL_STATE_OFFHOOK) { activeCallCount += 1 } Controls.playPauseControl("pause") } } } } // 获取所有SIM卡的subscriptionId,兼容旧系统 private fun getAllSubscriptionIds(telephonyManager: TelephonyManager): List<Int> { val subscriptionIds = mutableListOf<Int>() try { // 通过反射调用隐藏的getSubscriptionIds方法 val method = telephonyManager.javaClass.getMethod("getSubscriptionIds") val ids = method.invoke(telephonyManager) as IntArray? ids?.let { subscriptionIds.addAll(it.toList()) } } catch (e: Exception) { e.printStackTrace() // 反射失败, fallback到默认卡ID subscriptionIds.add(-1) } return subscriptionIds }
然后在注册监听时,给每个SIM卡都绑定监听:
val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val callListener = CallListener() // 遍历所有SIM卡ID,分别注册监听 getAllSubscriptionIds(telephonyManager).forEach { subId -> telephonyManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE, subId) }
方案2:Android 10及以上推荐用TelephonyCallback
从Android 10开始,Google推出了更简洁的TelephonyCallback,自动支持所有SIM卡的监听,不需要手动处理卡ID:
先创建回调实现类:
class CallTelephonyCallback : TelephonyCallback(), TelephonyCallback.CallStateListener { private var activeCallCount = 0 override fun onCallStateChanged(state: Int) { when (state) { TelephonyManager.CALL_STATE_IDLE -> { activeCallCount = max(0, activeCallCount - 1) if (activeCallCount == 0) { Controls.playPauseControl("play") } } TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> { if (state == TelephonyManager.CALL_STATE_OFFHOOK) { activeCallCount += 1 } Controls.playPauseControl("pause") } } } }
然后注册监听(记得判断系统版本):
val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val callCallback = CallTelephonyCallback() // 注册监听,自动覆盖所有SIM卡 telephonyManager.registerTelephonyCallback(mainExecutor, callCallback) } else { // 旧系统 fallback到方案1的逻辑 val callListener = CallListener() getAllSubscriptionIds(telephonyManager).forEach { subId -> telephonyManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE, subId) } }
额外必注意的细节
- 权限:务必在Manifest中声明
<uses-permission android:name="android.permission.READ_PHONE_STATE" />,Android 6.0+还要动态申请该权限;Android 13及以上如果需要后台监听,还得申请POST_NOTIFICATIONS权限。 - 通话计数器:加计数器是为了避免双卡同时通话时,其中一个通话结束就误恢复播放,只有所有通话都结束(计数器归0)才继续播放音乐。
内容的提问来源于stack exchange,提问作者D_lip
相关产品推荐
相关产品推荐

