双十一来了,给自己的应用做个icon换脸小功能
/ 今日科技快讯 /
近日,蚂蚁集团发布首次公开发行股票并在科创板上市发行公告,发行人和联席主承销商根据初步询价结果,协商确定本次发行价格为68.80元/股,公司股票代码688688。A+H股IPO拟募集约345亿美元。以发行价计算,蚂蚁集团市值已经超过贵州茅台。
/ 作者简介 /
本篇文章来自椎锋陷陈的投稿,和大家分享了一个给app自动换图标的功能,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章!
椎锋陷陈的博客地址:
https://www.jianshu.com/u/9bfd80e684ad
/ 前言 /
也许你也注意到了,在临近双11之际,手机上电商类APP的应用图标已经悄无声息换成了双11专属图标,比如某宝和某东:
可能你会说,这有什么奇怪的,应用市场开启自动更新不就可以了么?
真的是这样吗?
为此,我特意查看了我手机上的某宝APP的当前版本,并对比了历史版本上的图标,发现并不对应。
/ 知识储备 /
<activity-alias>
某一个Activity 的别名,用于实例化该目标Activity。目标必须与别名在同一应用中,并且在清单中必须在别名之前进行声明。
介绍下几个重要的属性:
android:enabled:必须设为“true”,系统才能通过别名实例化目标 Activity
android:icon:通过别名呈现给用户时目标 Activity 的图标。
android:name:别名的唯一名称。与目标 Activity 的名称不同,别名名称是任意的,它不引用实际类。
android:targetActivity:可通过别名激活的 Activity 的名称。
PackageManager#setComponentEnabledSetting
可以利用 PackageManager 在清单文件中所定义的任何组件上切换启用状态,包括您想启用或停用的任何一个Activity。
有了以上知识储备后,下面就该剖析一下这个需求的具体场景了。
/ 场景剖析 /
以电商类APP双11活动为例,在双11活动开始前的某个时间点(比如10天前)就要开始对活动的预热,此时就要实现图标的自动更换,而在活动结束之后,也必须要能更换回正常图标,并且要求过程尽量对用户无感知,更不能影响用户对APP的正常使用。
具体拆分成要实现的功能点便是:图标更换、自动操作、用户无感知。
/ 方案实现 /
1.图标更换:禁用Launcher组件,启用Alias组件,并将targetActivity指向原先的Launcher组件。
2.自动操作:指定日期转换为时间戳,并与当前时间戳对比,超过预设时间则执行替换操作。
3.用户无感知:尽量选择APP不活跃的阶段的,比如切换应用/回到桌面时。
/ 代码实现 /
首先,我们需要在AndroidManifest清单文件中添加<activity-alias>元素,默认为禁用状态,name属性作为我们找到此组件的唯一标志,而icon属性即是我们要替换的图标资源,并通过targetActivity属性将作为LANCHUER的SplashActivity作为实例化的目标 Activity:
<activity android:name=".SplashActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity><!--88会员节专属Activity别名-->
<activity-aliasandroid:name=".SplashAliasActivity"android:enabled="false"android:icon="@mipmap/ic_launcher_88"android:targetActivity=".SplashActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity-alias><!--双11专属Activity别名-->
<activity-aliasandroid:name=".SplashAlias2Activity"android:enabled="false"android:icon="@mipmap/ic_launcher_11_11"android:targetActivity=".SplashActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity-alias>
随后,我们图标替换的工作视作一项任务,定义一个数据类:
/*** 切换图标任务*/
data class SwitchIconTask (val launcherComponentClassName: String, // 启动器组件类名val aliasComponentClassName: String, // 别名组件类名val presetTime: Long, // 预设时间val outDateTime: Long) // 过期时间
定义一个LauncherIconManager单例,负责图标更换相关的工作。开放添加图标切换任务的接口,做好参数合法性的校验:
/*** 启动器图标管理器*/
object LauncherIconManager {/** 切换图标任务Map */private val taskMap: LinkedHashMap<String, SwitchIconTask> = LinkedHashMap()/*** 添加图标切换任务* @param newTasks 新任务,可以传多个*/fun addNewTask(vararg newTasks: SwitchIconTask) {for (newTask in newTasks) {// 防止重复添加任务if (taskMap.containsKey(newTask.aliasComponentClassName)) return// 校验任务的预设时间和过期时间for (queuedTask in taskMap.values) {if (newTask.presetTime > newTask.outDateTime) throw IllegalArgumentException("非法的任务预设时间${newTask.presetTime}, 不能晚于过期时间")if (newTask.presetTime <= queuedTask.outDateTime) throw IllegalArgumentException("非法的任务预设时间${newTask.presetTime}, 不能早于已添加任务的过期时间")}taskMap[newTask.aliasComponentClassName] = newTask}}...
}
LauncherIconManager.addNewTask(SwitchIconTask(SplashActivity::class.java.name,"$packageName.SplashAliasActivity",format.parse("2020-08-02").time,format.parse("2020-08-09").time),SwitchIconTask(SplashActivity::class.java.name,"$packageName.SplashAlias2Activity",format.parse("2020-11-05").time,format.parse("2020-11-12").time)
)
通过Application#registerActivityLifecycleCallbacks方法注册了对应用内Activity生命周期的监听,通过是否有活跃状态的Activity判断应用是否进入了后台:
/*** 应用运行状态注册器*/
object RunningStateRegister {fun register(application: Application, callback: StateCallback) {application.registerActivityLifecycleCallbacks(object : SimpleActivityLifecycleCallbacks() {private var startedActivityCount = 0override fun onActivityStarted(activity: Activity) {if (startedActivityCount == 0) {callback.onForeground()}startedActivityCount++}override fun onActivityStopped(activity: Activity) {startedActivityCount--if (startedActivityCount == 0) {callback.onBackground()}}})}}
class BaseApplication : Application() {override fun onCreate() {super.onCreate()LauncherIconManager.register(this)}
}
判断应用进入后台后,就可以开始对图标的更换工作了:
/*** 启动器图标管理器*/
object LauncherIconManager {.../*** 注册以监听应用运行状态*/fun register(application: Application) {RunningStateRegister.register(application, object: RunningStateRegister.StateCallback{override fun onForeground() {}override fun onBackground() {proofreadingInOrder(application)}})}/*** 依次校对预设时间* @param context 上下文*/fun proofreadingInOrder(context: Context) {for (task in taskMap.values) {if (proofreading(context, task)) break}}/*** 校对预设时间/过期时间* @param context 上下文* @return true 已过预设时间 false 未达预设时间或已过期*/private fun proofreading(context: Context, task: SwitchIconTask) =when {isPassedOutDateTime(task) -> {disableComponent(context, ActivityUtil.getLauncherActivityName(context)!!)enableComponent(context, task.launcherComponentClassName)false}isPassedPresetTime(task) -> {disableComponent(context, ActivityUtil.getLauncherActivityName(context)!!)enableComponent(context, task.aliasComponentClassName)true}else -> false}/*** 是否已超过预设时间* @param task 任务*/private fun isPassedPresetTime(task: SwitchIconTask) =System.currentTimeMillis() > task.presetTime/*** 是否已超过过期时间* @param task 任务**/private fun isPassedOutDateTime(task: SwitchIconTask) =System.currentTimeMillis() > task.outDateTime...
}
以上代码均已上传到GitHub。核心的类都封装到Library模块了,并提供Demo模块演示如何使用。如果觉得项目不错的话点个Star吧~
GitHub地址:
https://github.com/madchan/LauncherIconLib
/ 代码实现 /
通过以上构建的方案,便可让我们的APP在预设的时间点实现对应用图标的自动替换,缺点是只能加载随APK打包的图片资源,适用于运营活动时间相对固定的的场景。
参考官网文章:
https://developer.android.google.cn/guide/topics/manifest/activity-alias-element
推荐阅读:
我的新书,《第一行代码 第3版》已出版!
分享我成为GDE(Google开发者专家)的经历
萌新面试经,赶紧来看看!
欢迎关注我的公众号
学习技术或投稿
长按上图,识别图中二维码即可关注
双十一来了,给自己的应用做个icon换脸小功能相关推荐
- 用 UE 虚幻引擎做个捏脸小功能~~
最近在学习 UE 相关的使用,正好看到一篇文章讲解用 Control Rig 实现简单捏脸功能,这种小而美的完整案例挺适合来练手的,涉及到了 UI.蓝图.动画.骨骼等方面,值得推荐一下. 从这个小功能 ...
- 1小时教你做360度全景“小星球”效果图 Skillshare – Create a Panoramic ‘Little Planet’ from Anywhere
1小时教你做360度全景"小星球"效果图 Skillshare – Create a Panoramic 'Little Planet' from Anywhere 1小时教你做3 ...
- C#做的在线升级小程序
转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...
- 使用vue-cli+element-ui+expsess+mysql做一个简易的登录功能
使用vue-cli+element-ui+expsess+mysql做一个简易的登录功能 1使用webpack下载vue模板 vue init webpack aaa(aaa为项目名称) cd到aaa ...
- 用c语言简单办法做一个字典_幼儿园手工,用废纸筒做一个简单的小蝴蝶,有教程...
幼儿园的手工,除了用卡纸做各种简单的小制作外,纸筒也是常用的手工材料. 下面用纸筒做一个简单的小蝴蝶,做法很简单. 制作过程: 准备材料 废纸筒.剪刀.胶.水彩笔,纸板. 在纸筒上剪下五个圈圈 剪完的 ...
- 社区团购怎么做_分享有哪些方法可以做社区团购小程序
今天我们要分享的是社区团购,那么有的小伙伴就会问了什么是社区团购呢,我们简单的来说下社区团购是一种新型的团购模式,刚开始主要是通过团长搭建社群来发布相应的优惠活动,然后吸引用户下单,最后由团长进行订单 ...
- python开发跟淘宝有关联微_为什么微商和淘宝卖家不得不做公众号和小程序?
文/王爷 整理/叨叨 最近一个月,微信方面的动作比较多,尤其是有关微信小程序方面的动态,起码更新了4次.或许很多人还不知道什么是微信小程序,简单来说就是一个无需安装.即用即走的生长在微信上的一个应用. ...
- 用 typescript 做一个贪吃蛇小游戏
typescript 做一个贪吃蛇小游戏 搭建环境 创建 tscofig.json 文件 配置如下 {"compilerOptions": {"target": ...
- 美食类短视频怎么做?几个小方法来帮忙,简单很好学
美食类短视频怎么做?几个小方法来帮忙,简单很好学 民以食为天,尤其是在当今时代,因为疫情的影响,很多人宅在家里刷短视频,也大多会对美食类短视频更加的感兴趣,毕竟闲来无事在家,不能出门享受美食,自己跟着 ...
最新文章
- Arrays练习:字符串倒序排列
- Android API 中文(77)——AdapterView.OnItemSelectedListener
- xx Chrome浏览器更新2020版本:黑暗模式一样使用
- lombok之@NoArgsConstructor、@AllArgsConstructor和@Data注解
- 【模糊滑模】基于模糊切换增益调节的滑模控制
- RedisTemplate 常用方法、序列化方式、基于 Redis 实现分布式锁
- Sketch 52.2 轻量易用的矢量设计工具(下载) Sketch汉化
- PVE直通Intel核显虚拟机配置ffmpeg-qsv硬件加速
- Unable to read entire header; 80 bytes read; expected 512 bytes
- 单细胞测序——基本知识
- Python自动化体系学习思维导图、知识点整理
- 声纹识别demo_语音识别、声纹识别的区别及测试
- 【数据库】MySQL 加锁处理分析
- 纯js版本网页连连看原理分析和实现
- SPSS多元线性回归残差分析的基本方法
- 关于new Map()
- 云效x钉钉:让研发工作更简单
- 带你了解网络解说--链路聚合技术
- 大数据 Hadoop 生态体系介绍
- C程序---编程统计候选人得票数