常用的一些電商應(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:icon 和 label 屬性:類似 <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浪起來