如何使用InCallService拒接来电并获取Android12+来电号码
问题
- 如何使用
InCallService拒接来电?官方文档显示TelephonyManager.EXTRA_INCOMING_NUMBER和TelecomManager.endCall()已被弃用,需改用InCallService,但不清楚具体用法,仅需实现拒接功能,无需开发默认通话应用。 - Android 12及以上版本中,通过
CallerNumberReceiver无法获取来电号码,如何解决?
用户提供的配置与代码
AndroidManifest.xml
<receiver android:name=".CallerNumberReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver>
CallerNumberReceiver类
package com.example.myapplication1; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; import android.telephony.PhoneStateListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.widget.Toast; import androidx.annotation.RequiresApi; public class CallerNumberReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { telephonyManager.registerTelephonyCallback(context.getMainExecutor(), new CallStateListener() { @Override public void onCallStateChanged(int state) { if(state == TelephonyManager.CALL_STATE_RINGING){ // WHERE IS PHONE NUMBER? } } }); } else { telephonyManager.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String phoneNumber) { super.onCallStateChanged(state, phoneNumber); if (state == TelephonyManager.CALL_STATE_RINGING) { Toast.makeText(context, "number : " + phoneNumber, Toast.LENGTH_SHORT).show(); } } }, PhoneStateListener.LISTEN_CALL_STATE); } } @RequiresApi(api = Build.VERSION_CODES.S) abstract static class CallStateListener extends TelephonyCallback implements TelephonyCallback.CallStateListener { @Override public void onCallStateChanged(int state) { } } }
解决方案
一、Android 12+ 获取来电号码
Android 12(API 31)及以上,PHONE_STATE广播不再携带来电号码,TelephonyCallback.CallStateListener也无法获取号码,需改用TelephonyCallback.CallerIdListener,同时需要申请对应权限:
- 添加权限到Manifest
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
- 动态申请权限
在应用启动或使用前,动态申请上述危险权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS}, 1001); }
- 修改Receiver代码
替换原监听逻辑为CallerIdListener,在回调中获取来电号码:
@RequiresApi(api = Build.VERSION_CODES.S) static class CallerIdCallback extends TelephonyCallback implements TelephonyCallback.CallerIdListener { private Context context; public CallerIdCallback(Context context) { this.context = context; } @Override public void onCallerIdReceived(@NonNull TelephonyManager.CallerIdResult callerIdResult) { super.onCallerIdReceived(callerIdResult); String phoneNumber = callerIdResult.getPhoneNumber(); if (phoneNumber != null) { Toast.makeText(context, "来电号码: " + phoneNumber, Toast.LENGTH_SHORT).show(); } } } // 在onReceive方法中注册 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { telephonyManager.registerTelephonyCallback(context.getMainExecutor(), new CallerIdCallback(context)); }
二、使用InCallService拒接来电
即使不开发默认通话应用,也可通过InCallService实现拒接功能,步骤如下:
- 添加权限与服务到Manifest
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <application> <service android:name=".MyInCallService" android:permission="android.permission.BIND_INCALL_SERVICE"> <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="false" /> <!-- 无需UI,仅处理逻辑 --> <intent-filter> <action android:name="android.telecom.InCallService" /> </intent-filter> </service> </application>
- 实现InCallService子类
package com.example.myapplication1; import android.telecom.Call; import android.telecom.InCallService; public class MyInCallService extends InCallService { @Override public void onCallAdded(Call call) { super.onCallAdded(call); // 判断来电状态,执行拒接 if (call.getState() == Call.STATE_RINGING) { call.reject(false, null); } } @Override public void onCallRemoved(Call call) { super.onCallRemoved(call); } }
- 动态申请权限
在应用启动时申请ANSWER_PHONE_CALLS权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { requestPermissions(new String[]{Manifest.permission.ANSWER_PHONE_CALLS}, 1002); }
- 注意事项
- 部分厂商对通话拦截有额外限制,需确保应用权限正常授予。
- 系统会在来电时绑定该服务,若多个应用注册
InCallService,优先级由系统控制。
内容的提问来源于stack exchange,提问作者Muthana Rabab'ah
相关产品推荐
相关产品推荐

