美文网首页
Android 在线更新APP icon技术调研

Android 在线更新APP icon技术调研

作者: Brook_liu | 来源:发表于2021-04-06 16:37 被阅读0次

需求描述

当前app的桌面icon没法实现在线静默更换,为了满足节假日运营需求,现在必须通过发布新版本的方式才能更新appicon。所以希望app能实现在线静默更新appicon。

具体要求

目前来看app对于icon的更新频次并不高,并且运营需求也相对简单不复杂。所以,app预置一到两个版本的icon,并在特定的时间静默生效就能满足基本的需求。

技术原理

在AndroidManifest.xml中增加<activity-alias>标签,在代码中通过PackageManager的setComponentEnabledSetting方法来动态打开enabled属性从而显示对应icon。

官方API说明:

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

https://developer.android.google.cn/reference/android/content/pm/PackageManager?hl=en#setComponentEnabledSetting(android.content.ComponentName,%20int,%20int)

实现

  1. 在AndroidManifest.xml中声明<activity-alias>,配置文件里面可以声明多个<activity-alias>,也就对应多个icon。
<activity-alias
android:name=".MainActivity1"
android:enabled="false"
android:icon="@mipmap/icon_1"
android:label="@string/app_name"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>

属性enabled默认为false,在为true时,桌面就会显示图标icon_1,如果没有关闭主icon的话,桌面就会出现两个icon。

而<intent-filter>的作用就和activity组件是一样的,<activity-alias>虽然不是真身,但是也可以当作activity组件。所以这里也需要桌面启动的<intent-filter>。

2. 动态切换icon的代码

private void changeLauncher(String name) {

PackageManager pm = getPackageManager();

 //隐藏之前显示的桌面组件

 pm.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

 //显示新的桌面组件
 
pm.setComponentEnabledSetting(new ComponentName(MainActivity.this, name), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); }

都是调用PackageManager的setComponentEnabledSetting方法,第一个参数表示操作的组件是哪个,第二个参数表示显示还是隐藏,第三个组件表示是否关掉app。

说明

从官方文档以及相关资料来看,该技术有以下几点需要注意

  1. 该技术只能通过内置icon来实现替换,无法从服务器获取来更新icon。
  2. targetActivity 目标必须与别名在同一应用中,并且在清单中必须在别名<activity-alias>之前进行声明。
  3. setComponentEnabledSetting在执行切换的时候,系统会杀掉app进程。所以不适合app在前台时执行切换逻辑。

存在的坑

结合自己测试以及相关资料来看主要是覆盖安装存在较多的坑。

参考资料:

https://zhuanlan.zhihu.com/p/151781520

https://juejin.cn/post/6844903758971797518

已测场景:

如果9.0当前已切换到A活动icon,新版本9.1没有9.0 A活动icon对应的alias,存在图标消失或者打不开应用的情况(不同机型表现可能不一样)。

9.0当前已切换到A活动icon,新版本9.1仍然存在9.0 A活动icon对应的alias,但是默认关闭,默认打开B活动icon对应的alias。安装结果:桌面还是9.0的A活动icon,可以正常打开。

当前9.0是主icon,新版本9.1默认打开A活动icon,安装结果还是9.0的主icon。

当前版本9.0切换到A活动icon后,用户没有打开过app,这时候更新为新版本9.1,新版本有9.0 A活动icon对应的alias,不过没有打开enabled,结果:这种情况桌面图标还是A活动icon,也能正常打开应用。

当前版本9.0切换到A活动icon后,升级新版本9.1,不过9.1版本A活动对应的alias已经把icon替换成新的B活动icon,结果:安装成功,桌面显示活动B的icon,正常打开。

结论:

通过<activity-alias>内置icon这种方式来实现动态切换icon的话,新版本就必须一直保留对应<activity-alias>,要不然就存在图标消失或者打不开的情况。

解决措施:

  1. 按照增量方式增加<activity-alias>来增加一套活动icon:

需要注意的点,增加一套icon图相应的会增加资源,从而会增加包体积,并且需要永远去考虑市场上已有的版本已经存在的<activity-alias>。

结合Android的icon标准来看,一套icon图4848 =2.18kB, 7272 = 3.53kB, 9696= 5.1kB, 144144= 5.57KB, 总共16.38KB < 20KB。

2. 固定一到两个<activity-alias>不变,只在新版本中替换icon资源,通过版本管理来控制不同版本生效切换。(综合来看,此方案后台版本管理复杂点,但是客户端风险更小。)

初步方案设计

  1. 后台配置策略

后台控制客户端不同版本的生效标志,客户端不同版本获取不同的标志(比如,生效icon:A,B,C)并存在本地,待下次拉取到最新配置后,更新到本地缓存。

  1. 前端无感生效策略。

如何才能无感更新?所以必须用户没有操作app,并且用户没有关注桌面。

最佳更新时机,就是app在后台并且灭屏后启动切换。如果用户亮屏或者app回到前台就取消暂停切换。不过不在乎体验的话,就可以在app置后台后直接延时几十秒触发切换,这种情况用户可能看到,而且可能用户正在交易页面,短暂置后台,等他回来操作时就不在了,可能影响用户体验。

判断app是否在后台的技术实现:

依赖已有的activity生命周期监听接口ActivityLifecycleCallbacks去判断app是否在后台。只要有一个activity回调了resume,那就肯定在前台。所以只要在pause回调时延迟一段时间去判断是否有resume去更新了标志位。这样就可以判断pause回调时是不是置后台还是跳转acitivity。

市场主流app情况调研:

下载了天猫,淘宝,抖音,拼多多,支付宝,京东apk,直接解压查看了AndroidManifest.xml问题,发现它们都没有在配置文件中定义<activity-alias>,比对了同一个app的多个版本也没有发现声明此标签。

在豌豆荚网站查看淘宝的历史版本来看,发布的版本较多,并且具备活动icon的版本也是新版本。

屏幕快照 2021-01-29 17.07.42.png

比对了淘宝9.17.0,9.18.0,9.20.0三个版本。

发现它们的AndroidManifest文件中都没有定义<activity-alias>。而且资源文件中对应桌面icon都是同名但不同资源。这说明淘宝app是通过发布新版本来更新它的桌面icon。

image2021-1-29_17-12-1.png image2021-1-29_17-12-15.png image2021-1-29_17-12-35.png

调研结论:

动态切换icon的技术不难,但是由于存在版本升级和不同版本管理的坑,存在一定的风险并且需要付出更多控制风险的成本,实际带来效益也并不高。结合主流app的情况来,完全依赖发布新版本来切换icon也能满足需求,并且成本和风险都更小。

相关文章

网友评论

      本文标题:Android 在线更新APP icon技术调研

      本文链接:https://www.haomeiwen.com/subject/aovtkltx.html