IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS官方瘦身方案ODR(二):换肤系统改造|践行 On-Demand Resources -> 正文阅读

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

👋

我的个人项目扫雷Elic 无尽天梯梦见账本
类型游戏财务
AppStoreElicUmemi

前言

如果你还不太清楚 ODR: On-Demand Resources 是什么,可以看看Apple官方资源瘦身方案ODR(一):初见

既然知道了 ODR 能干什么了,那就拿自己的项目开个刀。
这里使用我的个人项目梦见账本,由于项目中有多套皮肤可以更换,所以存了很多套图标,这些图标就很适合使用 ODR 来优化。

关于 ODR 除了官方文档,也没找到很多实践的资料,这里就结合文档,手摸手和大家一起来实践一波吧。

先来个卖家秀

使用 ODR 之前

请添加图片描述

使用 ODR 之后!

请添加图片描述

一、 启用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 installPrefetch 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
public init(tags: Set<String>, bundle: Bundle)

检查状态

检查请求的标签的资源是否全部都已经在设备中保存了。

open func conditionallyBeginAccessingResources(completionHandler: @escaping (Bool) -> Void)

开始请求资源

请求不在本地的标签资源。

open func beginAccessingResources(completionHandler: @escaping (Error?) -> Void)

六、改造「梦见账本」

6.1 封装 OdrTool

protocol OdrTagProtocol {
    var tagName: String { get }
}

struct OdrTool {
    static func requestODR(of tags: OdrTagProtocol..., in bundle: Bundle = Bundle.main) {
        var tagsSet: Set<String> = []
        tags.forEach { tagsSet.insert($0.tagName) }
        let request = NSBundleResourceRequest(tags: tagsSet, bundle: bundle)
        request.conditionallyBeginAccessingResources { hasCache in
            if hasCache == false {
                // 这些资源不全在本地
                request.beginAccessingResources { error in
                    if let _ = error {
                        // 下载失败
                    }
                    else {
                        // 下载成功
                    }
                }
            }
            else {
                // 这些资源已经在本地了
            }
        }
    }
}

6.2 为皮肤系统 AppearanceStyle 拓展 Odr

AppearanceStyle 是真个换肤系统的核心,主体是一个 枚举

  • 这里让原先的皮肤都匹配一下自己的标签名就好了。
  • 然后添加一个 reloadOdr 方法来更新当前两个皮肤的 ODR
extension AppearanceStyle: OdrTagProtocol {
    static func reloadOdr() {
        OdrTool.requestODR(of: currentLightStyle, currentDarkStyle)
    }
    
    var tagName: String {
        switch self {
        case .Charge, .ChargeMain:
            return "Charge"
        case .ChargeLight:
            return "ChargeLight"
        case .Eternal, .Hachimitsu:
            return "Eternal"
        case .Spark:
            return "Sakura"
        case .SparkMain:
            return "Spark"
        case .NYXL:
            return "NYXL"
        case .Justice, .Dream, .Phoenix:
            return "Justice"
        case .Kiwi:
            return "Kiwi"
        case .Banshee:
            return "Banshee"
        case .Punk:
            return "Punk"
        }
    }
}

6.3 在合适节点更新Odr资源

节点一:应用启动

AppearanceStyle.reloadOdr()

节点二:设置皮肤

static func reloadApp() {
    guard let tabVC = UIStoryboard(name: "Home", bundle: nil).instantiateInitialViewController() else {
        return
    }
    UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController = tabVC
    reloadOdr()
}

6.4 运行项目,检查效果

Xcode 中显示我设置的两个皮肤的资源已经下载完成了。
请添加图片描述

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

请添加图片描述

6.5 解决问题

通过之前的了解,如果 ODR 资源没有被任何 NSBundleResourceRequest 使用的话就会被清理。而上面的封装并没有持有 NSBundleResourceRequest。对代码进行一下调整。

OdrTool

struct OdrTool {
    static func requestODR(of tags: OdrTagProtocol..., in bundle: Bundle = Bundle.main) -> NSBundleResourceRequest {
        ...
        let request = NSBundleResourceRequest(tags: tagsSet, bundle: bundle)
        ...
        // 把 NSBundleResourceRequest 抛出
        return request
    }
}

AppearanceStyle

extension AppearanceStyle: OdrTagProtocol {
    // 添加一个静态变量保存
    static var odrRequest: NSBundleResourceRequest?
    
    static func reloadOdr() {
        odrRequest = OdrTool.requestODR(of: currentLightStyle, currentDarkStyle)
    }
    
    var tagName: String {
        switch self {
            ...
        }
    }
}

6.6 检查修改后的效果

完美~ 又测了下切换皮肤的功能也是没问题的

请添加图片描述

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

请添加图片描述

6.7 使用资源的地方需要改动么?

不用

七、 总结

体验下来还是很顺滑的,感觉接入成本不高。个人项目自己比较熟,而且换肤体系封的比较好😜也为接入 ODR 带来了很大便利。而且我单个皮肤的资源只有 2M 左右下载也挺快。

如果是一些较大的资源加载可能就不能像我处理的这么简单了。而且 NSBundleResourceRequest 还有很多设置我没用,想深入了解的可以看下官方文档,这里我就抛个砖🧱。

而且任何优化方案的选择还是要结合实际项目来,能一股脑照搬的方案是不存在的。苹果的这个 ODR 挺好的,却感觉一直没有进入到广大 iOSer 的视野中,感觉挺可惜,如果感觉合适你的项目真的可以用起来哦~

参考

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 11:53:22  更:2021-09-09 11:55:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:32:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码