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

Google自动更新WebView后应用被强制关闭的问题求助

问题:WebView自动更新强制关闭应用后无法自动唤回

我开发的是一款混合应用,通过WebView展示全部内容,要求始终保持前台运行,部署在第三方厂商的Android 10英寸房间面板(Android 11)上,无需考虑电池续航问题。

核心问题:Google的WebView自动更新(出于安全必须保留)会直接强制关闭我的应用,且不会触发Activity的onPause、onDestroy等生命周期方法,类似崩溃但无Crashlytics/Sentry报错。

通过连续5天ADB日志监控,捕获到应用被关闭的关键日志:

2024-01-11 07:51:56.665 ActivityManager      system_server  I  Killing 4372:com.example.myapp/u0a167 (adj 0): stop com.google.android.webview due to installPackageLI
2024-01-11 07:51:56.670 ActivityTaskManager  system_server  W  Force removing ActivityRecord{7fad574 u0 com.example.myapp/.ui.MainActivity t100 f}}: app died, no saved state

我已实现一个粘性前台服务用于检测应用后台状态并唤回,普通场景下正常工作,但WebView更新强制杀进程时,因Activity生命周期未触发,服务无法感知应用已退出,无法执行唤回操作。


现有代码分析

前台检查服务(ForegroundCheckService.kt)

class ForegroundCheckService : Service() {

    private val handler = Handler(Looper.getMainLooper())
    private val foregroundCheckRunnable = object : Runnable {
        override fun run() {
            val isAppInForeground = OBApp.instance.isAppInForeground()

            if (!isAppInForeground) {
                bringAppToForeground()
            }

            handler.postDelayed(this, TimeUnit.MINUTES.toMillis(Constants.FOREGROUND_CHECK_INTERVAL))
        }
    }

    override fun onCreate() {
        super.onCreate()
        startForeground(1, createForegroundNotification())
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        try {
            handler.post(foregroundCheckRunnable)
        } catch (e: Exception) {
            Log.e("ForegroundCheckService", "Error in onStartCommand: $e")
        }
        return START_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacks(foregroundCheckRunnable)
    }

    private fun createForegroundNotification(): Notification {
        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("App Foreground Service")
            .setContentText("Running in the background")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setSilent(true)
            .build()
    }

    private fun bringAppToForeground() {
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        startActivity(intent)
    }

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

    companion object {
        const val CHANNEL_ID = "ForegroundServiceChannel"
    }
}

AndroidManifest.xml配置

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

<service
        android:name=".helper.ForegroundCheckService"
        android:foregroundServiceType="dataSync"
        android:stopWithTask="false" />

前台状态管理器(ForegroundManager.kt)

class ForegroundManager : Application.ActivityLifecycleCallbacks {
    private var isForeground = false

    fun isForeground(): Boolean {
        return isForeground
    }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        // No-op
    }

    override fun onActivityStarted(activity: Activity) {
        // No-op
    }

    override fun onActivityResumed(activity: Activity) {
        if (activity::class.java == MainActivity::class.java) {
            isForeground = true
            Log.d(Constants.TAG, "App to foreground (onResume)}")
        }
    }

    override fun onActivityPaused(activity: Activity) {
        if (activity::class.java == MainActivity::class.java) {
            isForeground = false
            Log.d(Constants.TAG, "App to background (onPause)}")
        }
    }

    override fun onActivityStopped(activity: Activity) {
        if (activity::class.java == MainActivity::class.java) {
            isForeground = false
            Log.d(Constants.TAG, "App to background (onStop)}")
        }
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
        // No-op
    }

    override fun onActivityDestroyed(activity: Activity) {
        // No-op
    }
}

Application类(OBApp.kt)

class OBApp : DaggerApplication() {
    companion object {
        lateinit var instance: OBApp
    }

    private val foregroundManager = ForegroundManager()

    override fun onCreate() {
        super.onCreate()
        Log.d("OBApp", "OnCreate() ")
        instance = this
        registerActivityLifecycleCallbacks(foregroundManager)
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                ForegroundCheckService.CHANNEL_ID,
                "Foreground Service Channel",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            channel.setSound(null, null)
            val notificationManager = getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(channel)
        }
    }

    override fun onTerminate() {
        super.onTerminate()
        unregisterActivityLifecycleCallbacks(foregroundManager)
    }

    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.factory().create(this)
    }

    fun isAppInForeground(): Boolean {
        return foregroundManager.isForeground()
    }

}

问题根源与解决方案

现有代码的缺陷

当前isAppInForeground()仅依赖Activity生命周期回调判断状态,但WebView更新是直接杀进程,Activity的生命周期方法完全不会触发,导致isForeground仍保持true,服务不会执行唤回操作。另外,前台服务类型设置为dataSync,与"保持应用前台"的场景匹配度较低。

解决方案

1. 改进前台状态检测逻辑:直接检查进程/Activity存活状态

替换原有依赖生命周期的判断,改为直接查询系统进程信息确认应用是否在前台:

修改OBApp中的isAppInForeground():

fun isAppInForeground(): Boolean {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val appProcesses = activityManager.runningAppProcesses ?: return false
    for (processInfo in appProcesses) {
        if (processInfo.processName == packageName && processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            // 进一步确认MainActivity是否在栈顶
            val tasks = activityManager.getRunningTasks(1)
            if (tasks.isNotEmpty()) {
                val topActivity = tasks[0].topActivity
                return topActivity?.className == MainActivity::class.java.name
            }
            return true
        }
    }
    return false
}

在Manifest中添加必要权限:

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

2. 让前台服务在进程重启后立即唤醒应用

修改服务的onStartCommand,返回START_REDELIVER_INTENT确保重启后恢复任务,并在启动时立即检查应用状态:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    try {
        // 服务启动/重启时立即检查并唤醒
        checkAndBringToForeground()
        handler.post(foregroundCheckRunnable)
    } catch (e: Exception) {
        Log.e("ForegroundCheckService", "Error in onStartCommand: $e")
    }
    return START_REDELIVER_INTENT
}

private fun checkAndBringToForeground() {
    val isAppInForeground = OBApp.instance.isAppInForeground()
    if (!isAppInForeground) {
        bringAppToForeground()
    }
}

// 同步修改Runnable逻辑
private val foregroundCheckRunnable = object : Runnable {
    override fun run() {
        checkAndBringToForeground()
        handler.postDelayed(this, TimeUnit.MINUTES.toMillis(Constants.FOREGROUND_CHECK_INTERVAL))
    }
}

3. 优化前台服务配置

将服务类型改为更匹配的specialUse,如果设备是厂商定制面板,可申请将应用设为系统应用并添加android:persistent="true",降低被系统杀死的概率:

<service
        android:name=".helper.ForegroundCheckService"
        android:foregroundServiceType="specialUse"
        android:stopWithTask="false"
        android:persistent="true" />

4. 添加进程重启后的自动唤醒逻辑

在OBApp的onCreate中判断是否为进程重启,直接启动主Activity:

override fun onCreate() {
    super.onCreate()
    Log.d("OBApp", "OnCreate() ")
    if (!::instance.isInitialized) {
        instance = this
        registerActivityLifecycleCallbacks(foregroundManager)
        createNotificationChannel()
        // 进程重启后直接唤醒主Activity
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        startActivity(intent)
    }
}

额外建议
  • 联系设备厂商将应用加入系统白名单,禁止WebView更新时杀死应用进程。
  • 手动触发WebView更新(通过ADB安装更新包),验证服务唤回逻辑是否生效。
  • 缩短前台检查间隔至30秒以内,提高检测及时性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:32:03