好的。我已经花了两天时间调查这个问题,最终找到了一种"狂野的方法"来解决它,而不需要对设备进行root :)
首先,以下是解决方案的要点:
1. 每当用户进入设置 -> 应用管理 -> 选择特定应用程序时,
我们会收到一个广播android.intent.action.QUERY_PACKAGE_RESTART,广播中包含应用程序包的名称作为参数。
2. 在此之后,当我们点击卸载按钮(使用包安装程序)时,它会打开一个名为com.android.packageinstaller.UninstallerActivity的活动
控制流程如下:
在应用程序设置下,用户点击卸载按钮 ---> 我们控制显示对话框/启动另一个活动/等等 ---> 我们完成预卸载任务 ---> 用户返回到卸载确认屏幕 ---> 用户确认并卸载应用程序。
使用的方法:
我们将在我们的应用程序中实现BroadcastReceiver,以监听动作"android.intent.action.QUERY_PACKAGE_RESTART",并在onReceive()方法中匹配我们的软件包名称。如果广播是为选择我们所需的应用程序包而接收到的,则我们将启动一个后台线程,该线程将使用ActivityManager监视前台运行的活动。
一旦我们发现前台活动是"com.android.packageinstaller.UninstallerActivity",就会确认用户想要卸载我们的应用程序。此时,我们将执行所需的任务(显示对话框或启动另一个在卸载窗口上重叠的活动等),然后允许用户继续确认卸载进程。
实现/源代码:
在manifest.xml中
添加权限:
<uses-permission android:name="android.permission.GET_TASKS"/>
和广播接收器:
<receiver android:name=".UninstallIntentReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<data android:scheme="package" />
</intent-filter>
</receiver>
UninstallIntentReceiver.java(卸载意图接收器类)
public class UninstallIntentReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("YOUR_APPLICATION_PACKAGE_NAME")){
new ListenActivities(context).start();
}
}
}
}
}
ListenActivities类 - 用于监控前台活动
class ListenActivities extends Thread{
boolean exit = false;
ActivityManager am = null;
Context context = null;
public ListenActivities(Context con){
context = con;
am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
public void run(){
Looper.prepare();
while(!exit){
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY);
String activityName = taskInfo.get(0).topActivity.getClassName();
Log.d("topActivity", "CURRENT Activity ::"
+ activityName);
if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
exit = true;
Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now", Toast.LENGTH_SHORT).show();
} else if(activityName.equals("com.android.settings.ManageApplications")) {
exit=true;
}
}
Looper.loop();
}
}
已知限制:
当用户在管理应用程序设置下点击卸载按钮时,我们将执行预卸载任务,然后提示用户确认窗口,在此窗口中,用户可以确认卸载或取消操作。
上述方法目前还未涵盖以下情况:如果用户在我们执行任务后单击取消按钮。但这可以通过一些修改轻松解决。
例如:如果最终未收到广播"android.intent.action.PACKAGE_REMOVED",则可以实现逻辑以恢复我们所做的更改。
我希望这种方法对您有所帮助:) 在我看来,这是唯一的方法,可以在不root设备的情况下解决您的问题!
[更新 1]:
检查卸载任务是否被取消的建议方法:
很有趣的是,我之前有完全不同且更为复杂的想法(涉及广播、ActivityManager等等),但在此处写作时,我脑海中突然浮现了另一个相对简单的想法 :)
当用户在管理应用程序设置下点击卸载按钮并在执行预卸载任务后,您只需要在应用程序中设置一些SharedPreference,告知您已执行预卸载任务并准备好卸载。之后您就不必再关心任何事情了。
如果用户继续卸载->这很好,因为您已经执行了所需的任务。
如果用户最终单击取消按钮并离开->不要费心。直到用户再次运行您的应用程序。现在,在应用程序的主活动的"onStart()" / "onResume()"中,您可以检查SharedPreference的值,如果它被设置为卸载,则表示用户最终没有继续执行卸载。现在,您可以撤消之前进行的更改(反转进行的预卸载任务),以确保您的应用程序运行正常!