Android使用BroadcastReceiver监听来电时CallScreeningService的使用位置?
关于CallScreeningService的使用场景说明
BroadcastReceiver实现来电监听的局限性
你目前用广播监听来电的方案在低版本安卓系统上可以正常运行,但存在明显的版本兼容性问题:
- Android 10(API 29)之后,READ_PHONE_STATE权限获取来电号码的能力被大幅收窄,多数场景下无法拿到准确的来电号码
- 安卓系统对后台启动Activity的权限限制越来越严格,Android 10及以上版本中,后台进程直接调用
startActivity()会被系统拦截,你的自定义来电界面大概率无法正常弹出 - 仅能被动监听来电状态,没有系统级的来电拦截、拒接权限,实现骚扰电话拦截的逻辑复杂度高、兼容性差
CallScreeningService的适用环节
CallScreeningService是Android 7.0(API 24)官方推出的专属来电处理服务,权限优先级远高于普通广播,适合用在以下环节:
- 来电触发的第一时间做号码校验:它的触发时机早于TelephonyManager来电广播,你可以在这里先匹配本地/云端骚扰电话库,如果是诈骗、推销电话,直接通过
CallResponse设置setDisallowCall(true)+setRejectCall(true)实现系统级拒接,不会出现普通拦截方案响一声才挂断的问题 - 高版本系统自定义来电界面的前置校验:Android 10及以上系统中,通过CallScreeningService触发的Activity启动请求不会被后台启动规则拦截,你可以在确认来电合法后再拉起你的自定义来电界面,同时可以设置
setSkipNotification(true)隐藏系统默认的来电通知,避免系统来电界面和自定义界面冲突 - 自定义来电的系统级配置:比如设置
setSkipCallLog(true)让特定来电不存入通话记录,给来电打自定义标记同步到系统通话记录等
现有代码适配建议
你可以保留BroadcastReceiver作为Android 7.0以下系统的兼容方案,Android 7.0及以上版本全部切换为CallScreeningService实现来电处理,优化后的服务代码示例如下:
@RequiresApi(api = Build.VERSION_CODES.N) public class CallService extends CallScreeningService { @Override public void onScreenCall(@NonNull Call.Details callDetails) { CallResponse.Builder response = new CallResponse.Builder(); Uri callerPhone = callDetails.getHandle(); // 提取来电号码 String phoneNumber = callerPhone.getSchemeSpecificPart(); // 校验是否为骚扰电话 if(isSpamNumber(phoneNumber)){ // 直接拒接,不弹通知 response.setDisallowCall(true); response.setRejectCall(true); response.setSkipNotification(true); }else{ // 合法来电,拉起自定义来电界面 Intent callerIntent = new Intent(getApplicationContext(), CallerInfoActivity.class); callerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); callerIntent.putExtra("EXTRA_PHONE_CALLER", phoneNumber); callerIntent.putExtra("EXTRA_NAME_CALLER", getContactName(phoneNumber)); startActivity(callerIntent); // 隐藏系统默认来电通知,避免界面冲突 response.setSkipNotification(true); } respondToCall(callDetails, response.build()); } // 自定义方法:匹配骚扰电话库 private boolean isSpamNumber(String phone){ // 实现你的号码校验逻辑 return false; } // 自定义方法:查询联系人姓名 private String getContactName(String phone){ // 实现你的联系人查询逻辑 return "Gil Pires"; } }
别忘了在AndroidManifest.xml中注册服务,同时引导用户在系统电话设置中将你的应用设为默认来电筛选应用,服务才会正常触发:
<service android:name=".CallService" android:permission="android.permission.BIND_SCREENING_SERVICE"> <intent-filter> <action android:name="android.telecom.CallScreeningService" /> </intent-filter> </service>
内容的提问来源于stack exchange,提问作者Stiven Fortes
相关产品推荐
相关产品推荐

