在Android中实现动态应用图标

在Android中实现动态应用图标

你可能已经遇到过那些能够完成一个神奇的技巧的应用程序——在你的生日时改变他们的应用图标,然后无缝切换回常规图标。这是一种引发你好奇心的功能,让你想知道,“他们到底是如何做到的?”。嗯,你对这个好奇并不孤单。很多开发者,包括我自己,也曾思考过这个问题。它似乎是一项看似不可能实现的任务,但猜猜怎么着?它并不是!在本文中,我们将解开在运行时更改Android应用图标的奥秘。我们将逐步介绍并展示给你,这不仅是可行的,而且还相当容易管理。

首先,应用图标是从类似于其他应用组件的清单文件中设置的。Android系统读取清单文件并相应地设置应用图标。目前没有办法在运行时更改应用图标。但有个变通方法。那就是使用activity-alias(如果你对activity-alias不熟悉,可以在官方文档中查看)。

https://developer.android.com/guide/topics/manifest/activity-alias-element

<?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>

如你所见,我们有两个activities。一个是主要activity,另一个是activity alias。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"
)

作为一名软件工程师,我们仍在使用硬编码的事实让我很不满意。我甚至希望事情变得更灵活,更容易改变。所以我想更抽象一些组件名称。但是这里有一个挑战,因为我们必须以某种方式获取与清单文件中使用的相同名称。为了解决这个问题,我们可以使用BuildConfigmanifestPlaceholders,而不是使用硬编码的字符串。在应用程序级别的build.gradle文件中,我们可以添加以下代码:

  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 = falsebuildConfigField("String", "main_activity", "\"${mainActivity}\"")buildConfigField("String", "main_activity_alias", "\"${mainActivityAlias}\"")}debug {isDebuggable = trueisMinifyEnabled = 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...><activityandroid:name="${main_activity}"...><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity-aliasandroid: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_activitymain_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_aliasclass 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实现了极高的灵活性。现在,您可以让用户为您的应用程序图标注入自己独特的风格,而无需迷失在代码的泥沼中。

Github

https://github.com/oguzhanaslann/DynamicIcon

参考

https://www.geeksforgeeks.org/how-to-change-app-icon-of-android-programmatically-in-android/
https://developer.android.com/guide/topics/manifest/activity-alias-element

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML 笔记 表格

1 表格基本语法 tr&#xff1a;table row th&#xff1a;table head 2 表格属性 2.1 基本属性 表格的基本属性是指表格的行、列和单元格但并不是每个表格的单元格大小都是统一的&#xff0c;所以需要设计者通过一些属性参数来修改表格的样子&#xff0c;让它们可以更更多样…

VR全景展示带来旅游新体验,助力旅游业发展!

引言&#xff1a; VR&#xff08;虚拟现实&#xff09;技术正以惊人的速度改变着各行各业&#xff0c;在旅游业中&#xff0c;VR全景展示也展现了其惊人的影响力&#xff0c;为景区带来了全新的宣传机会和游客体验。 一&#xff0e;什么是VR全景展示&#xff1f; VR全景展示是…

华硕平板k013me176cx线刷方法

1.下载adb刷机工具, 或者刷机精灵 2.下载刷机rom包 华硕asus k013 me176cx rom固件刷机包-CSDN博客 3.平板进入刷机界面 进入方法参考&#xff1a; ASUS (k013) ME176CX不进入系统恢复出厂设置的方法-CSDN博客 4.解压ME176C-CN-3_2_23_182.zip&#xff0c;把UL-K013-CN-3.2.…

软件测试面试之问——角色扮演

作为软件测试工程师&#xff0c;在求职面试中经常会被问到这样一个问题&#xff1a;你认为测试工程师在企业中扮演着什么样的角色呢&#xff1f; 某度百科是这样概括的&#xff1a;“软件测试工程师在一家软件企业中担当的是‘质量管理’角色&#xff0c;及时发现软件问题并及…

2.5 数字传输系统

笔记&#xff1a; 针对这一节的内容&#xff0c;我为您提供一个笔记的整理方法。将内容按重要性、逻辑关系进行组织&#xff0c;再进行简化。 ## 2.5 数字传输系统 ### 背景介绍&#xff1a; 1. **早期电话网**&#xff1a;市话局到用户采用双绞线电缆&#xff0c;长途干线采…

css的gap设置元素之间的间隔

在felx布局中可以使用gap来设置元素之间的间隔&#xff1b; .box{width: 800px;height: auto;border: 1px solid green;display: flex;flex-wrap: wrap;gap: 100px; } .inner{width: 200px;height: 200px;background-color: skyblue; } <div class"box"><…

【Unity】RenderFeature笔记

【Unity】RenderFeature笔记 RenderFeature是在urp中添加的额外渲染pass&#xff0c;并可以将这个pass插入到渲染列队中的任意位置。内置渲染管线中Graphics 的功能需要在RenderFeature里实现,常见的如DrawMesh和Blit ​ 可以实现的效果包括但不限于 后处理&#xff0c;可以编写…

访问控制、RBAC和ABAC模型

访问控制、RBAC和ABAC模型 访问控制 访问控制的目的是保护对象&#xff08;数据、服务、可执行应用该程序、网络设备或其他类型的信息技术&#xff09;不受未经授权的操作的影响。操作包括&#xff1a;发现、读取、创建、编辑、删除和执行等。 为实现访问控制&#xff0c; 计…

JavaScript系列从入门到精通系列第十六篇:JavaScript使用函数作为属性以及枚举对象中的属性

文章目录 前言 1&#xff1a;对象属性可以是函数 2&#xff1a;对象属性函数被称为方法 一&#xff1a;枚举对象中的属性 1&#xff1a;for...in 枚举对象中的属性 前言 1&#xff1a;对象属性可以是函数 对象的属性值可以是任何的数据类型&#xff0c;也可以是函数。 v…

linux系统中常见注册函数的使用方法

大家好&#xff0c;今天给大家分享一下&#xff0c;linux系统中常见的注册函数register_chrdev_region()、register_chrdev()、 alloc_chrdev_region()的使用方法​。 一、函数包含的头文件&#xff1a; 分配设备编号&#xff0c;注册设备与注销设备的函数均在fs.h中申明&…

mac文件为什么不能拖进U盘?

对于Mac用户来说&#xff0c;可能会遭遇一些烦恼&#xff0c;比如在试图将文件从Mac电脑拖入U盘时&#xff0c;却发现文件无法成功传输。这无疑给用户带来了很大的不便。那么&#xff0c;mac文件为什么不能拖进U盘&#xff0c;看完这篇你就知道了。 一、U盘的读写权限问题 如果…

[Python入门教程]01 Python开发环境搭建

Python开发环境搭建 本文介绍python开发环境的安装&#xff0c;使用anaconda做环境管理&#xff0c;VS code写代码。搭建开发环境是学习的第一步&#xff0c;本文将详细介绍anaconda和vs code的安装过程&#xff0c;并测试安装结果。 视频教程链接&#xff1a;https://www.bil…

localhost和127.0.0.1都可以访问项目,但是本地的外网IP不能访问

使用localhost和127.0.0.1都可以访问接口&#xff0c;比如&#xff1a; http://localhost:8080/zhgl/login/login-fy-list或者 http://127.0.0.1:8080/zhgl/login/login-fy-list返回json {"_code":10000,"_msg":"Success","_data":…

毛玻璃用户卡交互

效果展示 页面结构组成 从效果展示可以看到&#xff0c;此效果都是比较常规的。主要的核心就是卡片的悬停效果。 CSS 知识点 backdrop-filter 回顾transitiontransform 页面基础布局实现 <section><div class"container"><div class"card&q…

基于虚拟阻抗的下垂控制——孤岛双机并联Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

回顾C++

大一的时候学过C&#xff0c;当时学得也不深&#xff0c;考试也是糊弄过去的&#xff0c;最近刷力扣的时候&#xff0c;决定一边刷题&#xff0c;一边复习和学习C&#xff0c;在此记录一些C的知识点。反正遇到一点就记录一点&#xff0c;会一直更新。

jwt的基本介绍

说出我的悲惨故事给大家乐呵乐呵&#xff1a;公司刚来了一个实习生&#xff0c;老板让他写几个接口给我&#xff0c;我页面还没画完呢。他就把接口给我了&#xff0c;我敲开心&#xff0c;第一次见这么高效率的后端。但我很快就笑不出来了。他似乎不知道HTTP通信是无状态的。他…

深入解读redis的zset和跳表【源码分析】

1.基本指令 部分指令&#xff0c;涉及到第4章的api&#xff0c;没有具体看实现&#xff0c;但是逻辑应该差不多。 zadd <key><score1><value1><score2><value2>... 将一个或多个member元素及其score值加入到有序集key当中。根据zslInsert zran…

手把手教你开发律师法律咨询小程序

随着科技的快速发展&#xff0c;移动互联网已经成为人们获取信息和服务的主要途径之一。对于律师和法律机构来说&#xff0c;开发一个律师法律咨询小程序&#xff0c;可以更好地满足用户的需求&#xff0c;提供便捷的法律咨询服务。本文将引导您如何使用乔拓云网这个第三方制作…

Jmeter控制RPS

一、前言 ​ RPS (Request Per Second)一般用来衡量服务端的吞吐量&#xff0c;相比于并发模式&#xff0c;更适合用来摸底服务端的性能。我们可以通过使用 JMeter 的常数吞吐量定时器来限制每个线程的RPS。对于RPS&#xff0c;我们可以把他理解为我们的TPS&#xff0c;我们就不…