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

Android非过时来电检测方案:获取来电名称、号码及头像(支持静音)

Android 新版来电检测及信息获取实现方案

核心思路

采用Android 10(API 29)引入的TelecomManager.CallCallback实现来电监听,替代过时的PhoneStateListener,同时通过联系人ContentProvider查询获取名称与头像,全程不受静音模式影响。

步骤实现

1. 权限申请

需要动态申请以下权限(适配Android 13+):

  • READ_PHONE_STATE:获取来电状态与号码
  • READ_CONTACTS:查询联系人名称与头像
  • POST_NOTIFICATIONS(Android 13+):若需通过通知展示来电信息

权限申请代码示例:

private val REQUIRED_PERMISSIONS = arrayOf(
    Manifest.permission.READ_PHONE_STATE,
    Manifest.permission.READ_CONTACTS,
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Manifest.permission.POST_NOTIFICATIONS else ""
).filterNot { it.isEmpty() }.toTypedArray()

// 在Activity/Fragment中检查并申请权限
if (ContextCompat.checkSelfPermission(this, REQUIRED_PERMISSIONS[0]) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, 1001)
}

2. 注册来电监听

通过TelecomManager添加CallCallback,在来电响铃时触发逻辑:

private lateinit var telecomManager: TelecomManager
private lateinit var callCallback: TelecomManager.CallCallback

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    telecomManager = getSystemService(Context.TELECOM_SERVICE) as TelecomManager

    callCallback = object : TelecomManager.CallCallback() {
        override fun onCallAdded(call: TelecomManager.Call) {
            super.onCallAdded(call)
            val phoneNumber = call.details.handle?.schemeSpecificPart
            val callState = call.details.state

            // 仅处理响铃状态的来电
            if (callState == TelecomManager.CallDetails.STATE_RINGING && phoneNumber != null) {
                getContactInfo(phoneNumber) { displayName, avatarUri ->
                    // 此处获取到最终显示名称、头像URI、号码
                    runOnUiThread {
                        // 执行UI更新或自定义来电界面逻辑
                    }
                }
            }
        }

        override fun onCallRemoved(call: TelecomManager.Call) {
            super.onCallRemoved(call)
            // 通话结束后清理资源
        }
    }
}

override fun onResume() {
    super.onResume()
    telecomManager.addCallListener(callCallback)
}

override fun onPause() {
    super.onPause()
    telecomManager.removeCallListener(callCallback)
}

3. 获取联系人信息(名称、头像)

通过ContentProvider查询联系人,同时处理SPAM标识:

private fun getContactInfo(phoneNumber: String, callback: (String, Uri?) -> Unit) {
    CoroutineScope(Dispatchers.IO).launch {
        var displayName: String? = null
        var avatarUri: Uri? = null

        // 查询联系人数据
        val projection = arrayOf(
            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
            ContactsContract.CommonDataKinds.Phone.PHOTO_URI
        )
        val selection = "${ContactsContract.CommonDataKinds.Phone.NUMBER} LIKE ?"
        val selectionArgs = arrayOf("%$phoneNumber%") // 模糊匹配适配号码格式差异

        contentResolver.query(
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            projection,
            selection,
            selectionArgs,
            null
        )?.use { cursor ->
            if (cursor.moveToFirst()) {
                displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
                avatarUri = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.PHOTO_URI))?.let { Uri.parse(it) }
            }
        }

        // 处理SPAM标识:系统标记的垃圾来电会在callerDisplayName中包含SPAM字样
        val callDetails = telecomManager.calls.firstOrNull { it.details.handle?.schemeSpecificPart == phoneNumber }?.details
        val isSpam = callDetails?.callerDisplayName?.contains("SPAM", ignoreCase = true) == true

        // 最终显示名称:优先取联系人名称,无则用号码,SPAM来电追加标记
        val finalDisplayName = when {
            isSpam -> "SPAM - ${displayName ?: phoneNumber}"
            else -> displayName ?: phoneNumber
        }

        withContext(Dispatchers.Main) {
            callback(finalDisplayName, avatarUri)
        }
    }
}

关键说明

  • 适配新版Android:TelecomManager.CallCallback是官方推荐的非过时API,兼容Android 10及以上版本。
  • 静音模式兼容:监听基于系统Telecom服务,不受设备音频模式影响,静音状态下仍能正常触发来电回调。
  • 号码格式兼容:采用模糊匹配查询联系人,适配不同格式的号码存储(如带区号、空格)。
  • SPAM标识处理:直接读取系统返回的来电显示名称,自动识别垃圾来电标记。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:42:15