Android App不被手动强制停止和卸载的实现

最近在做项目时,遇到一个这样的问题,如何让我们的App在“系统设置”里面,不被手动强制停止和卸载?

首先,我们分析一下:

- 要实现不被手动停止,必须让系统设置的App详情页面的“强制停止”按钮被置灰才能做到。
- 要实现不被手动卸载,必须让App 获取系统的设备管理权限。

要实现以上两点,我们必须想办法让App在启动时自动获取系统的设备管理权限。接下来,我们通过查阅相关资料,需要按照以下步骤来做:

第一步:实现一个广播监听器,继承DeviceAdminReceiver。如下:

   

public class MyAdminReceiver extends DeviceAdminReceiver {
        private static final String TAG = "CustomAdminReceiver";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);
        }
    
        @Override
        public void onEnabled(Context context, Intent intent) {
            super.onEnabled(context, intent);
        }
    
        @Override
        public void onDisabled(Context context, Intent intent) {
            // onDisabled
        }
    }

第二步:在工程的res目录下,创建xml目录,在xml目录下创建my_admin.xml文件,具体内容如下:

   

<?xml version="1.0" encoding="utf-8"?>
    <device-admin xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-policies>
            <!--设置密码规则-->
            <limit-password />
            <!--监控登录次数-->
            <watch-login />
            <!--重置密码-->
            <reset-password />
            <!--强制锁屏-->
            <force-lock />
            <!--清空数据(恢复出厂设置)-->
            <wipe-data />
        </uses-policies>
    </device-admin>

第三步:在AndroidManifest.xml清单文件,添加以下内容:   

<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />

    <receiver
        android:name=".MyAdminReceiver"
        android:exported="false"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/my_admin" />
    
        <intent-filter>
            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
        </intent-filter>
    </receiver>

第四步:创建DeviceAdminUtil类,主要是做相关初始化,设备管理权限获取等。具体如下:

public class DeviceAdminUtil {
    
        private static DeviceAdminUtil instance;
        private DevicePolicyManager devicePolicyManager;
        private ComponentName componentName;
        private Context mContext;
    
        public static synchronized DeviceAdminUtil getInstance() {
            if (instance == null) {
                instance = new DeviceAdminUtil();
            }
            return instance;
        }
    
        /**
         * 初始化“设备管理权限的获取”
         *
         * @param context
         */
        public void init(Context context) {
            mContext = context.getApplicationContext();
            // 获取系统管理权限
            devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
            // 申请权限
            componentName = new ComponentName(mContext, MyAdminReceiver.class);
        }
    
        /**
         * 判断App是否已激活获取了设备管理权限,true:已激活,false:未激活
         *
         * @return
         */
        private boolean isAdminActive() {
            // 判断组件是否有系统管理员权限
            return devicePolicyManager.isAdminActive(componentName);
        }
    
        public void lockScreen() {
            if (isAdminActive() && devicePolicyManager != null) {
                // 立刻锁屏
                devicePolicyManager.lockNow();
            }
        }
    
    }

经过上述4步操作,已基本实现我们当初的想法。现在我们来验证下。

首先:那我们在App的Application的onCreate方法调用

DeviceAdminUtil.getInstance().init(this);

然后,再某一个按钮点击事件里,调用

DeviceAdminUtil.getInstance().lockScreen();

接下来,我们运行下App,点击那个按钮并没有锁屏,在系统设置的App详情页面,我们也发现App还是可以手动强制停止,还是可以手动卸载。怎么回事呢?

我们调试发现,做了上述4步,devicePolicyManager.isAdminActive(componentName)这个方法返回仍是false,也就是说App并没有被激活。原因找到了,我们就要想办法激活App。我们查阅DevicePolicyManager的源码,里面有很多方法,其中有一个方法如下:

   

    /**
     * @hide
     */
    public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) {
        setActiveAdmin(policyReceiver, refreshing, myUserId());
    }

这个方法就是激活App获取设备管理权限的方法,但被@hide了,也就是说这个方法只有系统源码层才能直接调用,应用层不能直接调用。到这里,有经验的小伙伴应该会想到,用反射来调用setActiveAdmin方法,实现如下:

   

private void setDeviceAdminActive(boolean active) {
        try {
            if (devicePolicyManager != null && componentName != null) {
                Method setActiveAdmin = devicePolicyManager.getClass().getDeclaredMethod("setActiveAdmin", ComponentName.class, boolean.class);
                setActiveAdmin.setAccessible(true);
                setActiveAdmin.invoke(devicePolicyManager, componentName, active);
            }
        } catch (Exception e) {
            LogUtil.e(e);
        }
    }

这里给出DeviceAdminUtil类的最终实现,如下:

public class DeviceAdminTool {
    
        private static DeviceAdminUtil instance;
        private DevicePolicyManager devicePolicyManager;
        private ComponentName componentName;
        private Context mContext;
    
        public static synchronized DeviceAdminUtil getInstance() {
            if (instance == null) {
                instance = new DeviceAdminUtil();
            }
            return instance;
        }
    
        /**
         * 初始化“设备管理权限的获取”
         *
         * @param context
         */
        public void init(Context context) {
            mContext = context.getApplicationContext();
            // 获取系统管理权限
            devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
            // 申请权限
            componentName = new ComponentName(mContext, MyAdminReceiver.class);
    
            setDeviceAdminActive(true);
        }
    
        /**
         * 判断App是否已激活获取了设备管理权限,true:已激活,false:未激活
         * app预装,启动后要授权静默激活
         *
         * @return
         */
        private boolean isAdminActive() {
            // 判断组件是否有系统管理员权限
            return devicePolicyManager.isAdminActive(componentName);
        }
    
        public void lockScreen() {
            if (isAdminActive() && devicePolicyManager != null) {
                // 立刻锁屏
                devicePolicyManager.lockNow();
            }
        }
    
        private void setDeviceAdminActive(boolean active) {
            try {
                if (devicePolicyManager != null && componentName != null) {
                    Method setActiveAdmin = devicePolicyManager.getClass().getDeclaredMethod("setActiveAdmin", ComponentName.class, boolean.class);
                    setActiveAdmin.setAccessible(true);
                    setActiveAdmin.invoke(devicePolicyManager, componentName, active);
                }
            } catch (Exception e) {
                LogUtil.e(e);
            }
        }
    
    }

以上,在Android7.1,Android8.1上测试有效。

大家如果有好的建议,请留言交流,谢谢~~
 

本文章已同步发表在此技术公众号,欢迎大家关注,转发。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Android 应用程序被用户手动杀死时,应用程序会收到 `onDestroy()` 生命周期回调函数。但是,在这种情况下,您无法阻止应用程序被杀死。因此,如果您希望在应用程序被杀死时执行某些操作,例如重新启动应用程序或发送通知等,您需要使用一些其他方法。 一种方法是使用 Android 的 `Service` 组件。通过创建一个 `Service`,您可以在应用程序被杀死后在后台继续运行代码。要监听应用程序被杀死的事件,您可以在 `Service` 中实现 `onTaskRemoved()` 方法。 在 `onTaskRemoved()` 方法中,您可以执行您希望在应用程序被杀死时执行的操作。例如,您可以使用 `PendingIntent` 发送一个通知,提示用户重新启动应用程序。 以下是一个示例代码片段,演示如何在 `Service` 中监听应用程序被杀死的事件: ```java public class MyService extends Service { @Override public void onCreate() { super.onCreate(); // 在此处执行任何必要的初始化操作 } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 在此处执行您希望在后台运行的代码 return START_STICKY; } @Override public void onTaskRemoved(Intent rootIntent) { // 在此处执行您希望在应用程序被杀死时执行的操作 super.onTaskRemoved(rootIntent); } @Override public IBinder onBind(Intent intent) { // 如果您的 Service 不提供绑定,则返回 null return null; } } ``` 请注意,使用 `Service` 可能会对设备的电池寿命产生影响。如果您希望在应用程序被杀死时执行某些操作,但不需要在后台运行代码,请考虑使用 Android 的 `AlarmManager` 和 `BroadcastReceiver` 组件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值