Android Kotlin:如何通过TelephonyCallback检测并获取来电号码
Android Kotlin:如何通过TelephonyCallback检测并获取来电号码
我完全理解你的困惑,最近Telephony相关的API确实有不少变动,刚上手的时候很容易摸不着头脑。其实要在你现有的TelephonyCallback逻辑里获取来电号码,核心是要结合通话日志权限和通话日志查询来实现,下面给你一步步讲清楚:
第一步:添加并申请必要权限
首先得确保你的App有读取通话日志的权限,从Android 10(API 29)开始,获取来电号码需要READ_CALL_LOG权限,不再是之前的READ_PHONE_STATE了:
- 在
AndroidManifest.xml里声明权限:
<uses-permission android:name="android.permission.READ_CALL_LOG" />
- 因为这是危险权限,还要在代码里动态申请(针对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




