android 动态修改app icon

常用的一些电商应用每到节日时,应用的icon会换成相应节日的,今天研究一下这个技术点,之前还以为android 会有这方面的api ,可以在代码中动态设置,这样从服务端下载图片后,直接调用这个api不就可以了,但是目前没有找到这个方法。今天在网上看到有人用 <activity-alias> 来动态修改app icon成功的 。

<activity-alias> 介绍

对于 Activity 组件,使用时需要在 Manifest 文件中通过 标签注册 name、theme、intent-filter 等相关属性信息,然后通过 Intent 操作便可以启动对应 Activity。殊不知,我们还能通过 <activity-alias>
标签为每个 Activity 注册一个“别名”,通过这个别名也能启动对应的目标 Activity。我们来看一下这个“别名”能够设置哪些属性:

<activity-alias 
        android:enabled=["true" | "false"] 
        android:exported=["true" | "false"] 
        android:icon="drawable resource" 
        android:label="string resource" 
        android:name="string" 
        android:permission="string" 
        android:targetActivity="string" >
 . . .
</activity-alias>

以下是这些属性的解释

  • android:enabled 属性,布尔类型,是否开启别名设置,默认值为 true;
  • android:exported 属性,布尔类型,是否支持其他应用通过这个别名访问目标 Activity,默认值为 true;
  • android:iconlabel 属性:类似 <activity>标签,表示目标 Activity 的显示图标和标签;
  • android:name 属性:Activity 别名,在 <activity>标签中, name 属性必须与对应 Activity 文件的名字保持一致,而这里的别名可任意设置,保证唯一性即可;
  • android:permission 属性:权限设置,对别名的使用加以限制,详细属性值参考开发者官网对 权限部分 的说明;
  • android:targetActivity 属性:指定别名能够启动的目标 Activity,注意,属性值一定要对应到 <activity>标签中的 name 属性,并且该 <activity>标签一定要位于 <activity-alias>标签前面;

实现过程

了解完 <activity-alias>
的基本知识之后,就知道动态修改桌面图标和应用名称是怎么做到的了。其实就是给整个应用的入口 Activity 添加一个 <activity-alias>
标签,并设置预先设计好的替代桌面图标和应用名称,并配置相同的 <intent-filter>
属性,动态启动即可。

在menifest.xml添加多个activity-alias、删除主Activity标签
<category android:name="android.intent.category.LAUNCHER" />属性

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <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=".icon_tag"
            android:enabled="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            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=".icon_tag_1212"
            android:enabled="false"
            android:icon="@mipmap/ic_logo2"
            android:label="活动图标"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>

注意看,在别名设置中添加了 <intent-filter>标签,与 targetActivity 的设置一致

  • android.intent.action.MAIN表示这个别名设置是整个应用的入口,应用启动时第一个创建的就是这个 Activity;

  • android.intent.category.LAUNCHER : 表示这个别名设置将出现在桌面 Launcher 应用上;

至于其他属性,<activity>标签中也有相应设置,只是通常我们在 <application>标签中统一设置而已,然后<activity>标签默认继承<application>标签中的设置。上述代码还有一点需要注意的是,android:enabled属性设为 false,否则运行时将会在桌面上出现两个相同功能但不同显示的应用图标和名称。

然后在 Activity 中动态切换,通过 PackageManager 对象提的 setComponentEnabledSetting()

 private void switchIcon(int useCode) {
        try {
            //要跟manifest的activity-alias 的name保持一致
            String icon_tag = "demo.com.demo0104.icon_tag";
            String icon_tag_1212 = "demo.com.demo0104.icon_tag_1212";

            if (useCode != 3) {
                PackageManager pm = getPackageManager();
                ComponentName normalComponentName = new ComponentName(getBaseContext(), icon_tag);
                //正常图标新状态
                int normalNewState = useCode == 2 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
                if (pm.getComponentEnabledSetting(normalComponentName) != normalNewState) {//新状态跟当前状态不一样才执行
                    pm.setComponentEnabledSetting(
                            normalComponentName,
                            normalNewState,
                            PackageManager.DONT_KILL_APP);
                }

                ComponentName actComponentName = new ComponentName(getBaseContext(), icon_tag_1212);
                //正常图标新状态
                int actNewState = useCode == 1 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
                if (pm.getComponentEnabledSetting(actComponentName) != actNewState) {//新状态跟当前状态不一样才执行
                    pm.setComponentEnabledSetting(
                            actComponentName,
                            actNewState,
                            PackageManager.DONT_KILL_APP);
                }
            }
        } catch (Exception e) {
        }
    }

这个只是一个测试demo ,实际中肯定是调用服务端接口来判断是否需要修改app icon 。这样修改后 ,过一会桌面上的icon才会改变, 如果想立即改变需要使用intent重启luncher。

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        List<ResolveInfo> resolves = mPm.queryIntentActivities(intent, 0);
        for (ResolveInfo res : resolves) {
            if (res.activityInfo != null) {
                ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
                am.killBackgroundProcesses(res.activityInfo.packageName);
            }
        }

这个操作需要添加相应的权限

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

遗留问题


1、这种方式只能修改luncher上的icon和名称,属于应用级别 ,但是在系统设置—— 应用管理 查看,还是以前的icon。

参考文档

Android 利用 <activity-alias> 动态改变 App 桌面图标
动态更换应用Icon
Android动态修改icon--让你的app浪起来

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,475评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,357评论 0 17
  • 我期待着春季, 是风拂动柳枝的轻语, 我遥看远处忽来朦胧细雨, 点点滴滴似故梦里的相遇。 我喜着晴天的心气, 看着...
    素絢阅读 167评论 8 8
  • 昨天晚上跟组长一起去聚餐,晚上10点多才回来,之后睡觉都很晚了,所以今天早上没有6点起来。没有读书好不习惯,只能挤...
    歌呗lrf阅读 130评论 0 0
  • 本文为 Coursera 课程 如何学习:学习困难科目的实用思维方法课程 第一周学习笔记 专注模式和发散模式 人类...
    要上班的斌哥阅读 1,064评论 0 3