我们想知道何时从Android设备上卸载应用程序。我们设置了有关设备应用程序的广播接收器(不在清单中),并在接收到它们时对其进行处理。问题:在卸载应用程序时(使用Android设置->应用程序/通知-> AppYouWantToUninstall->点击垃圾桶),无法接收广播...但是,只有在将应用程序安装在Android 10设备上时,这种情况才会发生。
当然,还有其他两种主要的方法来卸载应用程序:1)点击/按住应用程序,然后弹出“应用程序信息”菜单; 2)进入Play商店。另外两种方法提供了ACTION_PACKAGE_REMOVED的广播。
操作系统(Android 7、8、9和10的所有组合以及三种卸载方法均可提供ACTION_PACKAGE_REMOVED广播当应用程序在Android 10设备上时,设置卸载方法除外。我会怀疑,因此,我将回答几个可能的问题:“是的,如果我们在Android 10上使用Play Store卸载应用程序,则会获得广播”和“是的,如果我们使用在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)
}
要运行Broadcast receiver,您必须知道其工作方式。以前,当您注册广播接收器时,即使应用程序不在后台,任何注册的操作发生时也会触发它。然后,Android小组进行了一些更改以优化电池。如果您的应用目标为26或更高,则必须动态声明它而不是清单。这是文本
注意:如果您的应用定位到API级别26或更高级别,则不能使用清单以声明用于隐式广播的接收方(广播并不专门针对您的应用),除了一些隐式不受此限制的广播。在大多数情况下,可以改为使用预定的作业。
那么有什么选择?您必须使用context或applicationContext动态注册广播。因此,当您的上下文仍然存在时,应用程序会接收广播事件。这是来自Google的文字:
经上下文注册的接收者只要收到他们的广播,注册上下文有效。例如,如果您在活动上下文,只要活动是没有被摧毁。如果您在Application上下文中注册,则您只要应用程序正在运行,就可以接收广播。
那么,即使您的应用未运行,您如何收听广播事件?
由于广播接收器不可靠,我无法想象任何可行的解决方案,但是您可以一直考虑运行后台服务。这也将是多余的。检查这个答案Making BroadcastReceiver work in the background in API 26 or above
我可以想到的另一种解决方案,如果API级别低于26,它应该可以正常工作,但对于api 26及更高版本,在您的应用程序onResume中,您将检查每次可用的应用程序和当前应用程序列表。然后删除多余的应用程序。