android 動(dòng)態(tài)修改app icon

常用的一些電商應(yīng)用每到節(jié)日時(shí),應(yīng)用的icon會(huì)換成相應(yīng)節(jié)日的,今天研究一下這個(gè)技術(shù)點(diǎn),之前還以為android 會(huì)有這方面的api ,可以在代碼中動(dòng)態(tài)設(shè)置,這樣從服務(wù)端下載圖片后,直接調(diào)用這個(gè)api不就可以了,但是目前沒有找到這個(gè)方法。今天在網(wǎng)上看到有人用 <activity-alias> 來動(dòng)態(tài)修改app icon成功的 。

<activity-alias> 介紹

對(duì)于 Activity 組件,使用時(shí)需要在 Manifest 文件中通過 標(biāo)簽注冊(cè) name、theme、intent-filter 等相關(guān)屬性信息,然后通過 Intent 操作便可以啟動(dòng)對(duì)應(yīng) Activity。殊不知,我們還能通過 <activity-alias>
標(biāo)簽為每個(gè) Activity 注冊(cè)一個(gè)“別名”,通過這個(gè)別名也能啟動(dòng)對(duì)應(yīng)的目標(biāo) Activity。我們來看一下這個(gè)“別名”能夠設(shè)置哪些屬性:

<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 屬性,布爾類型,是否開啟別名設(shè)置,默認(rèn)值為 true;
  • android:exported 屬性,布爾類型,是否支持其他應(yīng)用通過這個(gè)別名訪問目標(biāo) Activity,默認(rèn)值為 true;
  • android:iconlabel 屬性:類似 <activity>標(biāo)簽,表示目標(biāo) Activity 的顯示圖標(biāo)和標(biāo)簽;
  • android:name 屬性:Activity 別名,在 <activity>標(biāo)簽中, name 屬性必須與對(duì)應(yīng) Activity 文件的名字保持一致,而這里的別名可任意設(shè)置,保證唯一性即可;
  • android:permission 屬性:權(quán)限設(shè)置,對(duì)別名的使用加以限制,詳細(xì)屬性值參考開發(fā)者官網(wǎng)對(duì) 權(quán)限部分 的說明;
  • android:targetActivity 屬性:指定別名能夠啟動(dòng)的目標(biāo) Activity,注意,屬性值一定要對(duì)應(yīng)到 <activity>標(biāo)簽中的 name 屬性,并且該 <activity>標(biāo)簽一定要位于 <activity-alias>標(biāo)簽前面;

實(shí)現(xiàn)過程

了解完 <activity-alias>
的基本知識(shí)之后,就知道動(dòng)態(tài)修改桌面圖標(biāo)和應(yīng)用名稱是怎么做到的了。其實(shí)就是給整個(gè)應(yīng)用的入口 Activity 添加一個(gè) <activity-alias>
標(biāo)簽,并設(shè)置預(yù)先設(shè)計(jì)好的替代桌面圖標(biāo)和應(yīng)用名稱,并配置相同的 <intent-filter>
屬性,動(dòng)態(tài)啟動(dòng)即可。

在menifest.xml添加多個(gè)activity-alias、刪除主Activity標(biāo)簽
<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="活動(dòng)圖標(biāo)"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>

注意看,在別名設(shè)置中添加了 <intent-filter>標(biāo)簽,與 targetActivity 的設(shè)置一致

  • android.intent.action.MAIN表示這個(gè)別名設(shè)置是整個(gè)應(yīng)用的入口,應(yīng)用啟動(dòng)時(shí)第一個(gè)創(chuàng)建的就是這個(gè) Activity;

  • android.intent.category.LAUNCHER : 表示這個(gè)別名設(shè)置將出現(xiàn)在桌面 Launcher 應(yīng)用上;

至于其他屬性,<activity>標(biāo)簽中也有相應(yīng)設(shè)置,只是通常我們?cè)?<application>標(biāo)簽中統(tǒng)一設(shè)置而已,然后<activity>標(biāo)簽?zāi)J(rèn)繼承<application>標(biāo)簽中的設(shè)置。上述代碼還有一點(diǎn)需要注意的是,android:enabled屬性設(shè)為 false,否則運(yùn)行時(shí)將會(huì)在桌面上出現(xiàn)兩個(gè)相同功能但不同顯示的應(yīng)用圖標(biāo)和名稱。

然后在 Activity 中動(dòng)態(tài)切換,通過 PackageManager 對(duì)象提的 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);
                //正常圖標(biāo)新狀態(tài)
                int normalNewState = useCode == 2 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
                if (pm.getComponentEnabledSetting(normalComponentName) != normalNewState) {//新狀態(tài)跟當(dāng)前狀態(tài)不一樣才執(zhí)行
                    pm.setComponentEnabledSetting(
                            normalComponentName,
                            normalNewState,
                            PackageManager.DONT_KILL_APP);
                }

                ComponentName actComponentName = new ComponentName(getBaseContext(), icon_tag_1212);
                //正常圖標(biāo)新狀態(tài)
                int actNewState = useCode == 1 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
                if (pm.getComponentEnabledSetting(actComponentName) != actNewState) {//新狀態(tài)跟當(dāng)前狀態(tài)不一樣才執(zhí)行
                    pm.setComponentEnabledSetting(
                            actComponentName,
                            actNewState,
                            PackageManager.DONT_KILL_APP);
                }
            }
        } catch (Exception e) {
        }
    }

這個(gè)只是一個(gè)測(cè)試demo ,實(shí)際中肯定是調(diào)用服務(wù)端接口來判斷是否需要修改app icon 。這樣修改后 ,過一會(huì)桌面上的icon才會(huì)改變, 如果想立即改變需要使用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);
            }
        }

這個(gè)操作需要添加相應(yīng)的權(quán)限

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

遺留問題


1、這種方式只能修改luncher上的icon和名稱,屬于應(yīng)用級(jí)別 ,但是在系統(tǒng)設(shè)置—— 應(yīng)用管理 查看,還是以前的icon。

參考文檔

Android 利用 <activity-alias> 動(dòng)態(tài)改變 App 桌面圖標(biāo)
動(dòng)態(tài)更換應(yīng)用Icon
Android動(dòng)態(tài)修改icon--讓你的app浪起來

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,287評(píng)論 25 708
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 6,523評(píng)論 0 17
  • 我期待著春季, 是風(fēng)拂動(dòng)柳枝的輕語, 我遙看遠(yuǎn)處忽來朦朧細(xì)雨, 點(diǎn)點(diǎn)滴滴似故夢(mèng)里的相遇。 我喜著晴天的心氣, 看著...
    素絢閱讀 184評(píng)論 8 8
  • 昨天晚上跟組長(zhǎng)一起去聚餐,晚上10點(diǎn)多才回來,之后睡覺都很晚了,所以今天早上沒有6點(diǎn)起來。沒有讀書好不習(xí)慣,只能擠...
    歌唄lrf閱讀 149評(píng)論 0 0
  • 本文為 Coursera 課程 如何學(xué)習(xí):學(xué)習(xí)困難科目的實(shí)用思維方法課程 第一周學(xué)習(xí)筆記 專注模式和發(fā)散模式 人類...
    要上班的斌哥閱讀 1,099評(píng)論 0 3