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

Android使用TelephonyCallback获取通话电话号码 替代废弃PhoneStateListener

实现方案

前置权限要求

无论使用哪种方案,都需要提前申请对应运行时权限:

  • android.permission.READ_PHONE_STATE:监听通话状态的必备权限,需动态申请
  • android.permission.READ_CALL_LOG:非默认拨号应用获取号码必备权限,需动态申请

方案1:非默认拨号应用通用实现

该方案不需要成为系统默认拨号应用,通过「监听通话状态+查询最新通话记录」的组合实现号码获取,适合绝大多数普通应用场景。

实现逻辑

在TelephonyCallback.CallStateListener的onCallStateChanged收到响铃(CALL_STATE_RINGING)或摘机(CALL_STATE_OFFHOOK)状态时,立即查询系统通话日志的最新一条记录,即可得到当前通话对应的手机号。

示例代码

val telephonyManager =
    context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

// 注册官方推荐的非废弃通话状态监听
telephonyManager.registerTelephonyCallback(
    context.mainExecutor,
    object : TelephonyCallback(), TelephonyCallback.CallStateListener {
        override fun onCallStateChanged(state: Int) {
            when(state) {
                TelephonyManager.CALL_STATE_RINGING,
                TelephonyManager.CALL_STATE_OFFHOOK -> {
                    // 状态变更时查询当前通话号码
                    val currentCallNumber = getLatestCallNumber(context)
                    // 此处处理拿到的号码
                }
            }
        }
    }
)

//  查询最新通话记录获取号码
private fun getLatestCallNumber(context: Context): String? {
    // 权限校验
    if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG)
        != PackageManager.PERMISSION_GRANTED
    ) {
        return null
    }
    val projection = arrayOf(CallLog.Calls.NUMBER)
    // 按通话时间倒序取第一条,即为当前正在进行的通话
    context.contentResolver.query(
        CallLog.Calls.CONTENT_URI,
        projection,
        null,
        null,
        "${CallLog.Calls.DATE} DESC LIMIT 1"
    )?.use { cursor ->
        if (cursor.moveToFirst()) {
            return cursor.getString(cursor.getColumnIndexOrThrow(CallLog.Calls.NUMBER))
        }
    }
    return null
}

方案2:拨号类应用专属实现

如果你的应用是拨号类工具,可申请成为系统默认拨号应用,通过官方提供的InCallService直接获取通话信息,不需要额外申请通话日志权限,数据准确性更高。

示例代码

首先自定义InCallService:

class CustomInCallService : InCallService() {
    // 新通话接入时触发
    override fun onCallAdded(call: Call) {
        super.onCallAdded(call)
        // 直接获取当前通话的号码
        val phoneNumber = call.details?.handle?.schemeSpecificPart
        // 监听通话状态变更
        call.registerCallback(object : Call.Callback() {
            override fun onStateChanged(call: Call, state: Int) {
                // 此处可同时拿到实时通话状态和对应号码
            }
        })
    }
}

然后在AndroidManifest.xml中注册服务,配置对应的intent-filter,用户主动将你的应用设置为默认拨号应用后即可正常接收回调。


内容的提问来源于stack exchange,提问作者Gabriele Bellini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 04:39:00