You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 10-12系统下隐藏APP或阻止卸载的技术方案咨询

Android 10-12 隐藏式启动器完全隐藏&防卸载解决方案思路

一、彻底隐藏Launcher图标(解决拖拽卸载入口问题)

Android 10+ 对Launcher图标的加载逻辑做了调整,仅禁用主Activity组件已无法完全隐藏图标,需从以下方向处理:

  • 禁用所有带LAUNCHER意图过滤器的组件:检查你的AndroidManifest.xml,凡是声明了<intent-filter>包含android.intent.action.MAIN和android.intent.category.LAUNCHER的组件(包括主Activity、Activity别名<activity-alias>),都要逐个禁用。示例代码:
    private void hideAllLauncherComponents(Context context) {
        PackageManager pm = context.getPackageManager();
        String packageName = context.getPackageName();
        try {
            PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES | PackageManager.GET_ACTIVITY_ALIASES);
            // 处理主Activity
            if (packageInfo.activities != null) {
                for (ActivityInfo activity : packageInfo.activities) {
                    if (isLauncherComponent(activity)) {
                        ComponentName component = new ComponentName(packageName, activity.name);
                        pm.setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
                    }
                }
            }
            // 处理Activity别名
            if (packageInfo.activityAliases != null) {
                for (ActivityInfo alias : packageInfo.activityAliases) {
                    if (isLauncherComponent(alias)) {
                        ComponentName component = new ComponentName(packageName, alias.name);
                        pm.setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
                    }
                }
            }
            // 通知Launcher刷新图标缓存
            context.sendBroadcast(new Intent(Intent.ACTION_PACKAGE_CHANGED).setData(Uri.parse("package:" + packageName)));
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    private boolean isLauncherComponent(ActivityInfo info) {
        if (info.intentFilters == null) return false;
        for (IntentFilter filter : info.intentFilters) {
            boolean hasMainAction = filter.hasAction(Intent.ACTION_MAIN);
            boolean hasLauncherCategory = filter.hasCategory(Intent.CATEGORY_LAUNCHER);
            if (hasMainAction && hasLauncherCategory) {
                return true;
            }
        }
        return false;
    }
    
  • 强制刷新Launcher缓存:部分第三方Launcher会缓存图标数据,禁用组件后发送ACTION_PACKAGE_CHANGED广播,能触发Launcher重新加载应用信息。

二、阻止所有卸载途径

1. 成为默认Launcher并锁定默认设置

  • 将你的APP注册为Launcher(在Manifest中声明android.intent.category.HOME和android.intent.category.DEFAULT的意图过滤器),引导用户设置为默认启动器。当APP是唯一默认Launcher时,系统会阻止普通卸载操作;结合设备所有者权限,调用DevicePolicyManager.setHomePackage()锁定默认Launcher,防止用户切换。

2. 获取设备所有者权限(Device Owner)

设备所有者权限可直接阻止应用卸载,无需root:

  • 调用DevicePolicyManager.setUninstallBlocked()方法,将你的APP包名设为不可卸载:
    private void blockUninstall(Context context) {
        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        ComponentName adminComponent = new ComponentName(context, YourDeviceAdminReceiver.class);
        if (dpm.isAdminActive(adminComponent)) {
            dpm.setUninstallBlocked(adminComponent, context.getPackageName(), true);
        }
    }
    
  • 注意:设备所有者权限需要用户通过NFC、二维码或企业MDM方式激活,无法在普通安装流程中自动获取。

3. 转为系统级应用(最彻底)

将APP安装到设备的/system/app或/priv-app目录(需设备root或厂商签名),系统级应用默认无法被普通用户卸载,只能通过root权限或恢复出厂设置移除。

三、Android版本适配注意事项

  • Android 10:禁用组件后必须发送ACTION_PACKAGE_CHANGED广播,否则部分原生Launcher仍会显示缓存图标。
  • Android 11/12:需声明android.permission.QUERY_ALL_PACKAGES权限(Android 11)或android.permission.GET_ALL_PACKAGES权限(Android 12),确保Launcher能正确感知组件状态变化;组件启用状态的修改必须在主线程执行。

内容的提问来源于stack exchange,提问作者dsx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:05:25