Android API30及以上Java实现自定义点击挂断呼入/呼出电话的方案求助
解决Android程序化结束通话的问题
你的问题核心是Android 10(API 29)及以上版本严格限制了系统隐藏API的反射访问,getITelephony()属于系统内部非SDK接口,被加入灰名单后反射调用会被系统拒绝,因此抛出NoSuchMethodException。以下是官方支持的替代方案:
官方合法方案:使用TelecomManager
从Android 9(API 28)开始,官方提供了TelecomManager.endCall()方法用于程序化结束通话,这是唯一合规的实现方式。
步骤1:添加权限到AndroidManifest.xml
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <!-- Android 13+ 如需前台服务控制通话,需添加: --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CALL_SYSTEM" />
步骤2:替换原有反射代码
将你原来的onClick逻辑替换为以下代码:
close_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Context context = v.getContext(); TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); // 检查权限是否已授予 if (ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) { try { // 尝试结束通话 boolean isHangUpSuccess = telecomManager.endCall(); if (isHangUpSuccess) { Log.d("HANG UP", "通话已成功挂断"); } else { Log.d("HANG UP", "挂断失败:当前无活跃通话或权限不足"); } } catch (SecurityException e) { Log.e("HANG UP", "权限异常:无法执行挂断操作", e); } } else { // 动态申请权限 ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ANSWER_PHONE_CALLS}, 1001); } // 关闭当前Dialog CustomDialog.this.getWindow().getAttributes().windowAnimations = R.style.SlidingDialogAnimation; CustomDialog.this.finishAndRemoveTask(); } });
关键注意事项
- 权限申请:
ANSWER_PHONE_CALLS是危险权限,必须通过动态申请让用户授权,不能仅依赖Manifest声明。 - 前台要求:Android 10及以上版本中,后台应用无法调用通话控制接口,需确保你的应用处于前台(如当前Dialog显示中),或使用前台服务维持进程状态。
- 默认拨号应用:如果你的应用设置为系统默认拨号应用,可获得更宽松的通话控制权限,无需额外申请部分权限,但仍需遵循系统规范。
为什么原有反射方案失效?
从Android 9开始,Google推出了非SDK接口限制政策,将getITelephony()这类内部方法加入灰名单/黑名单,禁止第三方应用通过反射调用。Android 10及以上版本进一步加强了该限制,直接拦截此类反射请求,导致你遇到NoSuchMethodException或权限拒绝异常。
内容的提问来源于stack exchange,提问作者Srikar Uppu
相关产品推荐
相关产品推荐

