You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Kotlin:如何通过TelephonyCallback检测并获取来电号码

Android Kotlin:如何通过TelephonyCallback检测并获取来电号码

我完全理解你的困惑,最近Telephony相关的API确实有不少变动,刚上手的时候很容易摸不着头脑。其实要在你现有的TelephonyCallback逻辑里获取来电号码,核心是要结合通话日志权限通话日志查询来实现,下面给你一步步讲清楚:

第一步:添加并申请必要权限

首先得确保你的App有读取通话日志的权限,从Android 10(API 29)开始,获取来电号码需要READ_CALL_LOG权限,不再是之前的READ_PHONE_STATE了:

  1. AndroidManifest.xml里声明权限:
<uses-permission android:name="android.permission.READ_CALL_LOG" />
  1. 因为这是危险权限,还要在代码里动态申请(针对Android 6.0及以上系统):
private fun checkCallLogPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CALL_LOG), 1001)
    }
}

记得在onRequestPermissionsResult里处理权限申请结果,确保用户授权后再执行后续逻辑。

第二步:修改TelephonyCallback逻辑,获取来电号码

你的现有TelephonyCallback已经能正确检测来电状态了,现在只需要在CALL_STATE_RINGING分支里,查询系统通话日志拿到最新的来电号码:

object : TelephonyCallback(), TelephonyCallback.CallStateListener {
    override fun onCallStateChanged(state: Int) {
        when (state) {
            TelephonyManager.CALL_STATE_RINGING -> {
                Log.d("incCall", "Incoming call detected")
                // 在这里获取来电号码
                val incomingNumber = getLatestIncomingCallNumber(applicationContext)
                incomingNumber?.let {
                    Log.d("incCall", "来电号码:$it")
                    // 这里可以处理你的业务逻辑
                }
            }
            TelephonyManager.CALL_STATE_OFFHOOK -> {
                Log.d("incCall", "Call answered")
            }
            TelephonyManager.CALL_STATE_IDLE -> {
                Log.d("incCall", "Call ended")
            }
        }
    }

    // 封装查询最新来电号码的方法
    private fun getLatestIncomingCallNumber(context: Context): String? {
        val projection = arrayOf(CallLog.Calls.NUMBER, CallLog.Calls.TYPE)
        val selection = "${CallLog.Calls.TYPE} = ?"
        val selectionArgs = arrayOf(CallLog.Calls.INCOMING_TYPE.toString())
        val sortOrder = "${CallLog.Calls.DATE} DESC"

        context.contentResolver.query(
            CallLog.Calls.CONTENT_URI,
            projection,
            selection,
            selectionArgs,
            sortOrder
        )?.use { cursor ->
            if (cursor.moveToFirst()) {
                val numberIndex = cursor.getColumnIndex(CallLog.Calls.NUMBER)
                return cursor.getString(numberIndex)
            }
        }
        return null
    }
}

补充说明

  • 为什么要查询通话日志?因为新版TelephonyCallback.CallStateListener的回调里没有直接提供来电号码参数(和旧版PhoneStateListener不一样),所以只能通过系统已经写入的通话日志来获取。
  • 一定要确保用户授权READ_CALL_LOG后再执行查询,不然会拿不到数据。
  • 测试的时候建议用真实来电(模拟器的模拟来电可能不会写入通话日志),避免出现拿不到号码的情况。

希望这个方案能帮到你,如果还有疑问可以随时问~

备注:内容来源于stack exchange,提问作者IdlleF

火山引擎 最新活动