Flutter应用实现Android来电拦截时遇隐藏方法访问权限错误
错误详情
Accessing hidden method Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony; (greylist-max-p, reflection, denied)
E/CallBlocker(19807): Error blocking call: android.telephony.TelephonyManager.getITelephony []
错误原因
这个问题的核心是Android 9(API 28)及以上版本严格限制了系统隐藏API的反射调用。getITelephony()属于Android内部的隐藏方法,被标记为greylist-max-p,意味着从Android P开始,第三方应用通过反射访问该方法会被系统直接拒绝。
解决方案
1. 改用官方合规的来电拦截方案(推荐)
从Android 10(API 29)开始,官方提供了CallScreeningService作为标准的来电拦截接口,完全规避隐藏API的限制:
- 在
AndroidManifest.xml中注册服务:<service android:name=".CallBlockerService" android:permission="android.permission.BIND_SCREENING_SERVICE"> <intent-filter> <action android:name="android.telecom.CallScreeningService" /> </intent-filter> </service> - 创建继承自
CallScreeningService的服务类,重写拦截逻辑:public class CallBlockerService extends CallScreeningService { @Override public void onScreenCall(Call.Details callDetails) { // 自定义号码拦截判断逻辑 boolean shouldBlock = checkBlacklist(callDetails.getHandle().getSchemeSpecificPart()); CallResponse.Builder responseBuilder = new CallResponse.Builder(); if (shouldBlock) { responseBuilder.setDisallowCall(true); responseBuilder.setRejectCall(true); } respondToCall(callDetails, responseBuilder.build()); } private boolean checkBlacklist(String phoneNumber) { // 这里实现黑名单匹配逻辑 return false; } } - Flutter端通过
MethodChannel动态申请READ_PHONE_STATE、ANSWER_PHONE_CALLS权限,触发服务启动。
2. 低版本Android兼容处理(仅适用于API 28及以下)
如果需要支持Android 9及更低版本,可直接使用TelephonyManager的endCall()方法,避免反射调用:
- 在
AndroidManifest.xml添加权限:<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> - 直接调用
endCall()实现拦截(注意:Android 9之后该方法也被限制,仅适配低版本)。
3. 权限申请注意事项
- 所有危险权限(如
READ_PHONE_STATE、ANSWER_PHONE_CALLS)必须在运行时动态申请,不能仅依赖清单声明。 - Android 11及以上版本,还需要申请
READ_CALL_LOG权限才能获取完整的来电号码信息。
内容的提问来源于stack exchange,提问作者Fahar Khan
相关产品推荐
相关产品推荐

