Android 中的动态应用程序图标

Android 中的动态应用程序图标

  • 一、需求
  • 二、解决方案
  • 三、方案实现
  • 四、结论

一、需求

您可能遇到过那些可以实现巧妙技巧的应用程序 - 更改应用程序图标(也许是在您的生日那天),然后无缝切换回常规图标。这种功能会激起你的好奇心,让你想知道,他们到底是怎么做到的?好吧,你并不是唯一一个有好奇心的人。许多开发人员,包括我自己,都思考过这个问题。这似乎是看似不可能的任务之一,但你猜怎么着?它不是!在本文中,我们将揭开运行时更改 Android 应用程序图标背后的谜团。我们将一步步为您分解,并向您展示它不仅可行,而且非常易于管理。

二、解决方案

首先,应用程序图标是从清单文件设置的,就像任何其他应用程序组件一样。Android系统读取manifest文件并相应地设置应用程序图标。目前无法在运行时更改应用程序图标。但有一个解决方法。也就是使用一个activity-alias(如果你对activity-alias不熟悉,可以查看这里的官方文档)。

三、方案实现

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

    <application
        ...
        android:icon="YOUR_ICON"
        android:roundIcon="YOUR_ICON">
        <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:icon="YOUR_ICON_2"
            android:roundIcon="YOUR_ICON_2"
            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>

如您所见,我们有两项活动。一个是主要活动,另一个是活动别名。默认情况下禁用活动别名。它的图标与主要活动不同。因此,当安装应用程序时,将设置主要活动的图标。activity-alias当我们启用活动别名时,将设置活动的图标。因此,我们可以通过启用和禁用活动别名来在运行时更改应用程序图标。现在让我们看看如何在运行时启用和禁用活动别名。我们可以通过使用PackageManager类来做到这一点。

fun Activity.changeIcon() {
        packageManager.setComponentEnabledSetting(
            ComponentName(
                this,
                "$packageName.MainActivityAlias"
            ),
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
        )

        packageManager.setComponentEnabledSetting(
            ComponentName(
                this,
                "$packageName.MainActivity"
            ),
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
        )
}

正如您所看到的,我们正在使用PackageManager类的setComponentEnabledSetting方法。我们正在传递活动别名和主要活动的组件名称。我们将活动别名设置为启用,将主要活动设置为禁用。因此,当我们调用此方法时,活动别名将被启用,而主活动将被禁用。所以应用程序图标将会改变。
在这里插入图片描述

另外,作为一名软件工程师,我不喜欢这种实现方式。我希望事情干净且灵活。因此,我认为最好将上面的函数更新如下:

fun Activity.changeEnabledComponent(
        enabled: String,
        disabled: String,
    ) {
        packageManager.setComponentEnabledSetting(
            ComponentName(
                this,
                enabled
            ),
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
        )

    packageManager.setComponentEnabledSetting(
            ComponentName(
                this,
                disabled
            ),
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )
}

因此,更改应用程序图标就像使用组件名称调用函数一样简单。例如:

changeEnabledComponent(
    enabled = "$packageName.MainActivityAlias",
    disabled = "$packageName.MainActivity"
)

另外,作为一名软件工程师,我们仍然使用硬代码这一事实让我很困扰。我什至希望事情变得更加灵活,更加愿意改变。所以我想对组件名称进行更多抽象。但这是一个挑战,因为我们需要以某种方式获得与清单文件中使用的相同的名称。为了解决这个问题,我们可以使用BuildConfig和manifestPlaceholders. 在应用程序级 build.gradle 文件中,我们可以添加以下代码:(我假设您正在为 build.gradle 文件使用Kotlin DSL 。)

    private val mainActivity = "YOURPATH.MainActivity"
    private val mainActivityAlias = "YOURPATH.MainActivityAlias"
    android {
        defaultConfig {
            ...
            manifestPlaceholders.apply {
                set("main_activity", mainActivity)
                set("main_activity_alias", mainActivityAlias)
            }
        }

        buildTypes {
            release {
                isMinifyEnabled = false
                buildConfigField("String", "main_activity", "\"${mainActivity}\"")
                buildConfigField("String", "main_activity_alias", "\"${mainActivityAlias}\"")
            }

            debug {
                isDebuggable = true
                isMinifyEnabled = false 
                buildConfigField("String", "main_activity", "\"${mainActivity}\"")
                buildConfigField("String", "main_activity_alias", "\"${mainActivityAlias}\"")
            }
        }
    }

这里我们将组件名称设置为manifestPlaceholdersbuildConfigField。因此我们可以从BuildConfig类访问它们。当然,我们需要更新清单文件,以便它使用占位符。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application ... >
        <activity
            android:name="${main_activity}"
            ... >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity-alias
            android:name="${main_activity_alias}"
            ...
            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>

您现在可能会看到一些错误,指出main_activity和/或main_activity_alias无法找到。但您可以忽略它们,因为它们将与 build.gradle 文件同步生成。现在我们可以更新代码以使用BuildConfig类。

changeEnabledComponent(
    enabled = BuildConfig.main_activity_alias,
    disabled = BuildConfig.main_activity
)

现在我们有了一个干净且灵活的代码。我们可以通过使用组件名称调用changeEnabledComponent函数来在运行时更改应用程序图标。我们可以更改 build.gradle 文件中的组件名称。因此我们可以在运行时更改应用程序图标,而无需更改代码。作为更广泛的示例,请查看下面的代码。

val mainActivity = BuildConfig.main_activity
val mainActivityAlias = BuildConfig.main_activity_alias

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            DynamicIconTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Screen(
                        on30Click = {
                            changeEnabledComponent(
                                enabled = mainActivityAlias,
                                disabled = mainActivity
                            )
                        },
                        on60Click = {
                            changeEnabledComponent(
                                enabled = mainActivityAlias,
                                disabled = mainActivity
                            )
                        }
                    )
                }
            }
        }
    }
}

四、结论

从本质上讲,我们已经打破了“在运行时动态更改 Android 应用程序图标是一项无法实现的壮举”的神话。通过利用应用程序清单中的功能activity-alias并熟练地使用 PackageManager 类,我们已经揭示了实现这一目标的路径。然而,真正的游戏规则改变者在于我们对更清晰、适应性更强的代码的追求,我们利用占位符和 BuildConfig 来实现最终的灵活性。现在,您可以让用户将自己独特的风格注入到您的应用程序图标中,而不会迷失在代码杂草中。@[toc](Android 中的动态应用程序图标)

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

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

相关文章

网络防御安全:2-6天笔记

第二章&#xff1a;防火墙 一、什么是防火墙 防火墙的主要职责在于&#xff1a;控制和防护。 防火墙可以根据安全策略来抓取流量之后做出对应的动作。 二、防火墙的发展 区域&#xff1a; Trust 区域&#xff0c;该区域内网络的受信任程度高&#xff0c;通常用来定义内部…

TensorFlow2实战-系列教程9:RNN文本分类1

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 1、文本分类任务 1.1 文本分类 数据集构建&#xff1a;影评数据集进行情感分析&…

Leetcode 206 反转链表

反转链表 准备工作1&#xff09;ListNode基本结构2&#xff09;初始化ListNode集合 解法一&#xff1a;遍历创建新节点解法二&#xff1a;两组List&#xff0c;面向对象操作解法三&#xff1a;递归调用解法四&#xff1a;直接移动解法五&#xff1a;解法二的面向过程 Leetcode …

spring cloud activiti 审批流的用法

demo的搭建及使用 1、创建activiti审批流需要安装bpmn插件&#xff0c;新的idea版本支持的这个bpmn插件只有下图这个&#xff0c;并不好用&#xff0c;所以我这里使用eclipse来创建bpmn流程 eclipse的连接如下&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1mSoKprN-…

基于Java SSM框架实现药品销售系统项目【项目源码+论文说明】

基于java的SSM框架实现药品销售系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个药品销售系统 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述药品销…

原生table样式

HTML <div><table style"width: 100%;"><thead><tr><th style"width:25%;">董事会</th><th style"width:25%;">监事会</th><th style"width:25%;">股东</th><th sty…

【Vue】前端项目引入阿里图标

【Vue&React】前端项目引入阿里图标 1、登录自己的iconfont-阿里巴巴矢量图标库&#xff0c;把需要的图标加入到自己的项目中去&#xff1b;2、加入并进入到项目中去选择Font class 并下载到本地3、得到的文件夹如下4. 把红框中的部分粘贴到自己的项目中&#xff08; stati…

CRG设计之复位

1. 前言 CRG(Clock and Reset Generation&#xff0c;时钟复位生成模块) 模块扮演着关键角色。这个模块负责为整个系统提供稳定可靠的时钟信号&#xff0c;同时在系统上电或出现故障时生成复位信号&#xff0c;确保各个模块按预期运行。简而言之&#xff0c;CRG模块就像是SoC系…

nginx无法启动,win10占用80端口 (注册表方式解决)

参考&#xff1a;https://blog.csdn.net/qq_39523111/article/details/128853509 改为4 重启后 不再占用 pid 不是4了 已经变为nginx了 改为0 没起作用

蓝桥杯2024/1/26笔记-----基于PCF8591的电压采集装置

功能实现要求&#xff1a; 每次建好工程文件夹&#xff0c;里边包含User&#xff08;放工程文件&#xff0c;mian.c&#xff0c;可以在这里写如同我这个文章的文本文档&#xff09;、Driver&#xff08;存放底层文件如Led.c&#xff0c;Led.h等&#xff09; 新建的工程先搭建框…

STM32——中断系统和外部中断EXTI

一、中断 1.1中断系统 中断系统是管理和执行中断的逻辑结构&#xff1b; 1.2中断 系统在执行主程序过程中&#xff0c;出现了特定的触发条件&#xff08;触发源&#xff09;&#xff0c;系统停止执行当前程序&#xff0c;转而去执行中断程序&#xff0c;执行完毕后&#xf…

windows系统下启动redis命令

windows系统下启动redis命令 进入redis安装目录 cd redis 输入 redis-server.exe redis.windows.conf 启动redis命令&#xff0c;看是否成功 可能会启动失败&#xff0c;报[1696] 30 Jan 09:46:07.518 # Creating Server TCP listening socket 127.0.0.1:6379: bind: No erro…

云计算底层技术、磁盘技术揭秘虚拟化管理、公有云概述

查看本机是否具备虚拟化支持 硬件辅助虚拟化 处理器里打开 虚拟化Inter VT-x/EPT 或AMD-V 构建虚拟化平台工具软件包 yum 与 dnf Yum和DNF都是用于管理Linux系统中的软件包的工具&#xff0c;但它们在许多方面存在一些差异。以下是一些可能的区别&#xff1a; 依赖解…

运行VUE提示找不到模块validate-engines.js...

原来好好的&#xff0c;突然提示找不到模块validate-engines.js&#xff0c;CMD命令行输入npm -v不是内部或外部命令&#xff0c;node -v可以查看到版本号。 解决&#xff1a; 1. 卸载nodejs&#xff0c;重新下载安装文件&#xff1a;下载nodejs 2. 到目录&#xff1a;C:\Us…

成功解决AttributeError: ‘str‘ object has no attribute ‘decode‘

成功解决AttributeError: ‘str’ object has no attribute ‘decode’. &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;报错分析及解决方案&#x1f333;&#x1f333;参考文章&#x1f333;&#x1f333;结尾&#x1f333; &#x1f333;引…

Chiplet,汽车“芯”风向

异构集成、高速互联、算力灵活可扩展正在成为新一轮汽车芯片竞争的焦点。尤其是随着以ChatGPT为代表的大数据、大模型产品在车端的落地&#xff0c;对于芯片的要求还在持续提升。 本周&#xff0c;12家日本汽车制造商&#xff08;包括丰田、日产、本田等&#xff09;、零部件制…

Redis 面试题 | 20.精选Redis高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

三、防御保护---防火墙安全策略篇

三、防御保护---防火墙安全策略篇 一、什么是安全策略二、安全策略的组成1.匹配条件2.动作3.策略标识 三、防火墙的状态检测和会话表1.会话表2.状态检测技术 四、ASPF--隐形通道五、用户认证1.用户认证的分类2.认证方式3.认证策略4.认证域 一、什么是安全策略 传统的包过滤防火…

ORBSLAM3 运行流程 以rgbd_tum.cc函数为例进行分析

一、运行 使用的是D435i相机自己录制的数据。 运行命令&#xff1a; ./Examples/RGB-D/rgbd_tum /opt/vslam/ORB_SLAM3_detailed_comments-dense_map_new/Vocabulary/ORBvoc.txt /opt/vslam/ORB_SLAM3_detailed_comments-dense_map_new/Examples/RGB-D/TUM1.yaml /opt/vsl…

医美诊疗前后要注意的八大诀窍

【记者许家源/综合报导】 随着年龄的增长&#xff0c;许多人都想保持年轻美丽&#xff0c;因此寻求医美诊疗的帮助。然而&#xff0c;进入医美诊所后&#xff0c;你可能会发现&#xff0c;想要打肉毒、除毛等&#xff0c;实际花费和广告中的金额相差甚远。为了避免上当受骗&am…