溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android動(dòng)態(tài)修改應(yīng)用圖標(biāo)與名稱的方法實(shí)例

發(fā)布時(shí)間:2020-09-23 00:49:18 來(lái)源:腳本之家 閱讀:450 作者:Wepon 欄目:移動(dòng)開發(fā)

遇到的坑

這里我把做這個(gè)功能中遇到的一些問(wèn)題寫在前面,是為了大家能先了解有什么問(wèn)題存在,遇到這些問(wèn)題的時(shí)候就不慌了,這里我把應(yīng)用圖標(biāo)和名稱先統(tǒng)一使用icon代替進(jìn)行說(shuō)明。

1、動(dòng)態(tài)替換icon,只能替換內(nèi)置的icon,無(wú)法從服務(wù)器端獲取來(lái)更新icon;

2、動(dòng)態(tài)替換icon以后,應(yīng)用內(nèi)更新的時(shí)候必須要切換到原始icon),否則可能導(dǎo)致更新安裝失敗(AS上表現(xiàn)為adb運(yùn)行會(huì)失敗),或者升級(jí)后應(yīng)用圖標(biāo)出現(xiàn)多個(gè)甚至應(yīng)用圖標(biāo)都不顯示的情況(這些問(wèn)題都可以通過(guò)下面我推薦的開發(fā)規(guī)則解決掉,所以這是一個(gè)坑點(diǎn),不是肯定會(huì)發(fā)生的問(wèn)題,只不過(guò)大多數(shù)人會(huì)遇到。);

3、Android系統(tǒng)動(dòng)態(tài)替換app icon會(huì)有延遲,在不同的手機(jī)系統(tǒng)上刷新icon的時(shí)間不一樣,大概在10秒左右,在這個(gè)時(shí)間內(nèi)點(diǎn)擊icon會(huì)提示應(yīng)用未安裝(提示可能會(huì)有差別,目前我的小米就不會(huì)提示任何信息,點(diǎn)了沒(méi)有反應(yīng));

4、更換icon的代碼運(yùn)行后一會(huì)應(yīng)用就閃退了,或者導(dǎo)致顯示中的Dialog和PopupWindow報(bào)錯(cuò)崩潰(這個(gè)問(wèn)題和第二個(gè)問(wèn)題有很大的相關(guān)性,按我下面給出的規(guī)則實(shí)行的話是可以解決的。

多入口配置

多入口配置,字面意思就是應(yīng)用程序的多個(gè)入口配置,在AndroidManifest.xml中有一個(gè)叫activity-alias的標(biāo)簽,這個(gè)標(biāo)簽從字面上看就能理解是activity別名的意思,這里我給出一個(gè)示例作下相應(yīng)的說(shuō)明。

activity-alias例子說(shuō)明:

  <activity-alias
   android:name="NewActivity1" // 注冊(cè)這個(gè)組件的名字,不需要生成文件
   android:enabled="false"  // 是否顯示這個(gè)啟動(dòng)項(xiàng)
   android:label="Alias1"  // 名稱,也就是對(duì)應(yīng)這個(gè)啟動(dòng)項(xiàng)顯示在桌面上的app名稱
   android:icon="@mipmap/ic_launcher_round" //圖標(biāo),也就是對(duì)應(yīng)這個(gè)啟動(dòng)項(xiàng)顯示在桌面上的app圖標(biāo) 
   android:targetActivity=".MainActivity"  //對(duì)應(yīng)的原來(lái)的Activity組件,這里路徑要跟注冊(cè)的Activity對(duì)應(yīng)。
   >
   <intent-filter> // LAUNCHER 啟動(dòng)入口
    <action android:name="android.intent.action.MAIN" />

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

顯示多個(gè)啟動(dòng)入口

然后這里我先做一個(gè)多個(gè)啟動(dòng)入口全部顯示的app示例,這里需要寫的代碼都在清單文件中,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.wepon.switchicondemo">

 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher_round"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  
  <!--原Activity-->
  <activity
   android:enabled="true"
   android:name=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

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

  <!--別名1-->
  <activity-alias
   android:name="NewActivity1"
   android:enabled="true"
   android:label="Alias1"
   android:icon="@mipmap/ic_launcher_round"
   android:targetActivity=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
  </activity-alias>
  
  <!--別名2-->
  <activity-alias
   android:name="NewActivity2"
   android:enabled="true"
   android:label="Alias2"
   android:icon="@mipmap/ic_launcher"
   android:targetActivity=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

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

 </application>

</manifest>

運(yùn)行后的效果如下:

Android動(dòng)態(tài)修改應(yīng)用圖標(biāo)與名稱的方法實(shí)例

可以看到桌面上顯示了三個(gè)圖標(biāo),進(jìn)入的都是MainActivity這個(gè)頁(yè)面,圖標(biāo)我用的自動(dòng)生成的,就懶的去找圖標(biāo)了,效果上能看出來(lái)就行。

當(dāng)然了,實(shí)際項(xiàng)目中我們只會(huì)顯示一個(gè)圖標(biāo),這里我們只需要把"別名1"和"別名2"的android:enabled="true"改為"false"就行了,這樣就只顯示一個(gè)圖標(biāo)了,就不放效果圖了。

代碼控制切換不同的應(yīng)用圖標(biāo)顯示

馬上春節(jié)了,我們產(chǎn)品說(shuō)到哪個(gè)時(shí)間點(diǎn)我們的應(yīng)用圖標(biāo)就要換成春節(jié)用的圖標(biāo)了,當(dāng)然,前面說(shuō)了這些圖標(biāo)要先在應(yīng)用寫好,不是通過(guò)服務(wù)器動(dòng)態(tài)拿的,而是應(yīng)用內(nèi)已經(jīng)寫好的。那這個(gè)時(shí)候我們就需要通過(guò)代碼進(jìn)行應(yīng)用圖標(biāo)的動(dòng)態(tài)切換了,這里我給出Demo里面布局如圖:

Android動(dòng)態(tài)修改應(yīng)用圖標(biāo)與名稱的方法實(shí)例

這里三個(gè)按鈕點(diǎn)擊后切換到相應(yīng)的應(yīng)用圖標(biāo)和名稱,"原ACTIVITY"代表只顯示MainActivity這個(gè)原來(lái)的啟動(dòng)入口,"ALIAS_1"代表別名1,以此類推。

這三個(gè)按鈕點(diǎn)擊對(duì)應(yīng)的代碼如下:

 /**
  * 設(shè)置Activity為啟動(dòng)入口
  * @param view
  */
 public void setActivity(View view) {
  PackageManager packageManager = getPackageManager();
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager
    .DONT_KILL_APP);
 }

 /**
  * 設(shè)置別名1為啟動(dòng)入口
  * @param view
  */
 public void setAlias1(View view) {
  PackageManager packageManager = getPackageManager();
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
      ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    PackageManager.DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);
 }
 /**
  * 設(shè)置別名2為啟動(dòng)入口
  * @param view
  */
 public void setAlias2(View view) {
  PackageManager packageManager = getPackageManager();
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
      ".NewActivity1"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    PackageManager.DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".NewActivity2"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager
    .DONT_KILL_APP);
  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);
 }

?。?!這里要注意一個(gè)點(diǎn),就是ComponentName里面的路徑一定要寫全了,如果在報(bào)錯(cuò)日志看到類似找不到這個(gè)路徑的日志的話,那十有八九就是這個(gè)問(wèn)題了。

切換的代碼其實(shí)很少,大家看了基本上也都明白了,這里就不做過(guò)多解釋了。這里我基于隱藏所以別名的情況下,也就是只顯示原來(lái)的一個(gè)APP圖標(biāo)的情況,點(diǎn)一下"ALIAS_1"這個(gè)按鈕,也就是將圖標(biāo)切換到"別名1",最終效果如下:

Android動(dòng)態(tài)修改應(yīng)用圖標(biāo)與名稱的方法實(shí)例

可以看到只顯示這一個(gè)入口了,但是如果大家在點(diǎn)了"ALIAS_1"之后,馬上就返回到主頁(yè)看盯著這個(gè)app的圖標(biāo),我們會(huì)發(fā)現(xiàn)在它在大概10s內(nèi)是沒(méi)有變化的,在大概10s后才更新成我們切換的那個(gè)圖標(biāo),還有,在它沒(méi)更新成功的時(shí)候如果我們點(diǎn)這個(gè)原來(lái)的圖標(biāo),一般會(huì)吐司一條“未安裝”之類的信息(華為是未安裝),這里我的小米是點(diǎn)了沒(méi)有反應(yīng),要等大概10s秒后更新成功了才能點(diǎn)這個(gè)圖標(biāo)進(jìn)入應(yīng)用。所以,通過(guò)代碼我們"已經(jīng)做到了"圖標(biāo)的切換,但是?。?!

那是不是這樣就完了呢??顯然不是的,問(wèn)題還挺多的,我一一道來(lái)。

不知道大家在點(diǎn)了切換的按鈕后有沒(méi)有一直停在app里面,沒(méi)有的話我們嘗試點(diǎn)完后在app里面不要回到桌面,如果停在app里面的話,我們會(huì)在大概10s,也就是更新成功的時(shí)候,應(yīng)用就會(huì)發(fā)生閃退了,也就是坑4這個(gè)問(wèn)題。這個(gè)問(wèn)題我做了很多測(cè)試,總結(jié)了一下原因和規(guī)避的方法,原因是我們?cè)诖a里面設(shè)置了我們?cè)瓉?lái)的真實(shí)的那個(gè)MainActiviy的enable為false,代碼如下:

  packageManager.setComponentEnabledSetting(new ComponentName(this, getPackageName() +
    ".MainActivity"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager
    .DONT_KILL_APP);

只要代碼設(shè)置了真實(shí)的那個(gè)Activity的enable為false,也就是代碼對(duì)應(yīng)的PackageManager.COMPONENT_ENABLED_STATE_DISABLED,那就會(huì)導(dǎo)致我們的應(yīng)用閃退,那是不是我們不設(shè)置這個(gè)就好了呢?那我們不設(shè)置這個(gè)的話怎么隱藏真實(shí)的MainActivity的圖標(biāo)呢?這個(gè)解決方法后面我會(huì)提出來(lái)。

但是,你以為只有這個(gè)問(wèn)題嗎?其實(shí)還有坑,只是這個(gè)坑不容易發(fā)現(xiàn),這個(gè)時(shí)候我們回到我們當(dāng)前的情況,也就是當(dāng)前我們已經(jīng)切換到"別名1"了,桌面上也只有這個(gè)圖標(biāo)了,我們也能點(diǎn)擊這個(gè)圖標(biāo)正常使用我們的應(yīng)用,這些都沒(méi)有問(wèn)題,我們以為都是正常的了。但是,這個(gè)時(shí)候,如果我們通過(guò)adb,使用Android Studio運(yùn)行項(xiàng)目的時(shí)候,會(huì)提示launch app失敗,失敗的信息如下:

01/10 16:48:54: Launching app
$ adb shell am start -n "com.wepon.switchicondemo/com.wepon.switchicondemo.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Error while executing: am start -n "com.wepon.switchicondemo/com.wepon.switchicondemo.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.wepon.switchicondemo/.MainActivity }
Error type 3
Error: Activity class {com.wepon.switchicondemo/com.wepon.switchicondemo.MainActivity} does not exist.

Error while Launching activity

同樣導(dǎo)致的問(wèn)題還有一個(gè),就是我們代碼動(dòng)態(tài)切換了app圖標(biāo)之后,應(yīng)用升級(jí),也就是更新應(yīng)用的時(shí)候,會(huì)導(dǎo)致安裝失敗,或者是安裝完成后出現(xiàn)多個(gè)圖標(biāo)甚至是沒(méi)有圖標(biāo)出現(xiàn)在桌面上了??!這些問(wèn)題是要遇到運(yùn)行,或者升級(jí)包的時(shí)候才會(huì)發(fā)現(xiàn)的,但是那時(shí)候發(fā)現(xiàn)就晚了,所以這是一個(gè)比較大的坑,這里對(duì)應(yīng)的坑就是我在前面提到的坑2這個(gè)點(diǎn)。

這里還有一種情況也會(huì)導(dǎo)致坑2的發(fā)生,例如,我們Demo現(xiàn)在是一個(gè)MainActivity和兩個(gè)別名,如果我們?cè)谙乱粋€(gè)版本把這兩個(gè)別名刪除了,或者刪除了我們當(dāng)前安裝包正在顯示的別名,那么安裝的新版本可能就不會(huì)有應(yīng)用圖標(biāo)顯示了,那就會(huì)導(dǎo)致我們應(yīng)用安裝成功了,但是卻沒(méi)有入口!

類似的問(wèn)題還有一些,主要都是在應(yīng)用升級(jí)后發(fā)生,而且不管是導(dǎo)致安裝失敗、安裝后沒(méi)有圖標(biāo)或者安裝后產(chǎn)生多個(gè)圖標(biāo),這些現(xiàn)象都是非常嚴(yán)重的,但是這些問(wèn)題我們都是可以避免的,這里我總結(jié)了一些規(guī)則,按這些規(guī)則進(jìn)行操作的話是不會(huì)產(chǎn)生以上這些問(wèn)題的,當(dāng)然,如果還有其他問(wèn)題的話歡迎交流,因?yàn)槲覀兊腶pp也在做這個(gè)功能。

動(dòng)態(tài)修改圖標(biāo)的開發(fā)規(guī)則,防坑專用

1、Activity的android:enabled屬性,一定不要在代碼里面去設(shè)置enabled這個(gè)值,否則會(huì)在切換圖標(biāo)的過(guò)程導(dǎo)致應(yīng)用閃退,目前測(cè)試了小米、華為和官方模擬器都有在這個(gè)問(wèn)題。

2、清單文件中設(shè)置Activity的android:enabled="false”,這個(gè)在之后的版本就固定這個(gè)值,如果設(shè)置為true了,則有可能在應(yīng)用升級(jí)后出現(xiàn)多個(gè)圖標(biāo);

3、然后為我們的應(yīng)用設(shè)置一個(gè)默認(rèn)的Activity-alias用來(lái)顯示圖標(biāo)(也是唯一一個(gè)顯示的,一般我們也只需要顯示一個(gè)圖標(biāo)),也是用來(lái)代替第一點(diǎn)設(shè)置Activity的android:enabled="false”可能導(dǎo)致的桌面上沒(méi)有應(yīng)用圖標(biāo)的問(wèn)題;

4、Activity-alias的android:enabled="true"的默認(rèn)顯示的項(xiàng)盡可能不要中途進(jìn)行變動(dòng),如果確實(shí)需要使用新的默認(rèn)值,則使用代碼進(jìn)行動(dòng)態(tài)變換;

5、Activity-alias的android:enabled="true"的不要設(shè)置為多個(gè),否則會(huì)出現(xiàn)多個(gè)圖標(biāo),如果試圖通過(guò)代碼進(jìn)行隱藏其中的一個(gè)或者幾個(gè),可能會(huì)出現(xiàn)圖標(biāo)消失的情況,這個(gè)第2點(diǎn)已經(jīng)有提過(guò)了;

6、后面新的版本如果要加新的Activity-alias,那么都要設(shè)置android:enabled=“false”,這個(gè)清單文件中的值要設(shè)置成false,然后再通過(guò)代碼動(dòng)態(tài)變換;

7、后面新的版本的Activity-alias必須包含上一個(gè)版本的所有Activity-alias,主要是防止覆蓋安裝后應(yīng)用圖標(biāo)消失的情況;
以上就是我在做這個(gè)功能的過(guò)程中總結(jié)出來(lái)的規(guī)則,目前沒(méi)有發(fā)現(xiàn)在其它的問(wèn)題,有別的問(wèn)題的朋友歡迎留言討論,還有,按照這些規(guī)則做的話,覆蓋安裝后的應(yīng)用圖標(biāo)也會(huì)是你上一次通過(guò)代碼動(dòng)態(tài)修改成功的圖標(biāo),因?yàn)槭謾C(jī)的Launcher會(huì)有記錄,也就是我們通過(guò)代碼會(huì)修改這個(gè)在Launcher中的記錄。

對(duì)了,我們?cè)谇鍐挝募信渲玫腁ctivity和Activity-alias的icon和label信息在新的版本中都是可以換的,這些跟代碼無(wú)關(guān)了,也就是跟我們平常換下app圖標(biāo)名稱是一樣的操作,希望大家不要誤解了這里 -_-!!!。

最后

最后,可能有的同學(xué)會(huì)想,我現(xiàn)在的應(yīng)用入口就是默認(rèn)的一個(gè)Activity,默認(rèn)的enable也是true,也沒(méi)有配置任何的Activity-alias,而我在上面說(shuō)的規(guī)則中都是建議清單文件中的Activity的android:enabled="false”,那有人可能就會(huì)想我的新版本設(shè)置成false會(huì)不會(huì)導(dǎo)致我的圖標(biāo)入口不見了呢?那么我告訴你,如果按照我上面說(shuō)的規(guī)則對(duì)你的新版本(可以動(dòng)態(tài)切換圖標(biāo)的版本)進(jìn)行設(shè)置的話,是不會(huì)有以上情況產(chǎn)生的,這里我給一個(gè)針對(duì)這種情況進(jìn)行升級(jí)的版本的清單文件的示例:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.wepon.switchicondemo">

 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher_round"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">

  <!--原Activity enabled固定為false,且不通過(guò)代碼進(jìn)行設(shè)置 -->
  <activity
   android:enabled="false"
   android:name=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

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

  <!-- 固定設(shè)置一個(gè)默認(rèn)的別名,用來(lái)替代原Activity-->
  <activity-alias
   android:name="DefaultAlias"
   android:enabled="true"
   android:label="@string/app_name"
   android:icon="@mipmap/ic_launcher_round"
   android:targetActivity=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

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

  <!--別名1 春節(jié),雙11,雙12,51,國(guó)慶等等,都可以給配置一個(gè)別名在清單文件,這里我只示例了一個(gè)。-->
  <activity-alias
   android:name="NewActivity1"
   android:enabled="false"
   android:label="Alias1"
   android:icon="@mipmap/ic_launcher"
   android:targetActivity=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

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

 </application>

</manifest>

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI