安卓代码动态切换 APP 启动图标

3,893 阅读3分钟

转载请注明出处

blog.csdn.net/hansion3333…
本文出自Hansion的博客

目录

前言

每当双11时,手机中的“天猫”的图标就会变成双11主题的图标。这是怎么实现的呢?

有人说是更新App,没错,可以实现。但是有些大材小用了,毕竟更新一个版本。

个人猜测是在双11前的某次更新版本时已将节日图片资源打包入内,根据服务器提供的数据动态改变。所以就有了本文

需要用到的知识:activity-alias

alias 英 [ˈeɪliəs] 美 [ˈeliəs, ˈeljəs]
n. 别名,化名;

顾名思义,activity-alias并不是代表一个Activity,而是代表一个已经存在的Activity的别名。
它使用在清单文件中,类似Activity标签。它可用来设置某个Activity的快捷入口

activity-alias基本用法

<activity-alias android:enabled=["true" | "false"]
                android:exported=["true" | "false"]
                android:icon="drawable resource"
                android:label="string resource"
                android:name="string"
                android:permission="string"
                android:targetActivity="string" >
    ...
</activity-alias>

属性解释:

属性 含义
enabled 是否生效。配置多个activity-alias时,如果只想一个生效,就设置一个为true
exported 是否可以被其他应用调起,配置intent-filter时默认为true,未配置intent-filter时默认为false,只能被应用自身调起
icon 自定义生效时的icon
label 作用同Activity标签中的label属性,主要表现为桌面上的app名称和activity的title的名称
name 该activity-alias的名字
permission 指明通过别名声明调起目标Activity所必需的权限
targetActivity 指明目标Activity,类似于Activity标签中的name属性,需写明包类路径。表明通过activity-alias调起的是哪个Activity

代码范例:

  • AndroidManifest.xml
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Android ICON"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity-alias
            android:name=".MainAliasActivity"
            android:targetActivity=".MainActivity"
            android:label="UNIQLO ICON"
            android:icon="@mipmap/ic_launcher_change"
            android:enabled="false">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>

这里声明了一个activity-alias,目标Activity为MainActivity,label为“UNIQLO ICON”,指定了一个与原icon不同的icon,目前未启用
我们在MainActivity中增加两个按钮,用于切换icon

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">
    <Button
        android:layout_margin="10dp"
        android:id="@+id/mChangeToAndroid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="安卓安卓" />
    <Button
        android:layout_margin="10dp"
        android:id="@+id/mChangeToUniQlo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="一库一库" />
</LinearLayout>

在MainActivity中对按钮的点击事件进行处理,并进行相应的切换操作

  • MainActivity.class
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView() {
        Button mChangeToAndroid = (Button) findViewById(R.id.mChangeToAndroid);
        Button mChangeToUniQlo = (Button) findViewById(R.id.mChangeToUniQlo);
        mChangeToAndroid.setOnClickListener(this);
        mChangeToUniQlo.setOnClickListener(this);
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.mChangeToAndroid:
                changeIcon("com.hansion.changelaunchericon.MainActivity");
                break;
            case R.id.mChangeToUniQlo:
                changeIcon("com.hansion.changelaunchericon.MainAliasActivity");
                break;
            default:
                break;
        }
    }
    public void changeIcon(String activityPath) {
        PackageManager pm = getPackageManager();
        pm.setComponentEnabledSetting(getComponentName(),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
        pm.setComponentEnabledSetting(new ComponentName(this, activityPath),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
        //重启桌面 加速显示
//        restartSystemLauncher(pm);
    }
    public void restartSystemLauncher(PackageManager pm) {
        ActivityManager am = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
        Intent i = new Intent(Intent.ACTION_MAIN);
        i.addCategory(Intent.CATEGORY_HOME);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        List<ResolveInfo> resolves = pm.queryIntentActivities(i, 0);
        for (ResolveInfo res : resolves) {
            if (res.activityInfo != null) {
                am.killBackgroundProcesses(res.activityInfo.packageName);
            }
        }
    }
}
  • 通过以上代码切换icon后,需在桌面等待数秒钟后生效。如下图:

不重启桌面的效果

  • 如果需要加速生效,则需要在更改icon后重启一下系统桌面。解开第34行代码的注释,增加权限
    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
  • 如下图:
    重启桌面的效果

  • 需要注意的是,更换icon会关闭App,所以切换icon要选择一个合适的时机来进行操作。

个人认为本文中切换APP启动方式一定不是最好的方式,图片资源从服务器动态获取才更灵活。如果你有更好的实现方式,请留言给我,谢谢。


例子Github地址


本文参考