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

Android Oreo静态广播接收器注册失效,如何实现后台通话记录功能?

Hey there, let's tackle this Android Oreo broadcast receiver issue you're facing—totally get why this is frustrating, since the old static broadcast approach doesn't work anymore, and dynamic registration dies when your app process is killed. Here are the most reliable solutions and workarounds specifically for call logging (incoming/outgoing calls) on Oreo and above:

1. Double-check if you can use the allowed static broadcast exceptions

First off, not all static broadcasts are blocked in Oreo! For call-related events, two key system broadcasts are still permitted for static registration:

  • android.intent.action.PHONE_STATE (triggers on incoming call state changes: ringing, off-hook, idle)
  • android.intent.action.NEW_OUTGOING_CALL (triggers when an outgoing call starts)

If you tried this before and it didn't work, make sure you've got all the pieces right:

  • Declare required permissions in your manifest:
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <!-- For Android 10+, add READ_CALL_LOG if you need call details -->
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    
  • Register the receiver correctly in the manifest, with the exact intent filters:
    <receiver
        android:name=".CallLogReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>
    
  • Note: On Android 6.0+, you need to request READ_PHONE_STATE and READ_CALL_LOG dynamically at runtime, since they're dangerous permissions.
2. Use AccessibilityService (works even when app is closed)

If static broadcasts still don't cut it (or you need more granular call data), AccessibilityService is a solid option. It's a system-level service that can monitor device-wide events, including call state changes—and it keeps running even if your app's main process is killed.

Here's the gist of how to set it up:

  • Create a class extending AccessibilityService:
    public class CallAccessibilityService extends AccessibilityService {
        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                // Check if the window belongs to the system phone app
                String packageName = event.getPackageName().toString();
                if (packageName.equals("com.android.phone") || packageName.equals("com.google.android.dialer")) {
                    // Extract call state or details here
                    TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
                    int state = tm.getCallState();
                    switch(state) {
                        case TelephonyManager.CALL_STATE_RINGING:
                            // Handle incoming call
                            break;
                        case TelephonyManager.CALL_STATE_OFFHOOK:
                            // Handle active call (incoming or outgoing)
                            break;
                        case TelephonyManager.CALL_STATE_IDLE:
                            // Handle call ended
                            break;
                    }
                }
            }
        }
    
        @Override
        public void onInterrupt() {}
    }
    
  • Register it in your manifest with the required meta-data:
    <service
        android:name=".CallAccessibilityService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibility_service_config" />
    </service>
    
  • Create the accessibility_service_config.xml in res/xml/ to define what events you want to listen to:
    <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
        android:accessibilityEventTypes="typeWindowStateChanged"
        android:accessibilityFeedbackType="feedbackGeneric"
        android:accessibilityFlags="flagDefault"
        android:canRetrieveWindowContent="true"
        android:description="@string/accessibility_service_description" />
    
  • Important: Users have to manually enable your app's accessibility service in Settings > Accessibility—you'll need to guide them through this in your app, since it's a system-level permission.
3. Foreground Service + Telephony Callback/PhoneStateListener

If you don't want to rely on accessibility permissions, using a foreground service paired with telephony listeners is another way to keep your call monitoring alive in the background.

For Android 12+ (API 31):

Use TelephonyManager.registerTelephonyCallback() which replaces the older PhoneStateListener:

  • Create a foreground service, then register the callback inside it:
    public class CallMonitoringService extends ForegroundService {
        private TelephonyManager telephonyManager;
        private TelephonyCallback telephonyCallback;
    
        @Override
        public void onCreate() {
            super.onCreate();
            // Start foreground service with a notification
            startForeground(1, createNotification());
    
            telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            telephonyCallback = new TelephonyCallback() {
                @Override
                public void onCallStateChanged(int state) {
                    super.onCallStateChanged(state);
                    // Handle call state changes here (same as before)
                }
            };
            // Register the callback (needs READ_PHONE_STATE permission)
            telephonyManager.registerTelephonyCallback(getMainExecutor(), telephonyCallback);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (telephonyCallback != null) {
                telephonyManager.unregisterTelephonyCallback(telephonyCallback);
            }
        }
    }
    

For Android 11 and below:

Use PhoneStateListener instead:

public class CallMonitoringService extends ForegroundService {
    private TelephonyManager telephonyManager;
    private PhoneStateListener phoneStateListener;

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(1, createNotification());

        telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        phoneStateListener = new PhoneStateListener() {
            @Override
            public void onCallStateChanged(int state, String phoneNumber) {
                super.onCallStateChanged(state, phoneNumber);
                // Handle call state and number here
            }
        };
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
    }
}
  • Note: Foreground services require a persistent notification (you can make it low-priority to be less intrusive), and you'll need the FOREGROUND_SERVICE permission (plus READ_PHONE_STATE/READ_CALL_LOG). While this is more reliable than dynamic registration alone, the service can still be killed by the system under extreme resource pressure—you can add logic in onTaskRemoved() to restart the service if needed.
4. InCallService (for advanced call management)

If your app needs more control over calls (like showing custom UI during calls), InCallService is the official system service for call management. It can listen to call lifecycle events even in the background, provided your app is granted the necessary permissions and is set as a default call handler (or at least has call access).

This is more complex, but it's the most robust option if you're building a full-featured call-related app. You'll need to:

  • Declare the BIND_INCALL_SERVICE permission in your manifest
  • Register the service with the android.telecom.InCallService intent filter
  • Handle callbacks like onCallAdded() and onCallRemoved() to track incoming/outgoing calls
Key Notes
  • Permissions are critical: Always test permission flows, especially on Android 10+ where call log access has stricter restrictions.
  • Battery optimization: Some devices have aggressive battery savers that can kill foreground services—you might need to guide users to exclude your app from battery optimization.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:43:25