You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Oreo系统下无法获取呼出号码问题求助

解决Android Oreo无法获取呼出号码的问题

我来帮你搞定这个在Oreo系统上拿不到呼出号码的问题,核心原因是Android 8.0(API 26)对广播接收器的权限和注册方式做了严格限制,你的老代码在低版本能正常运行,到Oreo就失效了,具体原因和修复方案如下:

问题根源

在Oreo之前,静态注册的BroadcastReceiver可以正常接收android.intent.action.NEW_OUTGOING_CALL广播,但从Android 8.0开始,系统禁止静态注册的接收器接收大部分隐式广播(包括这个呼出电话广播),你的场景刚好不在例外范围内。另外,你在onReceive里嵌套注册PhoneStateListener的做法也不严谨,容易导致内存泄漏和重复监听的问题。

分步修复方案

1. 替换静态注册为动态注册广播接收器

Oreo及以上系统必须动态注册NEW_OUTGOING_CALL的接收器,不能再依赖Manifest里的静态注册。比如在你的主Activity或者Application类里完成注册:

public class MainActivity extends AppCompatActivity {
    private CallBroadcastReceiver callReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化并动态注册广播接收器
        callReceiver = new CallBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        registerReceiver(callReceiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 一定要注销接收器,避免内存泄漏
        if (callReceiver != null) {
            unregisterReceiver(callReceiver);
        }
    }
}

2. 重构广播接收器逻辑

把来电和呼出的监听逻辑整合到一个更简洁的接收器里,去掉嵌套的PhoneStateListener(呼出电话直接通过广播处理就足够了):

首先确保Manifest里声明了必要权限:

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

然后修改接收器代码:

public class CallBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action == null) return;

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        String targetNumber = null;

        switch (action) {
            // 处理来电逻辑
            case TelephonyManager.ACTION_PHONE_STATE_CHANGED:
                targetNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                break;
            // 处理呼出电话逻辑
            case Intent.ACTION_NEW_OUTGOING_CALL:
                targetNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                break;
        }

        if (targetNumber != null) {
            editor.putString("number", targetNumber);
            editor.apply();
            initialiseAndStartService(context);
        }
    }

    private void initialiseAndStartService(Context context) {
        // 注意:Oreo之后启动后台服务会被限制,需要改成前台服务
        Intent serviceIntent = new Intent(context, YourTargetService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(serviceIntent);
        } else {
            context.startService(serviceIntent);
        }
    }
}

3. 适配Oreo的前台服务要求

如果你的initialiseAndStartService启动的是普通后台服务,在Oreo及以上系统会被系统强制停止,所以要把服务改成前台服务,并创建通知通道(API 26+强制要求):

在你的服务类里添加:

@Override
public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // 创建通知通道
        String channelId = "CallService_Channel";
        NotificationChannel channel = new NotificationChannel(
                channelId,
                "Call Processing Service",
                NotificationManager.IMPORTANCE_LOW // 低优先级,不会打扰用户
        );
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);

        // 启动前台服务
        Notification notification = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_service_icon)
                .setContentTitle("正在处理通话")
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .build();
        startForeground(1001, notification);
    }
}

额外提示

  • 动态注册的接收器会在宿主组件(比如Activity)销毁时失效,所以如果需要全局监听,可以考虑在Application类里注册,但要注意内存泄漏问题。
  • 测试时记得给应用授予必要的电话权限,Oreo之后权限需要动态申请,别忘了加权限申请的逻辑哦。

内容的提问来源于stack exchange,提问作者yasir khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:21:09