iOS 官方瘦身方案 ODR(二):换肤系统改造|践行 On-Demand Resources

👋
前言
如果你还不太清楚
ODR: On-Demand Resources
是什么,可以看看https://xie.infoq.cn/article/084b0c7e826e6572a881ed128
既然知道了 ODR
能干什么了,那就拿自己的项目开个刀。
这里使用我的个人项目梦见账本,由于项目中有多套皮肤可以更换,所以存了很多套图标,这些图标就很适合使用 ODR
来优化。
关于 ODR
除了官方文档,也没找到很多实践的资料,这里就结合文档手摸手一起来实践一波吧。
先来个卖家秀
使用 ODR
之前

使用 ODR
之后!

TestFlight
上看的大小,不过和真实下载的不会有多少差别。
一、 启用 ODR

从
iOS9
开始就是默认开启的了
二、 创建标签
标签用于识别和管理一组 ODR
。将一个或多个标签分配给项目中的资源可将其标识为 ODR
。在运行时,所有 ODR
的访问都与标签(而非单个资源)配合工作。
在 Target 的 Resource tags 可以看到添加标签的入口,这里可以选择项目中的资源,以添加到标签下。

项目之前的资源组织方式:

这里为了方便标签管理,进行一下资源包的拆分:

2.1 为 Assets 添加标签
将 Assets
添加到 Tag 下:


2.2 确认资源标签设置成功
打开资源包查看资源信息,就可以看到这里匹配的资源标签了。(一个资源可以设置多个标签)

在构建项目时,Xcode
会检查项目中的所有标记项目,并生成供操作系统使用的资源包。
2.3 为单个资源快速添加标签
也可以通过直接输入联想,快速为单个资源添已有标签,或者快速创建一个标签。

三、 标签分类
通过切换到 Prefetched
我们看到了三种分类:

创建的标签的默认类别是仅按需下载ODR
。标签可以在类别之间拖动。
***Initial install tags. ***
资源与应用程序同时下载。资源的大小包含在应用商店中应用的总大小中。当没有任何
NSBundleResourceRequest
访问时,可能会被清除。***Prefetch tag order. ***
安装应用后,资源开始下载。按标签顺序下载。
***Dowloaded only on demand. ***
按需加载。当应用请求时,将下载这些标签。
当操作系统下载标签时,它只会下载设备上没有的资源。
3.1 设置标签分类
设置标签分类很简单,从默认的 ODR 列表中拖到相应的分类下即可。
这里我把默认的两个皮肤的资源设置为:Initial install

四、 大小限制
应用剪切后,标签中资源的总大小不得超过 512 MB
。应用商店中存储的按需资源的总大小不得超过 20 GB
。
标签的理想大小不大于 64 MB
。此大小在下载速度和本地存储之间提供了良好的平衡,以便在设备的本地存储处于低位时可以清除。

Slicing.
复选标记(✓)表示大小反映的是应用剪切后的大小。
App bundle.
下载到设备的剪切后的应用程序包的大小。
Asset packs.
资产包由 Xcode 生成。
***Initial install tags. ***
标记为初始安装的标记的总剪切后的大小。
***Initial install and prefetched tags.. ***
标记为
Initial install
和Prefetch tag
的资源剪切后的总大小***In use on-demand resources. ***
一次行最多可用
ODR
的剪切后的大小。***Hosted on-demand resources. ***
所有
ODR
大小,不剪切的大小。
五、 管理 ODR
配置了标签后,直接运行项目。可以看出所有的 ODR
资源均没有下载。

5.1 ODR 更新时机确定
这里先描述下 梦见账本
的换肤逻辑,来帮助确定 ODR 的更新时机:
皮肤分为两种模式:普通模式、暗黑模式。
即:用户可以为两种模式分别设置皮肤,切换系统暗黑模式开关即可无缝切换
设置皮肤后会重新设置根控制器
这里是需要更新 ODR 的一个节点
另一个检查更新的节点是应用启动的时候
检查当前的两种皮肤,准备相关标签的资源
5.1 NSBundleResourceRequest 请求资源
一个标签可以被多个实例管理,下面列举三个重要的 API
。
初始化
tags: 标签集合
bundle: 一般是 main
检查状态
检查请求的标签的资源是否全部都已经在设备中保存了。
开始请求资源
请求不在本地的标签资源。
六、改造「梦见账本」
6.1 封装 OdrTool
6.2 为皮肤系统 AppearanceStyle 拓展 Odr
AppearanceStyle
是真个换肤系统的核心,主体是一个 枚举
。
这里让原先的皮肤都匹配一下自己的标签名就好了。
然后添加一个
reloadOdr
方法来更新当前两个皮肤的ODR
6.3 在合适节点更新 Odr 资源
节点一:应用启动
节点二:设置皮肤
6.4 运行项目,检查效果
Xcode
中显示我设置的两个皮肤的资源已经下载完成了。

但是打开 App,发现还是空白?

6.5 解决问题
通过之前的了解,如果 ODR 资源没有被任何 NSBundleResourceRequest
使用的话就会被清理。而上面的封装并没有持有 NSBundleResourceRequest
。对代码进行一下调整。
OdrTool
AppearanceStyle
6.6 检查修改后的效果
完美~ 又测了下切换皮肤的功能也是没问题的

再看 Xcode
发现,标签的状态不一样了,两个正在使用中的标签成了 In use
正在使用。

6.7 使用资源的地方需要改动么?
不用
七、 总结
体验下来还是很顺滑的,感觉接入成本不高。个人项目自己比较熟,而且换肤体系封的比较好😜也为接入 ODR 带来了很大便利。而且我单个皮肤的资源自由 2M
左右下载也挺快。如果是一些较大的资源加载可能就不能像我处理的这么简单了。而且 NSBundleResourceRequest
还有很多设置我没用,想深入了解的可以看下官方文档,这里我就抛个砖🧱。
而且任何优化方案的选择还是要结合实际项目来,能一股脑照搬的方案是不存在的。苹果的这个 ODR
挺好的,却感觉一直没有进入到广大 iOSer
的视野中,感觉挺可惜,如果感觉合适你的项目真的可以用起来哦~
参考
版权声明: 本文为 InfoQ 作者【Ryukie】的原创文章。
原文链接:【http://xie.infoq.cn/article/0675fdcaf9ef6b8a0c1b22122】。文章转载请联系作者。
评论