转载https://blog.csdn.net/pangjl1982/article/details/83308512
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"的不要设置为多个,否则会出现多个图标,如果试图通过代码进行隐藏其中的一个或者几个,可能会出现图标消失的情况