Android利用activity-alias動態更新圖示icon,標題label
網上已經有很多的介紹“Android動態修改桌面圖示”的部落格,無非就是用activity-alias,setComponentEnabledSetting方法,但是他們的部落格都有一個問題(或許是我沒找到正確的),就是當你在切換圖示的時候,你的應用會被殺死,重啟一次。
就拿下面的這個程式碼引入本篇部落格吧:
ComponentName oldCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAlias");
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
通常來隱藏一個桌面icon,都會呼叫這個方法,但是呼叫這個方法就會出現一個如下所示的問題:
由官方文件的描述可知:
DONT_KILL_APP
added in API level 1
int DONT_KILL_APP
Flag parameter for setComponentEnabledSetting(android.content.ComponentName, int, int) to indicate that you don't want to kill the app containing the component. Be careful when you set this since changing component states can make the containing application's behavior unpredictable.
當你用DONT_KILL_APP,會發生一些不可預料的問題,尤其是當前的activity嘗試要要禁止自己。所以最好是,由一個activity禁止另個一activity。
由上可知,該app最好有一個跳轉介面,這樣關閉的就是那個跳轉介面了:
看下應用效果圖吧:
現在看程式碼,首先是AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="demo.lgx.com.multipleicondemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SplashActivity"></activity>
<activity android:name=".MainActivity">
</activity>
<activity-alias
android:name=".IconAlias"
android:enabled="true"
android:icon="@mipmap/ic_launcher_old"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".IconAliaNew"
android:enabled="false"
android:icon="@mipmap/ic_launcher_new"
android:label="@string/app_name_new"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
</application>
</manifest>
可以看到定義了兩個activity-alias,一個android:enabled=”true”,一個android:enabled=”false”,android:enabled=”true”的activity-alias將會預設顯示在桌面上,
其中android:targetActivity=”.SplashActivity”中的屬性,就是真正要顯示的activity
從這裡可以看到,我們的activity都是沒有 <action android:name="android.intent.action.MAIN"/>
和 <action android:name="android.intent.action.MAIN"/>
,這兩個屬性都放在activity-alias裡,這就是為了保證,在使用PackageManager.DONT_KILL_APP時,應用不會重啟啊。
SplashActivity程式碼很簡單,就是開啟一個執行緒,過3s後,啟動MainActivity,
SplashActivity中的程式碼如下所示:
package demo.lgx.com.multipleicondemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
/**
* Created by Harry on 2017/6/19.
*/
public class SplashActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Observable.timer(3, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
startActivity(new Intent(SplashActivity.this,MainActivity.class));
finish();
}
});
}
}
我這裡的子執行緒等待3s,再跳轉,用的是RxJava哈。
最後就是MainActivity的程式碼了,如下所示:
package demo.lgx.com.multipleicondemo;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void MyClick(View v) {
PackageManager pm = getPackageManager();
ComponentName oldCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAlias");
ComponentName newCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAliaNew");
switch (v.getId()) {
case R.id.oldIcon:
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(newCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
break;
case R.id.newIcon:
pm.setComponentEnabledSetting(newCN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
break;
}
}
}
這就是動態改變icon和label的原始碼了。
下面我開始潑冷水了:
當你修改了icon後,你的app將不能夠升級安裝了,安裝後,開啟也會直接崩潰,這就意味著,你的app將一直維持這個版本。
不能安裝的錯誤日誌如下所示:
Error while executing: am start -n "demo.lgx.com.multipleicondemo/demo.lgx.com.multipleicondemo.IconAlias" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=demo.lgx.com.multipleicondemo/.IconAlias }
Error type 3
Error: Activity class {demo.lgx.com.multipleicondemo/demo.lgx.com.multipleicondemo.IconAlias} does not exist.
Error while Launching activity
解決這個辦法,我目前想到了一個方法,就是你的app不放入各大應用市場(表打我,嚶嚶嚶~),只是自己應用內部實現更新,在更新之前,先變化自己的圖示為預設圖示,再安裝更新。
如果哪個大神有更好的辦法,請說一下哈。否則我總是覺得這個app動態更新沒什麼卵用。