1. 程式人生 > >Android利用activity-alias動態更新圖示icon,標題label

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動態更新沒什麼卵用。