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

Android 14中Widget的BroadcastReceiver无法正常工作问题

WiFi状态Widget在Android 14无法实时更新的问题

我开发了一个追踪WiFi状态并在Widget中显示的组件。在Android 14系统中,开启或关闭WiFi后,Widget状态不会实时更新,只有调整Widget尺寸时,所有积压的状态变更才会一次性执行;但在Android 12系统中功能完全正常。

以下是相关代码实现:

1. WifiStateReceiver 代码

class WifiStateReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (WifiManager.WIFI_STATE_CHANGED_ACTION == intent.action) {
            val wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
            val isWifiEnabled = wifiState == WifiManager.WIFI_STATE_ENABLED
            updateWidget(context, isWifiEnabled)
        }
    }

    private fun updateWidget(context: Context, isWifiEnabled: Boolean) {
        val appWidgetManager = AppWidgetManager.getInstance(context)
        val componentName = ComponentName(context, MyAppWidgetProvider::class.java)
        val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)

        for (appWidgetId in appWidgetIds) {
            val views = RemoteViews(context.packageName, R.layout.widget_layout)
            views.setTextViewText(R.id.statusWifi, if (isWifiEnabled) "已开启" else "已关闭")
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }
}

2. MyAppWidgetProvider 代码

class MyAppWidgetProvider : AppWidgetProvider() {
    private var wifiStateReceiver: WifiStateReceiver? = null

    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray,
    ) {
        super.onUpdate(context, appWidgetManager, appWidgetIds)
    }

    override fun onEnabled(context: Context) {
        super.onEnabled(context)
        Log.d("WifiStateReceiver", "onEnabled")
        if (wifiStateReceiver == null) {
            wifiStateReceiver = WifiStateReceiver()
            val filter = IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                context.applicationContext.registerReceiver(wifiStateReceiver, filter, Context.RECEIVER_NOT_EXPORTED )
            }
        }
    }
    
    override fun onDisabled(context: Context) {
        super.onDisabled(context)
        Log.d("WifiStateReceiver", "onDisabled")
        wifiStateReceiver?.let {
            context.applicationContext.unregisterReceiver(it)
            wifiStateReceiver = null
        }
    }
}

3. AndroidManifest.xml 配置

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:installLocation="internalOnly">

    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Widget2"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver
            android:name=".MyAppWidgetProvider"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="android.net.wifi.supplicant.CONNECTION_CHANGE"/>
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" />
        </receiver>

        <receiver android:name=".WifiStateReceiver"
            android:exported="false">
            <intent-filter>
                <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
            </intent-filter>
        </receiver>
        <service android:name=".WifiStatusService" />
        
    </application>

</manifest>

4. Widget配置文件(widget_info.xml)

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="300dp"
    android:minHeight="100dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/widget_layout"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">
</appwidget-provider>

问题原因

Android 14对后台进程限制进一步加强:AppWidgetProvider的进程属于临时进程,Widget更新完成后会被系统快速回收,导致动态注册的广播接收器被销毁,无法接收后续WiFi状态变化。调整Widget尺寸时,系统会重启AppWidgetProvider进程,积压的状态变更会被一次性处理,因此出现延迟更新的现象。而Android 12的后台进程限制较宽松,进程存活时间更长,广播接收器可正常工作。

解决方案:使用前台服务托管广播接收器

通过前台服务持有广播接收器,保证进程不会被系统轻易回收,从而稳定接收WiFi状态变化。

1. 改造WifiStatusService为前台服务

class WifiStatusService : Service() {
    private lateinit var wifiStateReceiver: WifiStateReceiver

    override fun onCreate() {
        super.onCreate()
        wifiStateReceiver = WifiStateReceiver()
        val filter = IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)
        registerReceiver(wifiStateReceiver, filter)

        // Android 8.0+需要创建通知渠道并启动前台服务
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "WIFI_WIDGET_CHANNEL",
                "WiFi状态监控",
                NotificationManager.IMPORTANCE_LOW
            )
            getSystemService(NotificationManager::class.java).createNotificationChannel(channel)

            val notification = Notification.Builder(this, "WIFI_WIDGET_CHANNEL")
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle("WiFi状态监控")
                .setContentText("正在追踪WiFi状态")
                .build()

            startForeground(1, notification)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(wifiStateReceiver)
    }
}

2. 修改MyAppWidgetProvider,通过服务管理广播

class MyAppWidgetProvider : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray,
    ) {
        // 初始化Widget初始状态
        val wifiManager = context.getSystemService(WifiManager::class.java)
        val isWifiEnabled = wifiManager.isWifiEnabled
        val views = RemoteViews(context.packageName, R.layout.widget_layout)
        views.setTextViewText(R.id.statusWifi, if (isWifiEnabled) "已开启" else "已关闭")
        appWidgetManager.updateAppWidget(appWidgetIds, views)
    }

    override fun onEnabled(context: Context) {
        super.onEnabled(context)
        // 启动前台服务
        val serviceIntent = Intent(context, WifiStatusService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(serviceIntent)
        } else {
            context.startService(serviceIntent)
        }
    }

    override fun onDisabled(context: Context) {
        super.onDisabled(context)
        // 停止前台服务
        val serviceIntent = Intent(context, WifiStatusService::class.java)
        context.stopService(serviceIntent)
    }
}

3. 添加必要权限

在AndroidManifest.xml中添加Android 13+的通知权限:

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

4. 移除静态注册的广播接收器(可选)

删除AndroidManifest.xml中静态注册的WifiStateReceiver,避免重复接收广播:

<!-- 移除这段 -->
<receiver android:name=".WifiStateReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
    </intent-filter>
</receiver>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:35:02