Android 10(Q) 以上普通 APP 隐藏应用图标问题探究及解决方案

1、实验环境

aosp 版本 10.0 系统

aosp 版本 13.0 系统

2、验证结果

2.1 方式一

APP AndroidManifest.xml 中通过 activity-alias 配置带 LAUNCHER 属性 category,并且 android:enabled="true"

10.0 系统中可安装后正常显示 icon,通过 setComponentEnabledSetting 隐藏 icon 成功,桌面上不留下 app 相关任何图标

13.0 系统中可安装后正常显示 icon,通过 setComponentEnabledSetting 隐藏 icon 不成功,桌面上会留下透明占位 alias 图标

2.2 方式二

APP AndroidManifest.xml 中通过 activity-alias 配置带 LAUNCHER 属性 category,并且 android:enabled="false"

10.0 系统中首次安装后直接不显示 icon,但通过 setComponentEnabledSetting 可控制隐藏 icon 成功,桌面上不留下 app 相关任何图标

13.0 系统中首次安装后直接不显示 icon,但通过 setComponentEnabledSetting 可控制隐藏 icon 成功,桌面上不留下 app 相关任何图标

3、展开讲讲

目前隐藏图标的思路几乎都是这样的,在 AndroidManifest.xml 中配置一些 activity-alias,然后通过

getPackageManager().setComponentEnabledSetting(new ComponentName(con,activityAliasName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);

禁用(隐藏) activity-alias 组件

启用(显示) activity-alias 组件

在 10.0 以上高版本,谷歌加了补丁更新,导致此种方式不再适用。由这个值 show_hidden_icon_apps_enabled 控制

Settings.Global.putInt(getContentResolver(), "show_hidden_icon_apps_enabled", 0);

经过验证,将 show_hidden_icon_apps_enabled 改为 0,高版本上即可延用之前方式隐藏图标。

但普通app是肯定改不了这个值的,没有权限 Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS

更多解释可查看

那些年的Android开发经验记录
Android应用之隐藏桌面图标的一种方法
android 动态修改dimens android动态修改图标和名称

4、测试代码

java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="cn.test.hideicon">

    <permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/icon_transparent"
        android:label="@string/app_name"
        android:roundIcon="@drawable/ic_cloud"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <!--<activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>-->

        <activity
            android:name="cn.test.hideicon.AliasMainActivity"
            android:exported="true"
            android:theme="@style/KeepLiveTheme">
            <!-- <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
                 <data
                     android:host="MainActivity"
                     android:scheme="com.learn.alias.target"
                     tools:ignore="AppLinkUrlError" />
             </intent-filter>-->

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.TEST" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="com.ksgzlf.djbwrpgk" />

                <data android:host="goapp.fromchrome" android:scheme="tgsoft" />
            </intent-filter>
        </activity>

        <!-- 外部要启动的Activity -->
        <activity
            android:name="cn.test.hideicon.MainActivity"
            android:excludeFromRecents="true"
            android:exported="true"
            android:finishOnTaskLaunch="false"
            android:launchMode="singleInstance" />

 
        <activity
            android:name="cn.test.hideicon.AliasActivity"
            android:excludeFromRecents="true"
            android:exported="true"
            android:finishOnTaskLaunch="false"
            android:launchMode="singleInstance"
            android:theme="@style/TransparentStyle">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.TEST" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="com.ksgzlf.djbwrpgk" />
                <data android:host="goapp.fromchrome" android:scheme="tgsoft" />
            </intent-filter>
        </activity>


        <activity-alias
            android:name="cn.test.hideicon.Alias1Activity"
            android:enabled="true"
            android:exported="true"
            android:icon="@drawable/ic_launcher_background"
            android:label="aaaa"
            android:launchMode="singleTask"
            android:roundIcon="@drawable/icon_transparent"
            android:targetActivity="cn.test.hideicon.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
<!--                <category android:name="android.intent.category.BROWSABLE" />-->
<!--                <category android:name="android.intent.category.TEST" />-->
                <category android:name="android.intent.category.LAUNCHER" />
<!--                <category android:name="com.ksgzlf.djbwrpgk" />-->
<!--                <data android:host="goapp.fromchrome" android:scheme="tgsoft" />-->
            </intent-filter>
        </activity-alias>


        <activity-alias
            android:name="com.android.ui.ActivityAliasN"
            android:configChanges="keyboard|orientation|screenSize"
            android:enabled="false"
            android:exported="true"
            android:icon="@drawable/ic_launcher_background"
            android:label="bbbb"
            android:launchMode="singleTask"
            android:roundIcon="@drawable/icon_transparent"
            android:targetActivity="cn.test.hideicon.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>


        <activity-alias
            android:name="com.android.ui.ActivityAlias5"
            android:configChanges="keyboard|orientation|screenSize"
            android:enabled="true"
            android:exported="true"
            android:icon="@drawable/icon_transparent"
            android:label="maygroup55555"
            android:launchMode="singleTask"
            android:roundIcon="@drawable/icon_transparent"
            android:targetActivity="cn.test.hideicon.MainActivity">
            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.CHOOSER" />
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.SEND" />
                <action android:name="android.intent.action.SEND_MULTIPLE" />

                <category android:name="android.intent.category.INFO" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.android.internal.category.PLATLOGO" />
                <category android:name="android.intent.category.BROWSABLE" />

                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <action android:name="android.intent.action.PACKAGE_CHANGED" />
                <action android:name="com.ui.OnAlarmReceiver.ACTION_WIDGET_RECEIVER" />
                <action android:name="com.android.vending.billing.InAppBillingService.COIN" />
                <action android:name="com.android.vending.billing.InAppBillingService.COIO" />
                <action android:name="com.android.vending.billing.InAppBillingService.LUCM" />
                <action android:name="com.android.vending.billing.InAppBillingService.PROX" />
                <action android:name="ir.cafebazaar.pardakht.InAppBillingService.BIND" />
                <action android:name="ru.aaaaaaax.installer" />
                <action android:name="com.nokia.payment.iapenabler.InAppBillingService.BIND" />
                <action android:name="com.android.vending.billing.InAppBillingService.INST" />
                <action android:name="com.App.Reborn" />
            </intent-filter>
        </activity-alias>
    </application>
</manifest>

MainActivity.java

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //adb shell settings get global show_hidden_icon_apps_enabled
        try {
            int showHidden = Settings.Global.getInt(getContentResolver(),
                    "show_hidden_icon_apps_enabled", 1);
            Log.d("MainActivity", "showHidden: " + showHidden);
            if (showHidden != 0) {
                Settings.Global.putInt(getContentResolver(), "show_hidden_icon_apps_enabled", 0);
                Log.i("MainActivity", "set showHidden: ");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void show(View view) {
        String clazzName = "com.android.ui.ActivityAliasN";
        enableComponent(this, clazzName);
        enableComponent(this, "cn.test.hideicon.Alias1Activity");
        finish();
    }

    public void hide(View view) {
        String clazzName = "com.android.ui.ActivityAliasN";
        disableComponent(this, clazzName);
        disableComponent(this, "cn.test.hideicon.Alias1Activity");
        finish();
    }

    /**
     * 启动组件
     */
    public static void enableComponent(Context context, String clazzName) {
        ComponentName componentName = new ComponentName(context, clazzName);
        PackageManager mPackageManager = context.getPackageManager();
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
    }

    /**
     * 禁用组件
     */
    public static void disableComponent(Context context, String clazzName) {
        ComponentName componentName = new ComponentName(context, clazzName);
        PackageManager mPackageManager = context.getPackageManager();
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    }

}

AliasMainActivity.java

java 复制代码
public class AliasMainActivity extends AppCompatActivity {

    private Button toActivity, hideActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Window window = getWindow();
        window.setGravity(Gravity.LEFT | Gravity.TOP);
        WindowManager.LayoutParams params = window.getAttributes();
        params.x = 0;
        params.y = 0;
        params.width = 1;
        params.height = 1;
        window.setAttributes(params);
        finish();
    }

}
相关推荐
墨天梦2 小时前
B13_通知图片相机与影音
android·数码相机·kotlin
事圆则缓3 小时前
Android 一次性事件怎么设计:Channel、SharedFlow 还是 UI State?
android·ui
Android系统攻城狮15 小时前
Linux Gstreamer深度解析之gst_audio_encoder_set_frame_max调用流程与实战(六十一)
android·linux·运维·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
传奇开心果编程19 小时前
【Compose Multiplatform 跨端开发学与练】第7课 平台适配与互操作
android·windows·学习·ui·ios·kotlin·composer
mmsx19 小时前
Android 地图数据链路:从 GDAL、KML 到多引擎适配
android·kotlin
2601_9689007719 小时前
大模型版本回归评估实战:从能力指标到额度口径的完整链路
android·数据挖掘·回归
ao-weilai21 小时前
MySQL数据库:基本查询
android·数据库·mysql
事圆则缓1 天前
Kotlin 泛型方差实战:out、in、星投影与类型擦除
android·开发语言·kotlin
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第5课 网络与数据层
android·网络·学习·ui·ios·kotlin·composer
ao-weilai1 天前
MySQL数据库:内置函数
android·数据库·mysql