Android SDK30下如何通过编程方式实现来电拒接
问题根因
你当前使用的反射调用com.android.internal.telephony.ITelephony#endCall的方案在API 30(Android 11)上完全失效,核心原因两点:
- Android 9之后系统持续收紧隐藏API访问限制,第三方应用直接反射调用internal包下的非公开接口会被系统直接拦截
- 从API 28开始系统已经公开提供了正式的挂断电话API,老的隐藏接口本身也已经被系统废弃,不再对第三方应用开放
你写的反射代码本身也存在逻辑错误:通过ServiceManager拿系统服务的路径对第三方应用锁死,调用asInterface时传入null参数根本拿不到有效的服务代理对象,自然无法触发挂断操作。
前置配置
首先在AndroidManifest.xml中添加必须的权限:
<!-- Android 9+ 接听/挂断电话必须的核心权限 --> <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" /> <!-- 读取通话状态必备权限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 兼容Android 8及以下版本需要的权限 --> <uses-permission android:name="android.permission.CALL_PHONE" />
注意:
ANSWER_PHONE_CALLS属于危险权限,必须在代码中动态申请,未获得授权时挂断逻辑会直接被系统拒绝。
可用实现代码
直接丢弃你之前的无效反射逻辑,使用系统公开的TelecomManager接口实现,仅在Android 8以下版本用反射做兼容兜底:
import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import androidx.core.content.ContextCompat; import java.lang.reflect.Method; public class CallUtils { public static void disconnectCall(Context context) { // 权限校验,未授权直接终止操作 if (ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) != PackageManager.PERMISSION_GRANTED) { return; } // Android 9及以上走官方公开API,无隐藏接口限制 TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && telecomManager != null) { if (telecomManager.endCall()) { return; } } // 仅Android 8及以下老版本用反射逻辑兜底 try { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); Class<?> iTelephonyCls = Class.forName("com.android.internal.telephony.ITelephony"); Method getITelephonyMethod = TelephonyManager.class.getDeclaredMethod("getITelephony"); getITelephonyMethod.setAccessible(true); Object iTelephonyProxy = getITelephonyMethod.invoke(telephonyManager); Method endCallMethod = iTelephonyCls.getDeclaredMethod("endCall"); endCallMethod.setAccessible(true); endCallMethod.invoke(iTelephonyProxy); } catch (Exception e) { e.printStackTrace(); } } }
注意事项
- 权限申请顺序:先申请
READ_PHONE_STATE权限,拿到授权后再申请ANSWER_PHONE_CALLS,否则权限申请会被系统驳回 - 不要尝试发送
ACTION_CANCEL_CALL广播实现挂断,该广播仅允许系统默认拨号应用发送,第三方自定义来电屏应用无发送权限 - 测试请使用真机,部分安卓模拟器阉割了Telecom服务实现,会出现API调用返回失败的问题,模拟器测试结果不具备参考性
内容的提问来源于stack exchange,提问作者Ashish Virani
相关产品推荐
相关产品推荐

