【问题标题】:Not getting ACTION_PACKAGE_REMOVED broadcast - Android 10/Settings没有收到 ACTION_PACKAGE_REMOVED 广播 - Android 10/设置
【发布时间】:2020-06-05 03:20:13
【问题描述】:

我们想知道应用何时从 Android 设备上卸载。我们设置有关设备应用程序的广播接收器(不在清单中)并在收到时处理它们。问题:卸载应用程序时(使用 Android 设置 -> 应用程序/通知 -> AppYouWantToUninstall -> 点击垃圾箱)未收到广播……但这仅在应用程序安装在 Android 10 设备上时发生。

当然还有另外两种主要的卸载应用方式: 1) 长按应用,调出“应用信息”菜单; 2) 进入 Play 商店。其他两种方法发送 ACTION_PACKAGE_REMOVED 广播。

操作系统(Android 7、8、9 和 10)的所有组合和三种卸载方法都会发送 ACTION_PACKAGE_REMOVED 广播当应用在 Android 10 设备上时,设置卸载方法除外。 I我也会持怀疑态度,所以我会回答几个可能的问题:“是的,如果我们在 Android 10 上使用 Play 商店卸载应用程序,我们确实会收到广播” 和 “是的,如果我们对 Android 7、8、9 上的应用程序使用设置卸载,我们确实会收到广播”

类中的定义:

class AppInstallBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent == null || context == null) return
        when (intent.action) {
            Intent.ACTION_PACKAGE_ADDED ->
                enqueueWork(context, getIntent(context, ACTION_PACKAGE_ADDED, intent.data?.schemeSpecificPart))
            Intent.ACTION_PACKAGE_REPLACED ->
                enqueueWork(context, getIntent(context, ACTION_PACKAGE_REPLACED, intent.data?.schemeSpecificPart))
            Intent.ACTION_PACKAGE_CHANGED ->
                enqueueWork(context, getIntent(context, ACTION_PACKAGE_CHANGED, intent.data?.schemeSpecificPart))
            Intent.ACTION_PACKAGE_REMOVED ->
                enqueueWork(context, getIntent(context, ACTION_PACKAGE_REMOVED, intent.data?.schemeSpecificPart))
            Intent.ACTION_PACKAGE_FULLY_REMOVED ->
                enqueueWork(context, getIntent(context, ACTION_PACKAGE_FULLY_REMOVED, intent.data?.schemeSpecificPart))
                }
    }

...这是我们处理收到的操作的地方

    private suspend fun processAction(action:String, packageName: String, context: Context) {
        when (action) {
            ACTION_PACKAGE_ADDED -> updateAppInfo(context, packageName, false)
            ACTION_PACKAGE_REPLACED -> updateAppInfo(context, packageName, true)
            ACTION_PACKAGE_REMOVED -> deleteAppInfo(context, packageName)
            ACTION_PACKAGE_FULLY_REMOVED -> deleteFullyAppInfo(context, packageName)
        }
    }

这是我们定义(在应用程序中,而不是清单中)接收者的地方:

    private val installBroadcastReceiver = AppInstallBroadcastReceiver()
    private val installReceiverFilter = IntentFilter().apply {
        addAction(Intent.ACTION_PACKAGE_ADDED)
        addAction(Intent.ACTION_PACKAGE_REMOVED)
        addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
        addAction(Intent.ACTION_PACKAGE_CHANGED)
        addAction(Intent.ACTION_PACKAGE_REPLACED)
        addDataScheme("package")
    }

...我们在哪里注册,过滤

    private fun registerAppChanges() {
        Timber.d("Registering the installation receiver ..")
        registerReceiver(installBroadcastReceiver, installReceiverFilter)
        registerReceiver(unlockReceiver, unlockReceiverFilter)
    }

【问题讨论】:

  • 如你所见:有一个动作 ACTION_PACKAGE_FULLY_REMOVED ——在我们的测试中,这个广播从未见过——我们认为也许我们错过了那个类型......但事实证明不是就是这样。另外:我们不处理 ACTION_PACKAGE_CHANGED - 不要认为适用于卸载...可能是错误的。
  • 能否告诉你是如何注册AppInstallBroadcastReceiver的。它是在清单文件中还是在活动中注册的。
  • @androidcodehunter 是的,我将编辑问题的代码部分并显示我们正在注册活动。

标签: android kotlin broadcastreceiver uninstallation


【解决方案1】:

要运行Broadcast receiver,您必须知道它是如何工作的。以前,当您注册广播接收器时,即使应用程序不在后台,当任何注册操作发生时都会触发它。然后 android 团队进行了一些更改以优化电池。如果您的应用程序面向 26 或更高版本,则必须动态声明它而不是清单。这是正文

注意:如果您的应用针对 API 级别 26 或更高级别,则不能使用 manifest 声明一个隐式广播的接收器(广播 不专门针对您的应用程序),除了一些隐含的 不受该限制的广播。在大多数情况下,您 可以改为使用计划作业。

那么有什么选择呢?您必须使用上下文或 applicationContext 动态注册广播。因此,当您的上下文处于活动状态时,应用程序会接收广播事件。这是来自谷歌的文字:

上下文注册的接收者接收广播,只要他们的 注册上下文是有效的。例如,如果您在 一个活动上下文,只要活动是 没有被破坏。如果您在应用程序上下文中注册,您 只要应用程序正在运行,就可以接收广播。

那么,即使您的应用没有运行,您如何收听广播事件?

由于广播接收器不可靠,我无法想象任何可行的解决方案,但您可以考虑一直运行后台服务。这也将是矫枉过正。检查这个答案 Making BroadcastReceiver work in the background in API 26 or above 还有这个来自commonsware Android O and the Implicit Broadcast Ban

我能想到的另一个解决方案,如果 API 级别低于 26,它应该可以正常工作,但对于 api 26 及更高版本,在您的应用程序 onResume 中,您将检查每次可用的应用程序和您当前的应用程序列表。然后删除额外的应用程序。

【讨论】:

    【解决方案2】:

    接受接收器在很大程度上无法(不再)以对我们的情况有用的方式工作的现实,使用的解决方案是 1)在 onResume 中嵌入一些检查代码,以查看设备现实之间是否存在差异以及应用对现实的理解; 2) 使用一种接收器类型 (ACTION_PACKAGE_FULLY_REMOVED) 至少跟上那些(在我们的案例中主要关注的问题)。

    要使新的接收器类型生效,您必须在清单中注册接收器,如下所示:

            <receiver
                android:name=".receiver.FullyRemovedBroadcastReceiver">
    <!--            <android:exported="true">  -->
                 <intent-filter>
                     <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
                     <data android:scheme="package"/>
                  </intent-filter>
             </receiver>
    

    剩下的部分(创建广播接收器类):

     class FullyRemovedBroadcastReceiver : BroadcastReceiver() {
         override fun onReceive(context: Context?, intent: Intent?) {
             if (intent == null || context == null) return
             when (intent.action) {
                 ACTION_PACKAGE_FULLY_REMOVED ->
                     enqueueWork(context, getIntent(context, ACTION_PACKAGE_FULLY_REMOVED, intent.data?.schemeSpecificPart))
                 }
         }
    
         private fun getIntent(context: Context?, action: String, packageName: String?) =
                 Intent(context, AppChangeJobIntentService::class.java).apply {
                     this.action = action
                     putExtra(EXTRA_PACKAGE_NAME, packageName)
                     putExtra(EXTRA_DATA_REMOVED, true)
                     putExtra(EXTRA_REPLACING, false)
                 }
    
         private fun enqueueWork(context: Context, intent: Intent) {
             JobIntentService.enqueueWork(
                     context,
                     AppChangeJobIntentService::class.java,
                     APP_CHANGE_JOB_ID,
                     intent)
         }
     }
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      相关资源
      最近更新 更多