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

Android Studio Kotlin中基于Firebase实时数据库的来电拦截实现求助

实现基于Firebase拦截列表的来电拦截(BroadcastReceiver方案)

一、前置权限配置

首先在AndroidManifest.xml中添加必要权限,确保应用能读取电话状态并拦截来电:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- Android 10+ 专属拦截权限 -->
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<!-- Android 9及以下拦截来电权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

二、本地缓存拦截列表(必做优化)

BroadcastReceiver中直接访问Firebase会有延迟,甚至引发ANR,建议将拦截列表缓存到本地,同时监听Firebase的blocklist节点变化,实时更新缓存:

// 监听blocklist节点,同步更新本地缓存
blocklistRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val blockedNumbers = mutableSetOf<String>()
        snapshot.children.forEach { child ->
            val number = child.key ?: return@forEach
            if (child.value as Boolean) blockedNumbers.add(number)
        }
        // 保存到SharedPreferences
        val sharedPref = getSharedPreferences("BlocklistCache", MODE_PRIVATE)
        sharedPref.edit().putStringSet("blocked_numbers", blockedNumbers).apply()
    }

    override fun onCancelled(error: DatabaseError) {
        // 处理数据库读取错误
    }
})

三、实现来电拦截BroadcastReceiver

创建PhoneBlockReceiver类,继承自BroadcastReceiver,实现拦截逻辑:

class PhoneBlockReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 读取本地缓存的拦截列表
        val sharedPref = context.getSharedPreferences("BlocklistCache", Context.MODE_PRIVATE)
        val blockedNumbers = sharedPref.getStringSet("blocked_numbers", emptySet()) ?: emptySet()

        // 获取来电号码并统一格式
        val incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
        incomingNumber?.let { rawNumber ->
            val formattedNumber = rawNumber.replace("[^\\d+]".toRegex(), "")
            if (blockedNumbers.contains(formattedNumber)) {
                // 执行拦截操作
                try {
                    val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                        telephonyManager.endCall()
                    } else {
                        // 旧版本通过反射调用endCall
                        val method = telephonyManager.javaClass.getDeclaredMethod("endCall")
                        method.isAccessible = true
                        method.invoke(telephonyManager)
                    }
                    // 终止广播传递,避免系统处理来电
                    abortBroadcast()
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    }
}

四、注册BroadcastReceiver

在AndroidManifest.xml中注册接收器,设置高优先级确保先于系统处理来电:

<receiver
    android:name=".PhoneBlockReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="999">
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>

关键注意事项

  • 号码格式必须统一:Firebase中存储的是+91xxxxxxxxxx格式,拦截时需将来电号码转换成相同格式(去掉空格、括号等符号),避免匹配失败。
  • Android 10+ 厂商适配:部分品牌对来电拦截有自定义限制,可能需要引导用户手动开启应用的拦截权限。
  • 禁止耗时操作:BroadcastReceiver中不能执行网络请求等耗时任务,本地缓存是必须的优化手段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:14:55