当前位置: 首页 > news >正文

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 = 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_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_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 来实现最终的灵活性。现在,您可以让用户将自己独特的风格注入到您的应用程序图标中,而不会迷失在代码杂草中。@[toc](Android 中的动态应用程序图标)

相关文章:

  • 蓝桥杯练习题-图书ISBN号码
  • 低代码与人工智能:实现智能化办公的利器
  • 糊涂工具包使用 记录
  • 空间域:空间组学的耶路撒冷
  • 网络安全知识和华为防火墙
  • 手机壳也能散热了?
  • 使用 create-react-app 创建 react 应用
  • 关机恶搞小程序
  • input框不能输入
  • 代码随想录算法训练营第35天 | 860.柠檬水找零 + 406.根据身高重建队列 + 452.用最少数量的箭引爆气球
  • [GN] 设计模式——面向对象设计原则概述
  • 【游戏服务器部署】幻兽帕鲁服务器一键部署保姆级教程,游戏私服还是自己搭建的香
  • 全球工控大佬
  • 基于 NXP S32K311 评估板的方案
  • 网站打不开怎么办?高防IP弹性防护更省心
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Apache的基本使用
  • Computed property XXX was assigned to but it has no setter
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • css属性的继承、初识值、计算值、当前值、应用值
  • emacs初体验
  • Fundebug计费标准解释:事件数是如何定义的?
  • Hibernate最全面试题
  • Java面向对象及其三大特征
  • MySQL-事务管理(基础)
  • Netty源码解析1-Buffer
  • Nodejs和JavaWeb协助开发
  • PHP 7 修改了什么呢 -- 2
  • Python连接Oracle
  • SpiderData 2019年2月16日 DApp数据排行榜
  • vue 个人积累(使用工具,组件)
  • 阿里云购买磁盘后挂载
  • 测试开发系类之接口自动化测试
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 第十八天-企业应用架构模式-基本模式
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 扑朔迷离的属性和特性【彻底弄清】
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 移动端 h5开发相关内容总结(三)
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • # 计算机视觉入门
  • #NOIP 2014# day.2 T2 寻找道路
  • #stm32驱动外设模块总结w5500模块
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $.ajax()方法详解
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (AngularJS)Angular 控制器之间通信初探
  • (C#)一个最简单的链表类
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (四)Linux Shell编程——输入输出重定向
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (转)全文检索技术学习(三)——Lucene支持中文分词