Android 之动态更换桌面图标

Android之动态更换桌面图标

文章链接:blog.csdn.net/qq_16628781…

知识点

  1. 动态更换APP 桌面icon的引述;
  2. activity组件及定义“同盟”组件activity-alias;
  3. PackageManager类进行启用/禁用组件;
  4. PackageInfo的简介;
  5. 新名词记录{PackageInfo:Androidmanifest.xml文件描述类}

概述

APP,在中国电商行业中,某宝和某东是行业的标杆。其中有一点挺让人好奇的,那就是在双十一临近之时,他们的APP桌面图标突然变成了带有双十一字样的图标。但是明明记得那段时间并没有更新过,那么唯一的可能就是本来就内置了双十一的图标,等快到双十一的时候在动态更换,然后过了双十一那段时间,又将APP的桌面图标变成普通的icon。

既然图标本来就在APP里头(或者是网络下载下来的,只是猜测,有知道的小伙伴可以给我留言),那么就很好奇了,它们的图标到底是怎么样进行动态的更换的呢?

探索1

对于Android来说,所有的activity都是一个组件,我们可以对每个组件进行管理。
关于程序的入口,我们知道android.intent.action.MAIN进行的指定的。


<activity  android:name=".HomeActivity" android:label="@string/app_name" android:theme="@style/AppThemeToolbar">
            <intent-filter>
                //指定应用程序最先启动的Activity
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

对于android.intent.category.LAUNCHER,这个又是设置什么的呢?这个是决定应用程序是否显示在程序列表里头。

另外,还有一个activity-alias属性,这个属性可以用于创建多个不同的入口。用法如下所示:

<activity  android:name=".HomeActivity" android:label="@string/app_name" android:theme="@style/AppThemeToolbar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--name:组件名字-->
        <!--enabled:该组件是否启动-->
        <!--icon:组件图标-->
        <!--label:组件标签说明-->
        <!--targetActivity:组件的类-->
        <activity-alias  android:name=".HomeActivity2" android:enabled="false" android:icon="@drawable/icon2" android:label="icon2" android:targetActivity=".HomeActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
        <activity-alias  android:name=".HomeActivity3" android:enabled="false" android:icon="@drawable/icon3" android:label="icon3" android:targetActivity=".HomeActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

如上面代码显示,这里有3个程序的入口,其中第二和第三个是被禁用掉的,如果enable缺省值,那么默认是true。既然可以XML中禁用,那么对应的也可以在代码中启动组件了。

探索2

APP的icon是对于整个包范围的,既然是要动用到APP包,那么是不是系统就给我们提供了一个管理整个包的类呢?事实上,系统给我们提供了PackageManager这个类,这个类能够获取到当前应用里不同类型的信息。定义了一系列比如的服务的字段常量,低功耗ble蓝牙,相机==,以及一系列有关包操作的抽象方法。此类可以管理所有的系统组件。

我们知道APP上每一个对象都是系统里的一个组件,那么我们可以在PackageManager类里面看到有关于组件的操作方法;

这个方法有以下比较重要的方法:

//设置特定组件是否可以启动方法
public abstract void setComponentEnabledSetting(ComponentName componentName,  int newState, int flags);
//相反,得到特定组件是否启动的方法
public abstract int getComponentEnabledSetting(ComponentName componentName);

参数1:组件的名称;

参数2:组件新的状态;

参数3:标志是否要killapp;

有了以上两个方法,我们就可以根据给定不同的组件名称+状态进行设置是否可用了。结合探索1里面定义的3个组件的启动和禁止情况,我们可以进行对应的enable操作。

结合使用

private PackageManager mPackageManager;
    //默认组件
    private ComponentName componentNameDefault;
    private ComponentName componentName2;
    private ComponentName componentName3;

    /** * 设置第icon2图标生效 */
    private void enableComponentName2() {
        disableComponent(componentNameDefault);
        disableComponent(componentName3);
        enableComponent(componentName2);
    }

    /** * 设置第icon3图标生效 */
    private void enableComponentName3() {
        disableComponent(componentNameDefault);
        disableComponent(componentName2);
        enableComponent(componentName3);
    }

    /** * 启动组件 * * @param componentName 组件名 */
    private void enableComponent(ComponentName componentName) {
        //此方法用以启用和禁用组件,会覆盖Androidmanifest文件下定义的属性
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    /** * 禁用组件 * * @param componentName 组件名 */
    private void disableComponent(ComponentName componentName) {
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }

    //最后调用
    public void pmTest() {
        //获取到包管理类实例
        mPackageManager = getPackageManager();
        //得到此activity的全限定名
        componentNameDefault = getComponentName();
        //根据全限定名创建一个组件,即activity-alias 节点下的name:HomeActivity2 对应的组件
        componentName2 = new ComponentName(getBaseContext(), "com.yaojt.HomeActivity2");
        componentName3 = new ComponentName(getBaseContext(), "com.yaojt.HomeActivity3");
        String action = getActionFromServer();//从后台获取到应该使用那一个组件,或者根据时间来判断
        if ("comp2".equals(action)){
            enableComponentName2();
        }else if ("comp3".equals(action)){
            enableComponentName3();
        }
        //如果没有,则显示默认图标
    }

通过以上的代码,可以清楚的看到,如何获取已经在XML文件里面定义好的组件。然后根据不同需求,来启用或者禁止对应的组件,从而达到更新APP桌面图标的功能。(可能需要一段时间刷新,才能看到新的APP桌面图标)

课外知识

PackageInfo:装载Androidmanifest.xml文件所有信息的类。

所有的信息都来自AndroidManifest.xml文件;例如,包名packageName、版本号versionCode、sharedUserId共享id、apk第一次和最后一次安装时间、声明的activity,service、receiver、provider和请求的权限等等的信息。

总结

以上就是其中一种动态桌面更换图标的方法,需要的是预先放入需要更换的icon进去,或许还可以支持动态的设置icon,但是这部分我还没有仔细的去研究。如果你知道,请留言告知我,大家共同学习进步。

如有任何问题,请及时与我联系。谢谢

    原文作者:Android
    原文地址: https://juejin.im/entry/58f9b2d8ac502e006396a3db
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞