动态更换桌标 Activity-alias

前言

动态更换App图标,网上可以收搜到很多,这里也是参考前人经验,读完本文可以得到,如何动态更换桌标(非网络获取桌标图片),标志位的阐述,更加透彻的理解.

用到的知识

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

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,设置别名
        
            
                

                
            
        
        
        
            
                

                
            
        

这里要注意的是

android:name 标识:主要用于在代码中获取此组件enable的状态;
android:targetActivity标识,targetActivity标识就是点击后跳转的Activity;
icon和lable分别是启动图标和桌面名称

  • 代码配置

思路是首先获取服务端下发接口,缓存到本地,等用户退出主页的时候执行更换图标的逻辑

  1. 获取服务端接口,接口提示更换节日图标
  2. 判断要显示组件的状态是否为显示状态COMPONENT_ENABLED_STATE_ENABLED
 private boolean isComponentState(ComponentName componentName) {
      
    return mPackageManager.getComponentEnabledSetting(componentName) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}

注意:这里的标示位

属性 含义
COMPONENT_ENABLED_STATE_DEFAULT 默认状态,xml预设的状态
COMPONENT_ENABLED_STATE_ENABLED 此组件或应用程序已明确启用,无论其清单中指定了什么。
COMPONENT_ENABLED_STATE_DISABLED 此组件或应用程序已明确禁用,无论其清单中指定了什么。
COMPONENT_ENABLED_STATE_DISABLED_USER 用户已明确禁用该应用程序,无论其在清单中指定了什么。
COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED his application should be considered, until the point where the user actually wants to use it. (这个不清楚怎么翻才好,没有使用过)
  1. 如果不是则设置其可见,否则不变

注意这里设置标志位是永久性的,即使App升级获取此组件状态时,也是之前的值

  private void enableComponent(ComponentName componentName) {
        //此方法用以启用和禁用组件,会覆盖Androidmanifest文件下定义的属性
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

完整代码


public class ChangeAppIconUtils {

    private PackageManager mPackageManager;
    //默认桌标
    private static final String DEFAULT_ICON = "com.x.x.activitys.WelcomeActivity";
    //活动桌标
    private static final String ANTHER_ICON = "com.x.x.changeLauncherIconActivity";
    //缓存文件键值
    public static final String KEY_LAUNCHER_ICON = "key_launcher_icon";

    public ChangeAppIconUtils(PackageManager mPackageManager) {
        this.mPackageManager = mPackageManager;
    }

    /**
     * 启动组件
     *
     * @param componentName 组件名
     */
    private void enableComponent(ComponentName componentName) {
        //此方法用以启用和禁用组件,会覆盖Androidmanifest文件下定义的属性
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    /**
     * 禁用组件
     *
     * @param componentName 组件名
     */
    private void disableComponent(ComponentName componentName) {
        mPackageManager.setComponentEnabledSetting(componentName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }


    /**
     * 当前组件的状态,判断当前enable状态
     * 即使xml里面设置enable=false 标志位第一次获取时 还是COMPONENT_ENABLED_STATE_DEFAULT
     * 所以这里判断是否为enable
     *
     * @param componentName return true 未被应用为可显示
     */
    private boolean isComponentState(ComponentName componentName) {
        //默认图标且为默认状态则返回false
        return !(DEFAULT_ICON.equals(componentName.getClassName()) && mPackageManager.getComponentEnabledSetting(componentName) == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
                && mPackageManager.getComponentEnabledSetting(componentName) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
    }


  /**
     * 更换app 图标
     *
     * @param context    context
     * @param changeIcon changeIcon
     */
    private void changeIconState(Context context, String changeIcon) {
        ComponentName defaultIcon = new ComponentName(context, DEFAULT_ICON);
        ComponentName otherIcon = new ComponentName(context, ANTHER_ICON);
        //判断状态
        if (DEFAULT_ICON.equals(changeIcon)) {//设置默认icon
            boolean componentState = isComponentState(defaultIcon);
            if (componentState) {//如果不一样则设置
                enableComponent(defaultIcon);
                disableComponent(otherIcon);
//                restartSystemLauncher(context, mPackageManager);
            }
        } else {//其它icon
            boolean componentState = isComponentState(otherIcon);
            if (componentState) {
                enableComponent(otherIcon);
                disableComponent(defaultIcon);
//                restartSystemLauncher(context, mPackageManager);
            }
        }
    }

    /**
     * 没啥用,有的rom不会让你杀掉Launcher进程,例如华为,VIVO
     * @param context
     * @param pm
     */
    private void restartSystemLauncher(Context context, PackageManager pm) {
        ActivityManager am = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE);
        Intent i = new Intent(Intent.ACTION_MAIN);
        i.addCategory(Intent.CATEGORY_HOME);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        List resolves = pm.queryIntentActivities(i, 0);
        for (ResolveInfo res : resolves) {
            if (res.activityInfo != null && am != null) {
                am.killBackgroundProcesses(res.activityInfo.packageName);
            }
        }
    }

    public void setAppLauncherIcon(Context context, String tagName) {
        if (!TextUtils.isEmpty(tagName)) {
            if ("icon2".equals(tagName)) {
                changeIconState(context, ANTHER_ICON);
            } else {
                changeIconState(context, DEFAULT_ICON);
            }
        }
    }
}

使用的时候只需要

new ChangeAppIconUtils(getPackageManager()).setAppLauncherIcon(getApplicationContext(), sharePreUtils.getStringValue(ChangeAppIconUtils.KEY_LAUNCHER_ICON, ""));

这里的sharepreUtils是工具类获取接口中下发的状态值,icon1默认图标,icon2为节日图标,因为之前有人说会导致app的重启,所以这里的操作时放在主Activity onDestory里面执行的.

问题

  • 目前已知的问题,当改完图标之后,使用AS再次启动会无法启动,把快速启动关掉就可以了
Error while executing: am start -n "in.myinnos.changeappiconandname/in.myinnos.changeappiconandname.MainActivity-settings" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=in.myinnos.changeappiconandname/.MainActivity-settings }
Error type 3
Error: Activity class {in.myinnos.changeappiconandname/in.myinnos.changeappiconandname.MainActivity-settings} does not exist.

Error while Launching activity

这里我使用打包的方式覆盖安装没有出现这个问题

  • 改过图标后,会过一会儿图标才会改变,有的(华为)改变之前点击会提示<该应用未安装>,但是桌面更新后就可以点进去了
  • 使用重启桌面的方法,加快图标的切换,1.会被系统禁用例如华为 Vivo Oppo则无法重启桌面2.小米可以,但是还是会在1~3秒的时候关闭应用一次
  • 仅仅修改的是启动图标,如果有快捷方式那么快捷方式不会发生改变,当然可以使用代码动态更新快捷方式
  • 无法动态加载网络图片,还是仅仅是本地资源修改的桌标

参考

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

你可能感兴趣的:(动态更换桌标 Activity-alias)