好的。自 2 天以来,我一直在对这个问题进行大量调查,最终找到了一种“野蛮的方法”来解决它,而无需植根设备 :)
首先,这里是实现解决方案的重点:
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) {
// fetching package names from extras
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("YOUR_APPLICATION_PACKAGE_NAME")){
// User has selected our application under the Manage Apps settings
// now initiating background thread to watch for activity
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){
// get the info from the currently running task
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")) {
// User has clicked on the Uninstall button under the Manage Apps settings
//do whatever pre-uninstallation task you want to perform here
// show dialogue or start another activity or database operations etc..etc..
// context.startActivity(new Intent(context, MyPreUninstallationMsgActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
exit = true;
Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now", Toast.LENGTH_SHORT).show();
} else if(activityName.equals("com.android.settings.ManageApplications")) {
// back button was pressed and the user has been taken back to Manage Applications window
// we should close the activity monitoring now
exit=true;
}
}
Looper.loop();
}
}
已知限制:
当用户单击“管理应用程序设置”下的“卸载”按钮时,我们将执行我们的预卸载任务,然后将用户提示到“确认”窗口,用户可以在该窗口中确认卸载或取消操作。
如果用户在我们完成任务后点击取消按钮,上述方法目前还没有涵盖这种情况。但这可以通过一些修正轻松解决。
例如:如果最终没有收到广播“ android.intent.action.PACKAGE_REMOVED ”,我们可以实现一个逻辑来恢复我们所做的更改。
我希望这种方法对您有所帮助:) 因为这是我认为我们可以在不生根设备的情况下解决您的问题的唯一方法!
[更新 1]:检查卸载任务是否已取消的建议方法:
有趣的是,我之前有完全不同且非常复杂的想法(涉及广播、ActivityManager 等),但是在这里写它时,我脑海中突然出现了另一个相对非常简单的想法 :)
当用户单击“管理应用程序设置”下的“卸载”按钮并执行了预卸载任务后,您只需在应用程序中设置一些已执行预卸载任务并准备好卸载的 SharedPreference。在此之后,您无需关心任何事情。
如果用户继续卸载 -> 它很好,因为您已经执行了所需的任务。
而如果用户最终点击取消按钮并离开 - >不要打扰。直到用户再次运行您的应用程序。现在在应用程序主要活动的“onStart()”/“onResume()”中,您可以检查 SharedPreference 的值,如果它被设置为卸载,这意味着用户最终没有继续卸载。现在您可以恢复之前所做的更改(反转执行的预卸载任务)以确保您的应用程序完美运行!