trime icon indicating copy to clipboard operation
trime copied to clipboard

[Development Discuss] Look up an appropriate way to verify and update assets

Open WhiredPlanck opened this issue 3 years ago • 10 comments

主题描述 / Topic Descriptions

寻找合理的方式验证和更新预带的资源文件(assets 目录中的文件)。

目前同文对于资源文件的更新方式是:

  1. 手动更新(原地修改)文件;
  2. 提高版本号;
  3. 在应用启动后的一段时间内,先判断安装的版本和上一个版本是否相同,是则不更新/覆盖,否则强制更新/覆盖。

这样的机制简单、粗暴但有效,但我觉得还能改进(虽然会有变复杂的可能),上面这个方法主要有两点不足:

  1. 只能新增和更新文件,一旦日后有改名、删除等情况就会混杂;
  2. 无论新旧版本的资源内容是否实际相同,一旦比较到版本号不同,都得重新复制一次,“抠门”地说这样比较“浪费”;

私认为,虽然资源内容的变化常常是跟随着版本号的变化的,但是比较符合直觉的做法可能是去验证和比较文件是否相同,不同时才需要更新文件。

可能的解决方案 / Potential Solutions

基于上述陈述,相比较文件版本不同或有无变化,那么自然而然可以想到比较文件的哈希值(即 SHA1、SHA256 或 SHA512 等)。并且目前有一个存在的参考案例: fcitx5-android 的 build.gradle.kts

简单概括下 fcitx5-android 的这个方法,即在构建 APK 时验证各个资源文件的 SHA256 值,并记载到一份 JSON 描述文件里,在应用安装后同步文件前,比较 JSON 描述文件的哈希值,如果相同,则无需更新文件,否则:如果新的描述文件登记了新的条目,则匹配“新增”枚举值,其负责复制文件;如果有一样的条目值,比较他们的 SHA256,相同则不用更新,不同则匹配“更新”枚举值,其下负责更新(强制覆盖)文件;如果没有登记有旧版登记的文件,则匹配“删除”枚举值,其下负责删除对应的旧版文件。

这种方法我认为足够科学,体现了“非必要不接触”的哲学。也减少了潜在的 debug 困难。

那么为什么我不~~直接 Ctrl+CCtrl+V~~ 参考借鉴呢? 一是我们是老项目,依旧使用传统的 build.gradle,fcitx5-android 是 Kotlin DSL,直接复制粘贴肯定是行不通的; 二是实际上在仿照时遇到了困难,比如解决不了找不到方法所需的依赖(函数)、Gradle 语言不熟悉,以及一些细节上的考虑等。

遂将想法公之于众,待诸位共同探讨有无更简单、易行和便捷的方法?或者能尝试仿照 fcitx5-android 并回馈一些问题和可能的解决方法?

WhiredPlanck avatar Jun 13 '22 15:06 WhiredPlanck

  1. 文件hash其实还是有资源开销的。并且,是遍历整个文件并完成计算,如果没有差异也不是很能节约时间,如果有差异,则再进行复制,此时开销更大了。
  2. 考虑到共用目录会有用户自己放的文静,不能做整个目录的hash,使用需要对每个资源做hash并保留数组,我觉得不是很好。就我对手游的了解,只有涉及网络下载资源的情况,才会这么做。
  3. 同文内置asset数量和大小都比较有限。
  4. 需要考虑用户内置方案的修改版这么做
  5. 当然asset复制资源的用时,和直接复制磁盘文件有区别,会比较慢,你可以增加log来对比。(当然这和设备配置也有差别)

tumuyan avatar Jun 14 '22 00:06 tumuyan

另外其实现在的覆盖文件的时机的确是需要调整的,目前应该是比较的大版本号,同文在前几个pr里增加了带commit信息的版本号,需要改为比较这个版本号,增加自动释放文件的频率。 或者说编译时对资源整体hash作为一个资源版本号,比较这个版本号。

tumuyan avatar Jun 14 '22 00:06 tumuyan

  1. 文件hash其实还是有资源开销的。并且,是遍历整个文件并完成计算,如果没有差异也不是很能节约时间,如果有差异,则再进行复制,此时开销更大了。

这点 fcitx5-android 考虑到了,所以 Hash 的生成是在构建阶段就完成了,最终的比较都基于那份登记用的 JSON 表。

2. 考虑到共用目录会有用户自己放的文静,不能做整个目录的hash,使用需要对每个资源做hash并保留数组,我觉得不是很好。就我对手游的了解,只有涉及网络下载资源的情况,才会这么做。

这一点同样也被考虑到了,实际的遍历只会遍历 JSON 里登记的条目,即只比较应用本身自带的文件,其他是不动的(所以说“非必要不接触”),然后输出一份枚举值列表,然后匹配列表里的枚举值选择相对应的操作。

上述所有的开销项目在用户端有:解析(反序列)JSON 登记表、比较 SHA256 值(逐一比较新旧版的 JSON 登记表的条目)和复制文件。

  • 同文内置asset数量和大小都比较有限。

  • 需要考虑用户内置方案的修改版这么做

  • 当然asset复制资源的用时,和直接复制磁盘文件有区别,会比较慢,你可以增加log来对比。(当然这和设备配置也有差别)

文件 I/O 的开销在大多数情景下都是可观的,比反序列和比较 SHA256 字串都要可观,我想这也是为什么 fcitx5-andorid 为何如此精细化操作的原因。同文自带资源文件较少反而不是坏事,在 Rime 后端初始化启动时同步文件很快就能完成。

WhiredPlanck avatar Jun 14 '22 00:06 WhiredPlanck

目前应该是比较的大版本号

比较的其实就是 BuildConfig 里的整个 VERSION_NAME 字符串内容,完全相同则不操作,否则强制覆盖文件。

编译时对资源整体hash作为一个资源版本号

你的想法和 fcitx5-android 心有灵犀,这也是我认为他们的方法从理论上相当科学的原因。他们的JSON 登记表也是有自己的 SHA256 值的,比较文件的 Hash 的前置条件即为先比较新旧 JSON 登记表的 Hash,不同才进行文件的比较。

WhiredPlanck avatar Jun 14 '22 00:06 WhiredPlanck

这一点同样也被考虑到了,实际的遍历只会遍历 JSON 里登记的条目,即只比较应用本身自带的文件,其他是不动的(所以说“非必要不接触”),然后输出一份枚举值列表,然后匹配列表里的枚举值选择相对应的操作。

修改版是直接替换资源的,并没经过编译阶段。手工修改的难度变大了

文件 I/O 的开销在大多数情景下都是可观的,比反序列和比较 SHA256 字串都要可观,我想这也是为什么 fcitx5-andorid 为何如此精细化操作的原因。同文自带资源文件较少反而不是坏事,在 Rime 后端初始化启动时同步文件很快就能完成。

这一点可以在后边用不同用户的具体数值来比较

tumuyan avatar Jun 14 '22 00:06 tumuyan

修改版是直接替换资源的,并没经过编译阶段。手工修改的难度变大了

这一点确实是需要额外考虑的,尤其对于你来说。幸亏开了这个讨论 ~

这一点可以在后边用不同用户的具体数值来比较

这点没太理解,愿闻其详。

以及

增加了带commit信息的版本号,需要改为比较这个版本号

确实需要扩展比较的范围,也是在犹豫的一种方案。不过我们是否需要知道“新”和“旧”的概念呢?还是只要知道不同即可 ……?

WhiredPlanck avatar Jun 14 '22 01:06 WhiredPlanck

这一点确实是需要额外考虑的,尤其对于你来说。幸亏开了这个讨论 ~

对我自己倒是没有影响,小鹤作者之前和我聊过。实际上目前也是有影响的,比如svg图标无法被方便的编辑和替换。

没太理解,愿闻其详。

编译测试版本,在信息面板显示出释放资源的耗时,或者toast耗时。

是否需要知道“新”和“旧”的概念呢?还是只要知道不同即可

不同就需要替换,因为有回退旧版本的情况

tumuyan avatar Jun 14 '22 01:06 tumuyan

不同就需要替换,因为有回退旧版本的情况

嗯,所以是不是只要比较 commit hash 即可呢?还是在比较 VERSION_NAME 的基础再比较 commit hash ……?

编译测试版本,在信息面板显示出释放资源的耗时,或者toast耗时。

噢 ~ 到时看看怎么加 ~

WhiredPlanck avatar Jun 14 '22 01:06 WhiredPlanck

嗯,所以是不是只要比较 commit hash 即可呢?还是在比较 VERSION_NAME 的基础再比较 commit hash ……?

应该只比较资源的hash构成的版本号吧

tumuyan avatar Jun 15 '22 03:06 tumuyan

应该只比较资源的hash构成的版本号吧

你的意思是构建时计算整体资源(assets)的 hash,而不是 git hash 是吗?

WhiredPlanck avatar Jun 17 '22 05:06 WhiredPlanck

Introduced the related mechanism at 5f37b0e.

WhiredPlanck avatar Mar 23 '23 16:03 WhiredPlanck