Android 8广播意图变更:WiFiP2P应用后台监听系统广播问题咨询
Hey there, let's break down why your WiFi P2P broadcast receivers stopped working on Android Oreo and above, and how to fix it properly.
First, the core issue: Android 8.0 (API 26) introduced strict restrictions on manifest-declared broadcast receivers. Most system broadcasts—including the android.net.wifi.p2p.DISCOVERY_STATE_CHANGE and android.net.wifi.p2p.CONNECTION_STATE_CHANGE ones you're targeting—aren't on the system's whitelist. That means statically registering them in your AndroidManifest.xml won't work anymore once the app is swiped away from the recent apps list.
Here's the most reliable solution to keep listening to these broadcasts even when your app isn't in the foreground:
Solution 1: Foreground Service + Dynamic Broadcast Registration
A foreground service stays active even after the app is removed from recent apps (as long as the user doesn't force-stop it), and dynamically registered receivers aren't affected by the Oreo broadcast restrictions.
Step-by-Step Implementation:
Create a Foreground Service Class
This service will handle registering/unregistering the broadcast receiver and keep running in the background with a required notification (Oreo+ mandate):public class WiFiP2PBackgroundService extends Service { private WiFiP2PReceiver p2pReceiver; @Override public void onCreate() { super.onCreate(); // Initialize and register the receiver p2pReceiver = new WiFiP2PReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); // Add any other WiFi P2P actions you need to listen for registerReceiver(p2pReceiver, filter); // Start foreground service with a notification Notification foregroundNotification = buildForegroundNotification(); startForeground(1, foregroundNotification); } @Override public void onDestroy() { super.onDestroy(); // Clean up: unregister the receiver if (p2pReceiver != null) { unregisterReceiver(p2pReceiver); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } private Notification buildForegroundNotification() { // Create a notification channel for Oreo+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "wifi_p2p_channel", "WiFi P2P Background Service", NotificationManager.IMPORTANCE_LOW ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // Build the notification (low priority to avoid annoying users) return new NotificationCompat.Builder(this, "wifi_p2p_channel") .setContentTitle("WiFi P2P Active") .setContentText("Listening for peer connections") .setSmallIcon(R.drawable.ic_wifi_icon) .setPriority(NotificationCompat.PRIORITY_LOW) .build(); } }Implement the Broadcast Receiver
This class will handle the actual WiFi P2P state changes:public class WiFiP2PReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) { // Handle discovery state changes int discoveryState = intent.getIntExtra( WifiP2pManager.EXTRA_DISCOVERY_STATE, WifiP2pManager.DISCOVERY_STOPPED ); if (discoveryState == WifiP2pManager.DISCOVERY_STARTED) { // Peer discovery started } else { // Peer discovery stopped } } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { // Handle connection state changes NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo != null && networkInfo.isConnected()) { // Connected to a peer device } else { // Disconnected from peer } } } }Update the Manifest
Declare the service and required permissions:<!-- Required permissions for WiFi P2P --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Critical for WiFi P2P --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- For Android 9+ --> <application ...> <service android:name=".WiFiP2PBackgroundService" android:foregroundServiceType="connectedDevice" /> <!-- Optional but recommended --> </application>Start the Service When Your App Launches
Trigger the foreground service from your main Activity'sonCreate():Intent serviceIntent = new Intent(this, WiFiP2PBackgroundService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); }
Solution 2: JobScheduler (Less Ideal)
If you don't want a foreground notification, you could use JobScheduler to periodically check WiFi P2P state. However, this only works for non-real-time use cases—you won't get instant updates when broadcast events happen. It's not recommended if you need immediate responses to connection or discovery changes.
Important Notes
- Location Permission: WiFi P2P requires
ACCESS_FINE_LOCATION(not just coarse), and you'll need to request it dynamically on Android 6.0+. Without this, your receiver won't pick up any WiFi P2P events. - Battery Optimization: Some OEMs (like Samsung, Xiaomi) have aggressive battery optimization that can kill background services. Advise users to add your app to their battery optimization whitelist for reliable operation.
- Notification Priority: Setting the foreground notification to
IMPORTANCE_LOWkeeps it unobtrusive—no sound or pop-up, just a small icon in the notification shade.
内容的提问来源于stack exchange,提问作者San

