First of all, I have researched a lot about my issue, but I could not find a proper solution so I am posting my query here. Hope to get a better solution to the issue:
首先,我已经研究了很多关于我的问题,但我找不到合适的解决方案,所以我在这里发布我的查询。希望能够更好地解决这个问题:
I have a requirement where I need to ask for password to the user before user deletes my app from settings or from any other application like MyAppSharer. I have found one solution where I can successfully be able to call my activity when user clicks on Uninstall button. I have applied trick here, and calling service. In service, I run timer which runs every 1 second and in that one second, it checks for top most activity of running task. This is running perfectly as per expected.
在用户从设置或任何其他应用程序(如MyAppSharer)删除我的应用程序之前,我需要向用户请求密码。我找到了一个解决方案,当用户点击卸载按钮时,我可以成功地调用我的活动。我在这里申请了技巧,并致电服务。在服务中,我运行计时器,每1秒运行一次,在那一秒,它检查运行任务的最顶层活动。这按预期完美运行。
Now, my issue is, this activity apppears on each of application user tries to uninstall. I need that the activity which I call, should only appear for my application when user tries to uninstall my application.
现在,我的问题是,此活动适用于每个应用程序用户尝试卸载。我需要我调用的活动应该仅在用户尝试卸载我的应用程序时出现在我的应用程序中。
Here is my code:
这是我的代码:
public static final String PACKAGE_INSTALLER = "com.android.packageinstaller";public static final String PACKAGE_INSTALLER_UNINSTALL_ACTIVITY = "com.android.packageinstaller.UninstallerActivity";alarmTimer.scheduleAtFixedRate(new TimerTask() { public void run() { mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);; ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity; final String packageName = topActivity.getPackageName(); String className = topActivity.getClassName(); Log.v(TAG, "packageName:" + packageName); Log.v(TAG, "className:" + className); if (PACKAGE_INSTALLER.equals(packageName) && PACKAGE_INSTALLER_UNINSTALL_ACTIVITY.equals(className)) { //Here I need to apply one condition where package name received to be matched with my package name. But I am not sure how to fetch package name of selected application for uninstalling //To Cancel Existing UninstallerActivity and redirect user to home. Intent homeIntent = new Intent(); homeIntent.setAction(Intent.ACTION_MAIN); homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); homeIntent.addCategory(Intent.CATEGORY_HOME); startActivity(homeIntent); //To open my activity Intent loginActivity = new Intent(UninstallService.this, Act_Login.class); loginActivity.putExtra(Constants.KEY_IS_FROM_SERVICE, true); loginActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(loginActivity); } } }, 0, 1000);
4 个解决方案
#1
5
you should try something like the following :
你应该尝试类似以下的东西:
1st - declare your broadcast recevier in the Manifest file , that will listen to QUERY_PACKAGE_RESTART :
1st - 在Manifest文件中声明你的广播接收者,它将收听QUERY_PACKAGE_RESTART:
<receiver android:name=".UninstallReceiver"> <intent-filter android:priority="999999"> <action android:name="android.intent.action.QUERY_PACKAGE_RESTART" /> <data android:scheme="package" /> </intent-filter> </receiver>
2nd - your UnunstallIntentReceiver java class like the following :
第二个 - 你的UnunstallIntentReceiver java类如下:
public class UninstallReceiver 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("application_package")){ // start your activity here and ask the user for the password } } } } }
and please give me some feedback
请给我一些反馈意见
Hope That Helps.
希望有所帮助。
#2
1
If this is a corporate requirement (if you want to block a regular user from uninstalling your app, no chance, thanks Google for protecting us from bad devs), you should create a device administrator application. This way, although the user still can delete the app, it's one extra step if you want to prevent accidental erasing.
如果这是公司要求(如果您想阻止普通用户卸载您的应用程序,没有机会,感谢Google保护我们免受恶意开发),您应该创建一个设备管理员应用程序。这样,虽然用户仍然可以删除应用程序,但如果您想要防止意外删除,这是一个额外的步骤。
Before deleting your app, if it's enabled as device admin, the user must first disable the app as administrator, and the app receives this broadcast.
在删除您的应用程序之前,如果它已作为设备管理员启用,则用户必须首先以管理员身份停用该应用程序,并且该应用程序将接收此广播。
In your XML, put
在你的XML中,放
<activity android:name=".app.DeviceAdminSample" android:label="@string/activity_sample_device_admin"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter></activity><receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver" android:label="@string/sample_device_admin" android:description="@string/sample_device_admin_description" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter></receiver>
In the receiver, you have at least two methods worth noticing:
在接收器中,您至少有两种值得注意的方法:
@Overridepublic CharSequence onDisableRequested(Context context, Intent intent) { …}@Overridepublic void onDisabled(Context context, Intent intent) { …}
This way you know the user is potentially going to erase your app.
这样您就知道用户可能会删除您的应用。
Complete guide for device administration is at https://developer.android.com/guide/topics/admin/device-admin.html
有关设备管理的完整指南,请访问https://developer.android.com/guide/topics/admin/device-admin.html
#3
1
If you have root permissions make your app system (remove your apk-file from /data
to /system
directories). Then reboot device. After reboot your app is not available to delete by user (not superuser).
如果您拥有root权限,请创建您的应用系统(从/ data到/ system目录中删除您的apk文件)。然后重启设备。重启后,您的应用程序无法被用户删除(非超级用户)。
#4
1
The only way i see, is to provide your own uninstaller as part of your app (= an activity that lists all apps and allows to uninstall them). Your service could then check if your app was the one that started the packageinstaller and if not redirect the user.
我看到的唯一方法是提供您自己的卸载程序作为应用程序的一部分(=列出所有应用程序并允许卸载它们的活动)。然后,您的服务可以检查您的应用是否是启动packageinstaller的应用,如果不是重定向用户。
It is not possible (at least on the Android 4.4 I tested with) to grab the uninstaller activity data without root or being a system app. This is because the uninstaller is not called as an independent task, but as an activity on the stack of the starting task (which is the Settings app when uninstalling from settings, etc). You can only see the Task details of the calling task.
不可能(至少在我测试过的Android 4.4上)没有root或者是系统应用程序来获取卸载程序活动数据。这是因为卸载程序不是作为独立任务调用的,而是作为启动任务堆栈上的活动(从设置卸载时的“设置”应用程序等)。您只能看到调用任务的任务详细信息。
However there might be some really dirty possibility left, that i didn't test to the end: You could register the hidden interface IThumbnailReceiver
[1] with the hidden three argument version of ActivityManager.getRunningTasks
[2]. It seems like only the GET_TASKS permission is needed to grab a thumbnail (see [3]). It should be possible to find out which app is going to be removed from the app thumbnail... - But as this solution uses hidden APIs, there is no guarantee that it will work with older/newer/vendored Android versions.
然而,可能存在一些非常脏的可能性,我没有测试到最后:您可以使用隐藏的三个参数版本的ActivityManager.getRunningTasks [2]注册隐藏的接口IThumbnailReceiver [1]。看起来只需要GET_TASKS权限来获取缩略图(参见[3])。应该可以找出哪个应用程序将从应用程序缩略图中删除... - 但是由于此解决方案使用隐藏的API,因此无法保证它将适用于较旧/较新/销售的Android版本。
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/IThumbnailReceiver.aidl
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/ActivityManager.java#L766
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/services/java/com/android/server/am/ActivityManagerService.java#L6725
#1
5
you should try something like the following :
你应该尝试类似以下的东西:
1st - declare your broadcast recevier in the Manifest file , that will listen to QUERY_PACKAGE_RESTART :
1st - 在Manifest文件中声明你的广播接收者,它将收听QUERY_PACKAGE_RESTART:
<receiver android:name=".UninstallReceiver"> <intent-filter android:priority="999999"> <action android:name="android.intent.action.QUERY_PACKAGE_RESTART" /> <data android:scheme="package" /> </intent-filter> </receiver>
2nd - your UnunstallIntentReceiver java class like the following :
第二个 - 你的UnunstallIntentReceiver java类如下:
public class UninstallReceiver 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("application_package")){ // start your activity here and ask the user for the password } } } } }
and please give me some feedback
请给我一些反馈意见
Hope That Helps.
希望有所帮助。
#2
1
If this is a corporate requirement (if you want to block a regular user from uninstalling your app, no chance, thanks Google for protecting us from bad devs), you should create a device administrator application. This way, although the user still can delete the app, it's one extra step if you want to prevent accidental erasing.
如果这是公司要求(如果您想阻止普通用户卸载您的应用程序,没有机会,感谢Google保护我们免受恶意开发),您应该创建一个设备管理员应用程序。这样,虽然用户仍然可以删除应用程序,但如果您想要防止意外删除,这是一个额外的步骤。
Before deleting your app, if it's enabled as device admin, the user must first disable the app as administrator, and the app receives this broadcast.
在删除您的应用程序之前,如果它已作为设备管理员启用,则用户必须首先以管理员身份停用该应用程序,并且该应用程序将接收此广播。
In your XML, put
在你的XML中,放
<activity android:name=".app.DeviceAdminSample" android:label="@string/activity_sample_device_admin"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter></activity><receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver" android:label="@string/sample_device_admin" android:description="@string/sample_device_admin_description" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter></receiver>
In the receiver, you have at least two methods worth noticing:
在接收器中,您至少有两种值得注意的方法:
@Overridepublic CharSequence onDisableRequested(Context context, Intent intent) { …}@Overridepublic void onDisabled(Context context, Intent intent) { …}
This way you know the user is potentially going to erase your app.
这样您就知道用户可能会删除您的应用。
Complete guide for device administration is at https://developer.android.com/guide/topics/admin/device-admin.html
有关设备管理的完整指南,请访问https://developer.android.com/guide/topics/admin/device-admin.html
#3
1
If you have root permissions make your app system (remove your apk-file from /data
to /system
directories). Then reboot device. After reboot your app is not available to delete by user (not superuser).
如果您拥有root权限,请创建您的应用系统(从/ data到/ system目录中删除您的apk文件)。然后重启设备。重启后,您的应用程序无法被用户删除(非超级用户)。
#4
1
The only way i see, is to provide your own uninstaller as part of your app (= an activity that lists all apps and allows to uninstall them). Your service could then check if your app was the one that started the packageinstaller and if not redirect the user.
我看到的唯一方法是提供您自己的卸载程序作为应用程序的一部分(=列出所有应用程序并允许卸载它们的活动)。然后,您的服务可以检查您的应用是否是启动packageinstaller的应用,如果不是重定向用户。
It is not possible (at least on the Android 4.4 I tested with) to grab the uninstaller activity data without root or being a system app. This is because the uninstaller is not called as an independent task, but as an activity on the stack of the starting task (which is the Settings app when uninstalling from settings, etc). You can only see the Task details of the calling task.
不可能(至少在我测试过的Android 4.4上)没有root或者是系统应用程序来获取卸载程序活动数据。这是因为卸载程序不是作为独立任务调用的,而是作为启动任务堆栈上的活动(从设置卸载时的“设置”应用程序等)。您只能看到调用任务的任务详细信息。
However there might be some really dirty possibility left, that i didn't test to the end: You could register the hidden interface IThumbnailReceiver
[1] with the hidden three argument version of ActivityManager.getRunningTasks
[2]. It seems like only the GET_TASKS permission is needed to grab a thumbnail (see [3]). It should be possible to find out which app is going to be removed from the app thumbnail... - But as this solution uses hidden APIs, there is no guarantee that it will work with older/newer/vendored Android versions.
然而,可能存在一些非常脏的可能性,我没有测试到最后:您可以使用隐藏的三个参数版本的ActivityManager.getRunningTasks [2]注册隐藏的接口IThumbnailReceiver [1]。看起来只需要GET_TASKS权限来获取缩略图(参见[3])。应该可以找出哪个应用程序将从应用程序缩略图中删除... - 但是由于此解决方案使用隐藏的API,因此无法保证它将适用于较旧/较新/销售的Android版本。
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/IThumbnailReceiver.aidl
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/core/java/android/app/ActivityManager.java#L766
- https://github.com/omnirom/android_frameworks_base/blob/android-4.4/services/java/com/android/server/am/ActivityManagerService.java#L6725