Android 动态修改APP图标

news2025/1/12 20:42:21

文章目录

  • 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图标,可能会提示“应用数据读取失败”等。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python类与面向对象编程

⚠️⚠️⚠️本章后半部分难度激增&#xff0c;请一定认真学习⚠️⚠️⚠️ ⚠️⚠️⚠️本章后半部分难度激增&#xff0c;请一定认真学习⚠️⚠️⚠️ ⚠️⚠️⚠️本章后半部分难度激增&#xff0c;请一定认真学习⚠️⚠️⚠️ 上篇回顾&#xff1a; 上篇我们帮天下第一…

基于STM32开发的智能水族箱管理系统

目录 引言环境准备智能水族箱管理系统基础代码实现&#xff1a;实现智能水族箱管理系统 4.1 温度传感器数据读取4.2 水泵与加热器控制4.3 水位传感器数据读取4.4 用户界面与显示应用场景&#xff1a;水族箱管理与优化问题解决方案与优化收尾与总结 1. 引言 智能水族箱管理系…

从0到1实现一个自己的大模型,实践中了解模型流程细节

前言 最近看了很多大模型&#xff0c;也使用了很多大模型。对于大模型理论似乎很了解&#xff0c;但是好像又缺点什么&#xff0c;思来想去决定自己动手实现一个 toy 级别的模型&#xff0c;在实践中加深对大语言模型的理解。 在这个系列的文章中&#xff0c;我将通过亲手实践…

【OPENMV】学习记录 (持续更新)

一、基础知识 1 设置彩色&#xff0f;黑白&#xff1a; sensor.set_pixformat() 设置像素模式。 sensor.GRAYSCALE: 灰度&#xff0c;每个像素8bit。sensor.RGB565: 彩色&#xff0c;每个像素16bit。 2 设置图像大小&#xff1a; sensor.set_framesize() 设置图像的大小 sen…

day51 动态规划 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 动态规划 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][0] 表示第i天持有股票所得最多现金 &#xff0c;这里可能有同学疑惑&#xff0c;本题中只能买卖一次&#xff0c;持有股票之后哪还有现金呢&#xff1f; 其实一开始现…

解密智慧校园解决方案:赋能数字化教育的未来

在当今数字化时代&#xff0c;智慧校园解决方案正以惊人的速度改变着教育界的面貌。随着科技的快速发展&#xff0c;数字化教育已经逐渐成为现代教育的核心。智慧校园解决方案作为一个集技术、教育和创新于一体的综合性项目&#xff0c;为学校提供了许多机遇和挑战。本文将揭示…

期望18K,4年前端Cvte 视源股份一面挂

一面 1、自我介绍&#xff1f;毕业的时候一直在 xx 公司&#xff0c;你基本都在做什么项目&#xff1f; 2、你讲一下你主要负责哪一块的&#xff1f;balabala 3、你们的 json 是怎么定义组件间的联动的&#xff1f; 4、怎么确定区分两个 input&#xff1f; 5、你们是怎么触…

Vue3入门 - vue3相比于vue2的优点,及如何创建Vue3项目

目录 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API 2. Vue3的优势 二、使用create-vue搭建Vue3项目 1. 认识create-vue 2. 使用create-vue创建项目 3.熟悉项目和关键文件 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script>export default …

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑发用电相似性的海上风电中长期双边协商交易优化决策模型》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【CV算法工程师必看】作为一个图像算法工程师,需要会什么,要学哪些技术栈?

作为一个图像算法工程师,除了基本的编程技能和理论知识,还需要掌握一系列的技术栈。以下是详细的技能和技术栈分类: 编程语言 Python: 主要用于快速开发和原型设计。常用库:OpenCV、Pillow、NumPy、SciPy、Scikit-image、TensorFlow、PyTorch。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是由微软…

零售数据分析围绕人、货、场分析了什么?

零售数据分析围绕人、货、场分析了什么&#xff1f;通过全面分析零售业务中的人、货、场三个核心要素&#xff0c;为零售商提供深入的市场洞察和业务优化建议。通过对客流量、商品销售、场地布局等数据的收集和数据可视化分析&#xff0c;帮助企业更好地了解消费者行为、商品销…

一起学大模型 - 一起动笔练习prompt的用法

文章目录 前言一、代码演示二、代码解析1. 导入所需的库和模块&#xff1a;2. 设置日志记录和初始化模型&#xff1a;3. 定义一个函数用于清理GPU内存&#xff1a;4. 定义一个继承自LLM基类的QianWenChatLLM类&#xff0c;并实现对话生成的逻辑&#xff1a;5. 示例代码的主体部…

【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 查看…

【多模态】37、TextSquare | 借助 Gemini-Pro 通过四个步骤来生成高质量的文本问答数据

文章目录 一、背景二、方法2.1 Square-10M2.2 模型结构2.3 使用 Square-10M 进行有监督微调 三、效果3.1 实验设置3.2 Benchmark 测评 论文&#xff1a;TextSquare: Scaling up Text-Centric Visual Instruction Tuning 代码&#xff1a;暂无 出处&#xff1a;字节 | 华中科技…

大学生必备搜题神器app?分享3个软件和公众号,来对比看看吧 #媒体#其他#笔记

以下分享的软件提供了各种实用的功能&#xff0c;如数学公式计算、语文阅读辅助等&#xff0c;让大学生们在学习过程中更加高效和便利。 1.同声传译王 譬如我们在搜题或是浏览一些资料文档到时候&#xff0c;经常会访问到一些外文网页或文档&#xff0c;所以一款趁手的翻译工…

2024年四川省国家大学科技园申报条件对象和支持政策

2024年四川省国家大学科技园申报对象 国家大学科技园是以具有较强科研实力的大学为依托&#xff0c;将大学的综合智力资源优势与其它社会优势资源相结合&#xff0c;为高等学校&#xff08;以下简称为高校&#xff09;科技成果转化、高新技术企业孵化、创新创业人才培养、产学…

白酒:茅台镇白酒的丰富历史与文化传承

茅台镇&#xff0c;位于中国贵州省仁怀市&#xff0c;是中国著名的白酒产区&#xff0c;以其得天独厚的自然环境和与众不同的酿造工艺而闻名于世。作为茅台镇的白酒品牌之一&#xff0c;云仓酒庄豪迈白酒承载着丰富的历史与文化传承。 茅台镇的历史可以追溯到汉代&#xff0c;当…

@vue-office/excel 解决移动端预览excel文件触发软键盘

先直接上代码 不耽误大家时间 标明下插件库 非常感谢作者提供预览插件 vue-office/excel 只需要控制CSS :deep(.x-spreadsheet-overlayer) {.x-spreadsheet-selectors {display: none !important;} } :deep(.x-spreadsheet-bottombar) {li.active {user-select: none !import…

visual studio打包qt算子时,只生成dll没有生成lib等文件

问题&#xff1a;在visual studio配置了qt项目&#xff0c;并打包成dll&#xff0c;原则上会生成一堆文件&#xff0c;包括dll,lib等文件。 解决办法&#xff1a; 挨个右击源代码的所有头文件-》属性-》项类型。改成qt头文件形式&#xff0c;如下。