上次发版我就改了一行代码!

作者: eclipse_xu | 来源:发表于2016-12-22 09:55 被阅读2989次

动态更换应用Icon

产品:我们可以动态更换App在Launcher里面的Icon吗
开发:不可以
产品:我们可以动态更换App在Launcher里面的Icon吗
开发:不可以
产品:我们可以动态更换App在Launcher里面的Icon吗
开发:不可以
产品:我们可以动态更换App在Launcher里面的Icon吗
开发:让我想想……

原理1——activity-alias

在AndroidMainifest中,有两个属性:

// 决定应用程序最先启动的Activity
android.intent.action.MAIN 
// 决定应用程序是否显示在程序列表里
android.intent.category.LAUNCHER 

另外,还有一个activity-alias属性,这个属性可以用于创建多个不同的入口,相信做过系统Setting和Launcher开发的开发者在系统的源码中应该见过很多。

原理2——PM.setComponentEnabledSetting

PackageManager是一个大统领类,可以管理所有的系统组件,当然,如果Root了,你还可以管理其它App的所有组件,一些系统优化工具就是通过这个方式来禁用一些后台Service的。

使用方式异常简单:

private void enableComponent(ComponentName componentName) {
    mPm.setComponentEnabledSetting(componentName,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
}

private void disableComponent(ComponentName componentName) {
    mPm.setComponentEnabledSetting(componentName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);
}

根据PackageManager.COMPONENT_ENABLED_STATE_ENABLED和PackageManager.COMPONENT_ENABLED_STATE_DISABLED这两个标志量和对应的ComponentName,就可以控制一个组件的是否启用。

动态换Icon

有了上面的两个原理,来实现动态更换Icon就只剩下思路问题了。

首先,我们创建一个Activity,作为默认的入口并带着默认的图片,再创建一个双11的activity-alias,指向默认的Activity并带有双11的图片,再创建一个双12的activity-alias,指向默认的Activity并带有双12的图片……等等等。

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

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

<activity-alias
    android:name=".Test11"
    android:enabled="false"
    android:icon="@drawable/s11"
    android:label="双11"
    android:targetActivity=".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=".Test12"
    android:enabled="false"
    android:icon="@drawable/s12"
    android:label="双12"
    android:targetActivity=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

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

等等,这样有个问题,那就是这样会在Launcher上显示3个入口,所以,默认我们会把这些activity-alias先禁用,等到要用的时候再启用,养兵千日,用兵一时。

public class MainActivity extends AppCompatActivity {

    private ComponentName mDefault;
    private ComponentName mDouble11;
    private ComponentName mDouble12;
    private PackageManager mPm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDefault = getComponentName();
        mDouble11 = new ComponentName(
                getBaseContext(),
                "com.xys.changeicon.Test11");
        mDouble12 = new ComponentName(
                getBaseContext(),
                "com.xys.changeicon.Test12");
        mPm = getApplicationContext().getPackageManager();
    }

    public void changeIcon11(View view) {
        disableComponent(mDefault);
        disableComponent(mDouble12);
        enableComponent(mDouble11);
    }

    public void changeIcon12(View view) {
        disableComponent(mDefault);
        disableComponent(mDouble11);
        enableComponent(mDouble12);
    }

    private void enableComponent(ComponentName componentName) {
        mPm.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    private void disableComponent(ComponentName componentName) {
        mPm.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }
}

OK了,禁用默认的Activity后,启用双11的activity-alias,结果不变还是指向了默认的Activity,但图标已经发生了改变。

根据ROM的不同,在禁用了组件之后,会等一会,Launcher会自动刷新图标。

效果参考下图。

2.gif

相关文章

网友评论

  • 653d1ebd6d6d:http://stackoverflow.com/questions/1103027/how-to-change-an-application-icon-programmatically-in-android

    这个链接里提到了两种方法,一种是使用shortcut,一种是作者的方法
  • don94:厉害了,
  • Jafir:效果是杠杠的。

    但是遇到2个问题:
    1、如果所有的component都disable了,那么相当于应用程序不在launcher里面,也不可以打开main 的activity了,这样的话,如果安装或者更新升级的话,好像装不上哦?
    2、如果现在enable的是其他component,如果重新安装或者更新升级,好像也装不上。

    错误log:
    Error while executing: am start -n "com.jafir.mybookexplore/com.jafir.mybookexplore.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
    Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.jafir.mybookexplore/.MainActivity }
    Error type 3
    Error: Activity class {com.jafir.mybookexplore/com.jafir.mybookexplore.MainActivity} does not exist.
    8f874dd2ffbd:解决了,该图标后没有消失,图标换地方了,不在原来位置显示,半天没找到,后来无意中看到了。
    8f874dd2ffbd:怎么弄的,我试了还是一直报错,点击双11后图标消失了,只能用AS启动,就报你这种错。
    Jafir:@Jafir 我错了,后面我又重新试了一下, 之前那个错误代码是在IDE中重新更新安装。如果是直接使用安装包安装那么可以安装更新 component还是之前切换之后的
  • 妙法莲花1234:碉堡,思路厉害了
  • 福大大:不错,正需要!!
  • Jepack:不错,感谢分享
  • caeabb7052a6:赶紧去试一下效果咋样
  • sendtion:感谢分享
  • 乔伯:进程被杀后也会生效吗?
  • hfk:前阵子还在想要怎么实现,医生,厉害
  • 叮宕:这个问题的由来是因为我们没法获得一个icon对象。
  • 山言两语:学习了。
  • stevenMvp:微信公众号可以添加桌面入口和这个原理一致吗?
  • stevenMvp:666,很棒!

本文标题:上次发版我就改了一行代码!

本文链接:https://www.haomeiwen.com/subject/mmqcvttx.html