Android如何動態更換桌面圖示(巨坑)
1、Android如何動態更換桌面圖示
1.1使用場景
APP,在中國電商行業中,某寶和某東是行業的標杆。其中有一點挺讓人好奇的,那就是在雙十一臨近之時,他們的APP桌面圖示突然變成了帶有雙十一字樣的圖示。可能就是本來就內建了雙十一的圖示,等快到雙十一的時候在動態更換,然後過了雙十一那段時間,又將APP的桌面圖示變成普通的icon。
1.2知識點
動態更換APP 桌面icon的引述;
activity元件及定義“同盟”元件activity-alias;
PackageManager類進行啟用/禁用元件;
PackageInfo的簡介;
新名詞記錄{PackageInfo:Androidmanifest.xml檔案描述類}
1.3使用Activity-alias
<activity android:name="com.aliasicon.MainActivity" android:enabled="false" android:exported="true" > <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity-alias android:name="com.zztzt.android.simple.activity.tztCommHeadPageGenearlActivity" android:configChanges="orientation|keyboardHidden|fontScale|screenSize" android:enabled="true" android:exported="true" android:icon="@drawable/tzt_icon" android:label="@string/app_general_name" android:screenOrientation="portrait" 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="com.zztzt.android.simple.activity.tztCommHeadPageLicaiActivity" android:configChanges="orientation|keyboardHidden|fontScale|screenSize" android:enabled="false" android:exported="true" android:icon="@drawable/tzt_icon_licai" android:label="@string/app_licai_name" android:screenOrientation="portrait" android:targetActivity=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity-alias>
String systemPath = "com.aliasicon.MainActivity"; String springPath = "com.zztzt.android.simple.activity.tztCommHeadPageAliasActivity"; String licaiPath = "com.zztzt.android.simple.activity.tztCommHeadPageLicaiActivity"; String genearlPath = "com.zztzt.android.simple.activity.tztCommHeadPageGenearlActivity"; String finalPath = ""; ComponentName genearlComponent; ComponentName licaiComponent; ComponentName springComponent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); genearlComponent = new ComponentName(getApplication(), genearlPath); licaiComponent = new ComponentName(getApplication(), licaiPath); springComponent = new ComponentName(getApplication(), springPath); //第一個預設按鈕 Button btnDefault = (Button) findViewById(R.id.tztToDefault); btnDefault.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { disableComponent(MainActivity.this, licaiComponent); disableComponent(MainActivity.this, springComponent); enableComponent(MainActivity.this, genearlComponent); } }); //理財按鈕 Button btnLiCai = (Button) findViewById(R.id.tztToLiCai); btnLiCai.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { disableComponent(MainActivity.this, genearlComponent); disableComponent(MainActivity.this, springComponent); enableComponent(MainActivity.this, licaiComponent); } }); //春節按鈕 Button btnSpring = (Button) findViewById(R.id.tztToSpring); btnSpring.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { disableComponent(MainActivity.this, genearlComponent); disableComponent(MainActivity.this, licaiComponent); enableComponent(MainActivity.this, springComponent); } }); } /** * 啟用元件 * * @param componentName * 重要方法 */ private void enableComponent(Activity activity, ComponentName componentName) { PackageManager pm = activity.getPackageManager(); int state = pm.getComponentEnabledSetting(componentName); if (PackageManager.COMPONENT_ENABLED_STATE_ENABLED == state) { //已經啟用 return; } pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } /** * 禁用元件 * * @param componentName * 重要方法 */ private void disableComponent(Activity activity, ComponentName componentName) { PackageManager pm = activity.getPackageManager(); int state = pm.getComponentEnabledSetting(componentName); if (PackageManager.COMPONENT_ENABLED_STATE_DISABLED == state) { //已經禁用 return; } pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } public void saveData(String savePath) { SharedPreferences sp = getSharedPreferences("Icon", Context.MODE_PRIVATE); //獲取到edit物件 SharedPreferences.Editor edit = sp.edit(); //通過editor物件寫入資料 edit.putString("Value", savePath); //提交資料存入到xml檔案中 edit.commit(); } public String getData() { SharedPreferences sp = getSharedPreferences("Icon", Context.MODE_PRIVATE); return sp.getString("Value", ""); }
2、巨坑
通過上面的程式能夠實現卻換圖示;如果程式碼裡通過節假日的時間進行控制,則客戶開啟app會自動的切換圖示;
是不是很神奇?先別高興太早。
2.1App的覆蓋
任何App都會更新,進行覆蓋安裝。覆蓋安裝的Manifest的配置不當導致出現難以挽回的問題。
1、從上面的xml裡配置可見,一個Activity和兩個Activity-alisa的配置情況:
Activity的android:enabled="false"
第一個Activity-alias的android:enabled="true"
第二個Activity-alias的android:enabled="false"
所以App開啟,桌面上預設的就是使用第一個Activity-alias的名字和圖示。
2、如果新版本的配置還是按照這個配置(即使添加了新的alias,只要預設的Activity-alias不發生變化)客戶端額升級覆蓋安裝,是不會出現錯誤的。
3、我們稱之為“方案一”
2.2桌面上出現兩個圖示的問題
1、如果新版本把Activity的enable設定為true(方案二),則桌面上除了原來的Activity-alias圖示之外,還擁有了該Activity的圖示,即有了兩個圖示;
Activity的android:enabled="true"
第一個Activity-alias的android:enabled="false"
第二個Activity-alias的android:enabled="false"
3、如果試圖使用使用上面的程式碼裡的disableComponent方法或者android:enabled="false"隱藏顯示的Activity-alias圖示,則導致兩個圖示都消失;
2.3桌面上圖示消失的問題
1、方案二會出現兩個圖示,如果再使用方案一進行覆蓋,則兩個圖示都消失。
2、如果再次使用方案二進行覆蓋,則圖示還是能重新顯示出來的。
2.4總結
1、如果使用方案一進行覆蓋安裝,不管圖示怎麼動態的變換,再使用方案一進行覆蓋安裝,是正常的;
2、如果使用方案二進行覆蓋安裝,不管配置的圖示是什麼樣的,再使用方案二進行覆蓋安裝,也是正常的;
3、如果使用方案一進行覆蓋安裝,如果圖示沒有動態切換的情況下,再使用方案二進行覆蓋安裝,也是正常的;
4、如果使用方案一進行覆蓋安裝,如果圖示已經經過動態切換的情況下,再使用方案二進行覆蓋安裝,會出現雙圖示的;
5、如果使用方案一進行覆蓋安裝,如果圖示已經經過動態切換的情況下,再使用方案二進行覆蓋安裝,會出現雙圖示的;如果在進行使用程式碼試圖隱藏其中一個,則兩個圖示都消失;
6、如果使用方案一進行覆蓋安裝,如果圖示沒有動態切換的情況下,再使用方案二進行覆蓋安裝,也是正常的,再使用方案一進行覆蓋安裝,也是正常的;
2.5最終方案(方案一)
採用方案一的方案,即通過程式碼動態變動圖示,一定要注意以下事項:
1、Activity的android:enabled="false"
如果設定為true了,則會出現雙圖示;
2、Activity-alias的android:enabled="true"的預設顯示的項不要中途進行變動,如果確實需要使用新的預設值,則使用程式碼進行動態變換;
3、Activity-alias的android:enabled="true"的不要設定為多個,否則會出現多個圖示,如果試圖通過程式碼進行隱藏其中的一個或者幾個,可能會出現圖示消失的情況。