Android 动态修改APP图标

文章目录

  • Android 动态修改APP图标
    • 定义activity-alias
    • 修改图标和App名
    • 监听APP前后台状态切换
    • 进入后台时切换修改图标和名字
    • 缺点

Android 动态修改APP图标

修改前:

在这里插入图片描述

修改后:

在这里插入图片描述

定义activity-alias

在 AndroidManifest.xml 中设置 activity-alias:

activity-alias标签中的属性:

标签作用
android:name别名
android:enabled是否启用别名
android:icon应用图标
android:label应用名
android:targetActivity必须指向原入口Activity

下面定义了2个alias标签:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:name=".BaseApplication"
        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/Theme.MyApplication">
        <activity android:name=".SecondActivity" />
        <activity android:name=".MainActivity" />

        <activity-alias
            android:name=".DefaultAliasActivity"
            android:enabled="true"
            android:exported="true"
            android:icon="@mipmap/ic_launcher"
            android:roundIcon="@mipmap/ic_launcher_round"
            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=".TaobaoAliasActivity"
            android:enabled="false"
            android:exported="true"
            android:icon="@mipmap/ic_taobao"
            android:label="taobao"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

    </application>

</manifest>

修改图标和App名

object AliasUtils {
    private const val DEFAULT_ALIAS = "com.example.myapplication.DefaultAliasActivity"
    private const val TAOBAO_ALIAS = "com.example.myapplication.TaobaoAliasActivity"

    fun setDefaultAlias(context: Context) {
        context.packageManager.apply {
            setComponentEnabledSetting(
                ComponentName(context, DEFAULT_ALIAS),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP
            )
            setComponentEnabledSetting(
                ComponentName(context, TAOBAO_ALIAS),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP
            )
        }
    }

    fun setTaobaoAlias(context: Context) {
        context.packageManager.apply {
            setComponentEnabledSetting(
                ComponentName(context, TAOBAO_ALIAS),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP
            )
            setComponentEnabledSetting(
                ComponentName(context, DEFAULT_ALIAS),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP
            )
        }
    }
}

监听APP前后台状态切换

class BaseApplication : Application() {
    companion object {
        private lateinit var INSTANCE: BaseApplication

        fun getInstance(): BaseApplication {
            return INSTANCE
        }
    }

    override fun onCreate() {
        super.onCreate()
        INSTANCE = this
        ActivityManager.getInstance().init(INSTANCE)
    }
}
public final class ActivityManager implements Application.ActivityLifecycleCallbacks {

    private static volatile ActivityManager sInstance;

    /**
     * Activity 存放集合
     */
    private final ArrayMap<String, Activity> mActivitySet = new ArrayMap<>();

    /**
     * 应用生命周期回调
     */
    private final ArrayList<ApplicationLifecycleCallback> mLifecycleCallbacks = new ArrayList<>();

    /**
     * 当前应用上下文对象
     */
    private Application mApplication;
    /**
     * 栈顶的 Activity 对象
     */
    private Activity mTopActivity;
    /**
     * 前台并且可见的 Activity 对象
     */
    private Activity mResumedActivity;

    private ActivityManager() {
    }

    public static ActivityManager getInstance() {
        if (sInstance == null) {
            synchronized (ActivityManager.class) {
                if (sInstance == null) {
                    sInstance = new ActivityManager();
                }
            }
        }
        return sInstance;
    }

    public void init(Application application) {
        mApplication = application;
        mApplication.registerActivityLifecycleCallbacks(this);
    }

    /**
     * 获取 Application 对象
     */
    public Application getApplication() {
        return mApplication;
    }

    /**
     * 获取栈顶的 Activity
     */
    @Nullable
    public Activity getTopActivity() {
        return mTopActivity;
    }

    /**
     * 获取前台并且可见的 Activity
     */
    @Nullable
    public Activity getResumedActivity() {
        return mResumedActivity;
    }

    /**
     * 判断当前应用是否处于前台状态
     */
    public boolean isForeground() {
        return getResumedActivity() != null;
    }

    /**
     * 注册应用生命周期回调
     */
    public void registerApplicationLifecycleCallback(ApplicationLifecycleCallback callback) {
        mLifecycleCallbacks.add(callback);
    }

    /**
     * 取消注册应用生命周期回调
     */
    public void unregisterApplicationLifecycleCallback(ApplicationLifecycleCallback callback) {
        mLifecycleCallbacks.remove(callback);
    }

    /**
     * 销毁指定的 Activity
     */
    public void finishActivity(Class<? extends Activity> clazz) {
        if (clazz == null) {
            return;
        }
        String[] keys = mActivitySet.keySet().toArray(new String[]{});
        for (String key : keys) {
            Activity activity = mActivitySet.get(key);
            if (activity == null || activity.isFinishing()) {
                continue;
            }

            if (activity.getClass().equals(clazz)) {
                activity.finish();
                mActivitySet.remove(key);
                break;
            }
        }
    }

    /**
     * 销毁所有的 Activity
     */
    public void finishAllActivities() {
        finishAllActivities((Class<? extends Activity>) null);
    }

    /**
     * 销毁所有的 Activity
     *
     * @param classArray 白名单 Activity
     */
    @SafeVarargs
    public final void finishAllActivities(Class<? extends Activity>... classArray) {
        String[] keys = mActivitySet.keySet().toArray(new String[]{});
        for (String key : keys) {
            Activity activity = mActivitySet.get(key);
            if (activity == null || activity.isFinishing()) {
                continue;
            }

            boolean whiteClazz = false;
            if (classArray != null) {
                for (Class<? extends Activity> clazz : classArray) {
                    if (activity.getClass().equals(clazz)) {
                        whiteClazz = true;
                    }
                }
            }

            if (whiteClazz) {
                continue;
            }

            // 如果不是白名单上面的 Activity 就销毁掉
            activity.finish();
            mActivitySet.remove(key);
        }
    }

    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
        if (mActivitySet.size() == 0) {
            for (ApplicationLifecycleCallback callback : mLifecycleCallbacks) {
                callback.onApplicationCreate(activity);
            }
        }
        mActivitySet.put(getObjectTag(activity), activity);
        mTopActivity = activity;
    }

    @Override
    public void onActivityStarted(@NonNull Activity activity) {
    }

    @Override
    public void onActivityResumed(@NonNull Activity activity) {
        if (mTopActivity == activity && mResumedActivity == null) {
            for (ApplicationLifecycleCallback callback : mLifecycleCallbacks) {
                callback.onApplicationForeground(activity);
            }
        }
        mTopActivity = activity;
        mResumedActivity = activity;
    }

    @Override
    public void onActivityPaused(@NonNull Activity activity) {
    }

    @Override
    public void onActivityStopped(@NonNull Activity activity) {
        if (mResumedActivity == activity) {
            mResumedActivity = null;
        }
        if (mResumedActivity == null) {
            for (ApplicationLifecycleCallback callback : mLifecycleCallbacks) {
                callback.onApplicationBackground(activity);
            }
        }
    }

    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
    }

    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {
        mActivitySet.remove(getObjectTag(activity));
        if (mTopActivity == activity) {
            mTopActivity = null;
        }
        if (mActivitySet.size() == 0) {
            for (ApplicationLifecycleCallback callback : mLifecycleCallbacks) {
                callback.onApplicationDestroy(activity);
            }
        }
    }

    /**
     * 获取一个对象的独立无二的标记
     */
    private static String getObjectTag(Object object) {
        // 对象所在的包名 + 对象的内存地址
        return object.getClass().getName() + Integer.toHexString(object.hashCode());
    }

    /**
     * 应用生命周期回调
     */
    public interface ApplicationLifecycleCallback {

        /**
         * 第一个 Activity 创建了
         */
        void onApplicationCreate(Activity activity);

        /**
         * 最后一个 Activity 销毁了
         */
        void onApplicationDestroy(Activity activity);

        /**
         * 应用从前台进入到后台
         */
        void onApplicationBackground(Activity activity);

        /**
         * 应用从后台进入到前台
         */
        void onApplicationForeground(Activity activity);
    }
}

进入后台时切换修改图标和名字

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    ActivityManager.getInstance().registerApplicationLifecycleCallback(object :
        ActivityManager.ApplicationLifecycleCallback {
        override fun onApplicationCreate(activity: Activity?) {
        }

        override fun onApplicationDestroy(activity: Activity?) {
        }

        override fun onApplicationBackground(activity: Activity?) {
            Log.e("TAG", "App处于后台")
            if (type == TYPE_DEFAULT) {
                AliasUtils.setDefaultAlias(this@MainActivity)
            } else if (type == TYPE_TAOBAO) {
                AliasUtils.setTaobaoAlias(this@MainActivity)
            }
        }

        override fun onApplicationForeground(activity: Activity?) {
            Log.e("TAG", "App处于前台")
        }
    })
}

缺点

  • 切换图标时,应用会自动退出,因此放在后台执行相对有好些。
  • 切换图标是一个耗时过程,1s~10s不等。
  • 在切换图标过程中,点击App图标,可能会提示“应用数据读取失败”等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/686839.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法无用系列】电影推荐——余弦相似度计算用户相似度原理

【算法无用系列】通过余弦相似度计算电影、用户相似度 话不多说&#xff0c;本文通过电影推荐系统中&#xff0c;基于余弦相似度算法计算出用户相似和电影相似原理。希望可以帮助一些代码不懂的同学一些思路。 记录用户电影评分数据 一般情况来说&#xff0c;会根据用户的行为…

《贫穷的本质》

穷人获取的信息有限&#xff0c;存在认知上的差距&#xff0c;不了解自己现有的资源&#xff0c;并且合理使用。 self conclusion 1、由以下摘抄1有感而发&#xff1a;童年时期将很大程度上影响未来的发展。 《贫穷的本质》一书告诉我们&#xff0c;孕妇和幼儿时期如果能提供更…

【全开源】CRM管理客户关系系统源码

CRM&#xff1a;助力企业高效管理客户关系 全面解决企业销售团队的全流程客户服务难题&#xff0c;旨在助力企业销售全流程精细化、数字化管理&#xff0c;全面解决企业销售团队的全流程客户服务难题&#xff0c;帮助企业有效盘活客户资源、量化销售行为&#xff0c;合理配置资…

【C语言】学生管理系统:完整模拟与实现

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 &#x1f525;引言 本篇文章为修改了在校期间实训报告&#xff0c;使用C…

使用Ollama+OpenWebUI部署和使用Phi-3微软AI大模型完整指南

&#x1f3e1;作者主页&#xff1a; 点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月6日23点50分 &#x1f004;️文章质量&#xff1a;96分 欢迎来到Phi-3模型的奇妙世界&#xff01;Phi-3是由微软…

Linux通过安装包配置环境变量(详细教程)

本章教程使用jdk1.8.0_241版本在Linux CentOS系统中,配置Java环境变量。 一、下载安装包 微云下载:https://share.weiyun.com/JeWZMDoh 二、上传安装包 将安装包上传到linux中的opt目录中 三、解压安装包 tar -xzvf jdk-8u241-linux-x64.tar.gz四、配置环境变量 vim /etc/p…

CC++内存管理【new和delete操作符的详细分析】【常见面试题】

C/C内存管理 1.C/C内存分布 我们先来看一段代码&#xff0c;来了解一下C/C中的数据内存分布。 # include <stdlib.h>int globalVar 1; static int staticGlobalVar 1; // 比globalVar还要先销毁,同一个文件下后定义的先析构 // 全局变量存在 数据段&#xff08;静态…

【Linux】ip命令详解

Linux网络排查 目录 一、ip命令介绍 1.1 ip命令简介 1.2 ip命令的由来 二、ip命令使用帮助 2.1 ip命令的help帮助信息 2.2 ip命令对象介绍 2.3 ip命令选项介绍 三、查看网络信息 3.1 显示当前网络接口信息 3.2 显示网络设备运行状态 3.3 显示详细设备信息 3.4 查看…

【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变

前言 【Unity实战篇 】 | Unity实现UGUI颜色渐变&#xff0c;支持透明渐变一、双层颜色渐变1.1 组件属性面板1.2 效果及代码 二、多层颜色渐变2.1 组件属性面板2.2 效果及代码 总结 前言 在Unity中UGUI的实现图片和文字颜色渐变效果是一个很常见的需求。下面就来看一下颜色渐变…

爬虫——有道云翻译

废话不多说直接上代码 固定文本内容 import timefrom selenium import webdriver from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWai…

Python接口自动化测试:Json 数据处理实战

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 上一篇说了关于json数据处理&#xff0c;是为了断言方便&#xff0c;这篇就带各位小伙伴实战一下…

SpringBootWeb 篇-深入了解 AOP 面向切面编程与 AOP 记录操作日志案例

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 AOP 概述 1.1 构造简单 AOP 类 2.0 AOP 核心概念 2.1 AOP 执行流程 3.0 AOP 通知类型 4.0 AOP 通知顺序 4.1 默认按照切面类的类名字母排序 4.2 用 Order(数字) 注…

b端系统类管理平台设计前端开发案例

b端系统类管理平台设计前端开发案例

(学习笔记)数据基建-数据质量

数据基建-数据质量 数据质量数据质量保障措施如何推动上下游开展数据质量活动数据质量保障如何量化产出数据质量思考全链路数据质量保障项目 数据质量 概念&#xff1a;数据质量&#xff0c;意如其名&#xff0c;就是数据的准确性&#xff0c;他是数据仓库的基石&#xff0c;控…

【案例分享】印前制版工单系统:“鹿山科技”助力“铭匠数据”重塑业务流程

内容概要 本文介绍了鹿山信息科技通过明道云HAP平台的数字化解决方案提升了铭匠数据在印前制版行业的效率。周口铭匠数据科技有限公司位于河南省周口市沈丘县&#xff0c;是一家专注于印前制版设计服务的公司&#xff0c;成立于2023年。企业在销售业务、版材制作生产和美工设计…

CATIA入门操作案例——草图绘制案例,导入草图图片,尺寸约束直径/半径切换,草图分析闭合检查,草图固定

目录 引出草图绘制&#xff0c;导入图片方便绘制新建product&#xff0c;进入sketch tracer模块技巧&#xff1a;尺寸直径 / 半径切换技巧&#xff1a;右键&#xff0c;自动搜索 草图分析&#xff1a;检查闭合警告&#xff1a;Change it to material mode to see the Paintings…

60V大功率半桥GaN半桥驱动器替代LMG1210

1. 产品特性&#xff08;替代LMG1210&#xff09; ➢ 工作频率高达 10MHz ➢ 20ns 典型传播延迟 ➢ 5ns 高侧/低侧匹配 ➢ 两种输入控制模式 ➢ 具有可调死区时间的单个 PWM 输入、 独立输入模式 ➢ 1.5A 峰值拉电流和 3A 峰值灌电流 ➢ 内置 5V LDO ➢ 欠压保护 ➢ 过…

小程序简单版录音机

先来看看效果 结构 先来看看页面结构 <!-- wxml --><view class"wx-container"><view id"title">录音机</view><view id"time">{{hours}}:{{minute}}:{{second}}</view><view class"btngroup"…

【人工智能】第七部分:ChatGPT的未来展望

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

kafka安装流程

安装kafka前需要安装zookeeper zookeeper安装教程 1.新建一个logs文件夹 2.修改配置文件 3.修改listeners参数 4.以管理员身份启动kafka服务 .\bin\windows\kafka-server-start.bat .\config\server.properties 如果报 输入行太长。 命令语法不正确。 解决方案如下&#x…