Skip to content

Releases: ayss2188/custom-font-switcher

自定义字体切换模块 v1.4.9.5

Choose a tag to compare

@github-actions github-actions released this 26 Oct 23:19

本版修复:更新流程(与子项目同步的那套修法),界面和功能与 1.4.9.2 一致。

· 更新源加时间戳破缓存(?t=),刚发版也能立刻看到新版本
· 确认有新版时强制安装(force),不再误报"已是最新"
· curl / busybox wget / wget / toybox wget 逐个尝试,失败原因写进 .update/worker.log
· 小于 1MB 的假长度当未知(不再显示 0 B / 9 B)
· 派发改为同步返回 + 派发前清旧状态,不再卡在"正在连接"
· 安装完成判据:版号匹配 + modules_update 目录大小连续 3 秒不变,
  且本次会话必须见过下载/安装阶段,才亮「立即重启生效」

自定义字体切换模块 v1.4.9.X

Choose a tag to compare

@github-actions github-actions released this 25 Oct 21:23

对比基准:线上版本 v1.4.8.4。只写你能看到、能用到的变化。

一、新增「高级设置」——本版重点

这是什么

一个默认隐藏的调试面板。以前遇到"字体没生效""某个 App 闪退""图标变方框",只能在主界面翻报告;现在集中到一个带分区的面板里,每一项都写了它是干嘛的、怎么看结果。

怎么进去

1. 打开 WebUI,停在主界面
2. 滑到最下面,找到「当前版本」那一行
3. 连点 7 次(连续点,中途别停)
4. 弹出输入框 → 输入口令:cfs2026
5. 进入「高级(调试用)」

进去以后:

· 标题右边「锁定」:点它确认后,主界面入口重新隐藏
  想再进:连点版本号 7 次 + 口令
· 右上角「✕」关闭;进入子页后变成「‹ ✕」
· 子页不显示「锁定」,避免误触

分区只读保护:面板会先读你的系统。不是你系统的分区显示为只读,卡片上写「本机不是 X 系统」,点了没反应 —— 在小米手机上不会误开三星的开关。

分区与功能

分区 项数 内容
界面自定义 15 背景图片(设置/清除)、背景预设三档、背景暗化、背景模糊、卡片不透明度、深浅色、强调色、圆角、标题字号、隐藏 Google 兼容卡片、隐藏反馈入口、简化模式、导出/导入界面设置、重新锁定、恢复默认界面
通用 · 出问题了先看这里 10 槽位统计、挂载状态、逐个核对、当前生效/待生效、识别系统、抓日志、诊断报告、重扫字体、清缓存
三星专区 7 三星专用:单个图标变方框、某个 App 显示异常时逐个开关试
澎湃OS / MIUI 专区 7 小米、红米、POCO:只影响 MiSans 这类自家字体
Flyme 专区 9 魅族:厂商字体排除、分区范围、闪退规避
ColorOS / realme 专区 6 OPPO / 一加 / realme:主题字体目录、product 分区
vivo / iQOO 专区 6 主题目录 /data/bbkcore/theme、/data/skin/fonts
荣耀 / 华为专区 4 这两个系统保护自家主字体,这里只看状态
AOSP / 原生专区 4 原生系统相关槽位
更危险的区域 5 物理替换、清空、强制重扫这类操作,每项都有确认框

二、界面外观:可换背景 + 毛玻璃

· 新增「设置背景图片」:选一张图当背景,原图导入、最大 24MB,不压缩
· 所有浮层(选字体、字属性、诊断报告、各种菜单)改成毛玻璃
· 三档背景预设:预设一偏暗 / 预设二最亮最清 / 预设三最糊
  点一下自动把滑块调到对应值;手动拖过就显示"自定义"
· 三个滑块:背景暗化、背景模糊、卡片不透明度,拖动即时生效
· 有壁纸时按钮不再用强调色,避免抢眼
· 平板 / 横屏:模糊层按屏幕尺寸铺满,四周不再露一条清晰的边

三、状态显示与模块更新

· 「槽位总数 / 实际挂载 / 逐个核对」三项能取到真实数字(不再显示 "-")
· 切换字体后:卡片"当前"立即更新,"待生效"标记正确
· 模块更新:检查更新 / 下载 / 安装 / 重启提示整套实测通过,
  装完不会再变回"下载中",重启后也不会残留红色「立即重启生效」

四、卸载 / 重装更干净

· 卸载:物理删除背景图、清掉界面外观,重装后壁纸不再"复活"
· 重装:安装号变化时自动清掉上一套界面设置,回到默认外观
· 字体库仍按原规则:还有另一个字体模块装着时保留共享字体库

五、这一版没有改的东西

· 默认行为:默认仍然「不替换任何系统字体」,装完要先选
· 开关默认值:一个都没改
· 机型识别与槽位扫描规则:除上面写到的,其它与 1.4.8.4 一致

升级提示

1. 从 1.4.8.4 直接覆盖安装即可,装完重启一次
2. 第一次打开 WebUI,字体列表和状态数字需要几秒加载,属正常
3. 想换背景:高级设置 → 界面自定义 → 设置背景图片

自定义字体切换模块 v1.4.8.4

Choose a tag to compare

@github-actions github-actions released this 24 Oct 10:56

🐞 大 bug 修复:中文合集(.ttc)从来没被替换过

ttcwrap.sh 里写字节的格式写成了 '\\%03o'(多一个反斜杠)。
shell 把 \\ 当字面反斜杠,于是输出的是文本 \101\102… 而不是字节 →
表目录长度永远对不上 → ttc_wrap 一直返回 1、产物 0 字节。

影响:所有靠 .ttc 合集出中文的机型(三星、部分魅族/一加),
中文兜底字体从来没有真正换过 —— 诊断报告里的 via=wrapfail 就是它。

已修:重写字节发射器,并在启动时探测本机 printf 认哪种八进制写法
(\101 / \0101),两种都不认就改用 awk 逐字节写。
本地已用真实字体验证:5 face 合集、混合合集都生成成功,结构校验通过。

🐞 修「升级后第一次开机会没有字体」

真机日志:

阶段=post-fs-data 没有挂载计划(slots.map 为空),尝试重新生成
阶段=post-fs-data 重新生成后仍然没有挂载计划(退出码 1),本次不挂载
  • 安装/升级删完扫描缓存后当场重扫一次,不再指望开机补
  • 开机补计划失败时再补一次完整重算(第一次是轻量、跳过合集)
  • apply 的输出写进 mount.log,失败原因不再被 >/dev/null 吞掉

✨ 新增:一键抓崩溃日志(App 闪退 / WebUI 闪退)

界面上「④ 抓崩溃日志」:

  • 开始 → 去复现问题 → 停止并导出 → Download/崩溃日志_时间.txt
  • 导出内容:每个崩溃点前后各 120/260 行 + 尾部 4000 行 + 汇总头
  • 同时收集系统侧证据:dropbox(App 崩溃/系统崩溃/watchdog)、
    tombstone(原生崩溃)、ANR traces —— 只看 logcat 往往定不了性
  • 停止后再点不会重复生成(比对大小+修改时间,直接返回上次那份)
  • 停止后可以一键上传(和完整报告同一条通道,上传前弹窗写备注 + 提示连 VPN + 先测网络)
  • 界面是异步的:后台启动 + fetch 轮询状态,按钮变字转圈,不再卡界面

WebUI 自己闪退时的三个备用入口:

  1. 管理器模块卡片的「操作」按钮
  2. 模块目录里的 抓日志-开始.sh / 抓日志-停止导出.sh(MT 管理器点执行即可)
  3. 命令行:su -c "sh /data/adb/modules/custom_font_switcher/logcatch.sh start|stop"

✨ 一键上报:把现成数据都带上(仍然 1~2 秒)

以前只报二十来项,现在把磁盘上已有的状态全读进来(只读不扫盘):
选中字体的元数据、字体库清单、扫描缓存概况、挂载状态、合集合成日志、
抓日志状态、冲突模块、环境(管理器/内核/ksud)、开机事件、设置全文。
上限从 4KB 提到 64KB(现在走作者自己的服务器,不再受邮件正文限制)。

🔧 「操作」按钮变得纯粹

  • KernelSU / APatch:只抓日志(不再顺手生成诊断报告、不再检查更新)
  • Magisk:只打开 WebUI

🐞 诊断报告两处误报

  • protect.list / 「粗细调节」族里的字体不再被标成 [★要修](例:RobotoFlex-Regular.ttf)
  • 「字体库 N 个」现在包含内置配色(以前只数 f*.ttf,出现"0 个却占 128MB")

💬 文案与界面

  • 刷入提示改成实情:「正在生成挂载计划(槽位多或设备慢时要几十秒到几分钟)」,
    原来写"很快"是错的
  • 分区顺序统一:② 快速通道 → ③ 完整报告 → ④ 抓崩溃日志 → ⑤ 网络诊断
  • 入口卡改成「遇到问题?抓日志 / 报故障」,说明移到卡片外面
  • 修掉一个 HTML 未闭合导致的 bug:⑤ 网络诊断 被塞进隐藏容器里看不见

自定义字体切换模块 v1.4.8.3

Choose a tag to compare

@github-actions github-actions released this 23 Oct 06:18

🐞 修「魅族上什么都替换不了」(槽位计划变成 0 个)

真机现场(MEIZU 20 Pro / Flyme / KernelSU):

[3/4] 扫描与槽位
- 槽位计划:0 个,其中中文合集槽位 0 个
上次选择:builtin_flair → 没找到可替换的槽位(范围: all)
→ 已设为「无字体」

原因:上一版为了防魅族闪退,让 Flyme 完全不做本机扫描,只用机型清单;
而机型清单里没有 MEIZU 20 Pro 的条目 → 一个槽位都没有 → 装上也白装。

已修:

  • Flyme 恢复本机扫描,但只扫 /system 下的字体目录
  • /product、/vendor、/my_product、/my_stock 等厂商分区一律不碰
    (Flyme 的 UI 字体就在这些分区里,替换它们会引发闪退/跳转失败)
  • 厂商字体名单(SFPro / SFDIN / DINPro / MyriadPro…)继续排除,作为第二层保险

升级后会重扫一次(扫描印记 14083)。这一版对非魅族设备无行为变化。

自定义字体切换模块 v1.4.8.2

Choose a tag to compare

@github-actions github-actions released this 22 Oct 22:37

🐞 修「切换字体后界面不刷新」

现象:选完配色/字体,提示条说"已选择…",但卡片还标着旧的「当前」,顶部数字也不动。

原因:刷新函数开头有"已在刷新就跳过"的闸门(防止并发刷新),而切换完成时正好撞上
另一次刷新在跑(补族键/定时刷新),这次调用直接返回、也不报错 → 界面停在旧状态。

已修:切完立刻本地更新卡片状态 → 直接刷顶部 → 再全量刷新 → 1.2 秒后再兜一次。
顺带纠正一处语义:切换后只改「待重启生效」,「当前实际生效」保持旧的(重启后才变)。

🐞 修「开关点了,顶部数字不变」

同一个根因(刷新闸门),同样处理。

🐞 修「A/B 比较只有右边粗细会变」

原因:滑块只设了可变字体轴(font-variation-settings)。左边是当前字体,
如果是静态字体,这条设置毫无效果;右边恰好是可变的,看起来就"只有右边在变"。

已修:同时设置 font-weight 数值 —— 静态字体会由浏览器合成粗细,两边都有反馈。
滑块标题也注明「静态字体只能模拟」。

🛡 加「切换字体卡在修改中」的兜底

切换走的是同步执行,极端情况下不返回,界面会永远停在"修改中",之后点什么都没反应。
现在 180 秒看门狗:超时也会清掉锁定、恢复界面,并提示可以看诊断报告。


本版之前的那一版(1.4.8.1)内容:魅族修复 + 更新卡住

🐞 修「更新时一直卡在『正在安装中』」

现象:点「下载并安装」后进度条停在「正在安装中」,管理器里其实已经装好了。

原因:安装是把管理器命令放后台跑、等它写退出码。但 ksud / Magisk 有时候
装完不返回(被管理器接管),退出码永远不出现 → 界面一直等,600 秒后才判失败。

已修:

  • 等待期间增加版本判据:已安装模块的版本变成目标版本,或出现
    /data/adb/modules_update/<id>(管理器已接管、待重启生效)→ 立即认定装好
  • 判据要求"版本必须发生变化",所以重复安装同一版本时不会误报完成
  • 超时 600 秒 → 180 秒;超时但版本已对上,也按成功处理

🐞 魅族:把替换范围严格退回 1.4.3

上一版(1.4.8)先补了 Flyme 的厂商字体名单、并限制本机扫描只用 /system。
这一版更彻底:Flyme 上直接不做本机扫描,槽位只来自机型清单 ——
与 1.4.3 的槽位来源完全一致(当初只有这条路径时魅族没有出过问题)。

  • 影响范围:只有 Flyme 设备受影响;其它系统行为不变
  • 厂商字体名单(SFPro / SFDIN / DINPro 等)保留,作为第二层保险
  • 升级后会重扫一次(扫描印记 14081)

说明:这是"先保证不崩"的做法。若后续确认魅族系统字体也能安全替换,
再逐步放开,不一次性冒进。


以下是同一轮更新的前两次发布内容(1.4.8 / 1.4.7.5),仍然有效,一并列出。

🐞 修「魅族 Flyme 上 App 闪退 / 酷安不能跳外链 / B站视频退回桌面」

现象(两位魅族用户报告):

  • 把「卸载模块」关掉(App 能看到模块挂载)时:WebUI 闪退、酷安点外链跳不动、B站视频卡一下退回桌面
  • 把「卸载模块」单独给 WebUI 打开(App 看不到挂载)时:一切正常

根因:被替换的字体里包含 Flyme 自己的 UI 字体(SFPro / SFDIN / DINPro 这类)。
Flyme 的字体服务会校验这些文件,发现被换过就出异常,连带 App 一起崩。
识别厂商字体的名单里原本只覆盖 MeizuSans 一类,漏了上面这几个,所以它们照常被替换。

已修:补齐 Flyme 的厂商字体名单 —— 以下文件不再替换:

SFPro* / SFDIN* / SF-* / *DINPro* / *MyriadPro* / *SFRounded*
(连同原有的 MeizuSans / FlymeSans / mFlyme 等)

另外,Flyme 上「本机扫描」也不再使用 /product、/vendor、/my_product 等厂商分区的结果(只保留 /system)—— 也就是把替换范围退回 1.4.3 那种水平,厂商 UI 字体彻底不在替换列表里。

升级后会自动重扫一次(扫描印记 slot/font 提到 14080),重扫完这些槽位就从计划里消失了,
「卸载模块」关着也不会再被 Flyme 判定为“字体被改过”。

如果你不是魅族用户:这一版对你没有任何行为变化(名单只对新识别的厂商字体生效)。


性能与手感优化 + 去掉一个高风险开关。界面首屏更快(一次交互代替两次串行),字体读取改分块(顺带解决大字体把管理器 WebView 撑爆的隐患),动效统一。「同族字重自动配对」开关删除,改由更安全的「字重组」承担。

⚡ 首屏:两次 exec → 一次

KernelSU 的 exec 是同步的(执行期间 WebView 的 JS 线程被占住),原来首屏要串行跑两次:

fontctl.sh list     ← shell 启动 + 解析 common/slots/mount + 脚本本身 ≈ 250KB
fontctl.sh status   ← 再来一次,且 status 里还要跑 slot_sources_report

现在新增 fontctl.sh quick:一次输出「状态 + 字体列表」,界面解析一次就渲染;
槽位来源统计(要跑外部进程的部分)改由后台补,不再挡首屏。

顺带删掉「字体列表被解析两遍」的重复代码。

🧠 字体读取改分块(修 OOM 隐患)

原来一次读整段,od 会把 1 字节变成 3 个字符 —— 4MB 二进制 ≈ 12MB 文本,
一次性通过同步桥接回传 WebView。解析 40MB 级大字体时很容易把管理器撑爆,
用户侧表现就是「点开 WebUI 直接闪退」。

现在每次最多 256KB 二进制(≈768KB 文本)循环拼接,硬上限 8MB;
单块失败只丢这一块,不打断整次探测。cmap 读取上限 4MB → 1MB,name 表 64KB → 32KB。

🎨 动效统一(原来生硬)

  • 统一缓动/时长令牌:--ease-out / --ease-emphasis / --dur-*
  • 字体卡片:依次错峰 18ms 上浮淡入(只播一次,不会每次刷新都重放)
  • 卡片/按钮:按压缩到 0.972 回弹,不再是"瞬间变色"
  • 底部菜单:translateY 过渡,可被打断(原来直接跳到位)
  • 提示条:改用 transition(不用 keyframes,避免再覆盖 translate(-50%) 的居中)
  • 首屏骨架屏:数据回来前显示呼吸占位,不再"空白一下再刷出来"
  • 长列表/报告区:content-visibility: auto,屏幕外不排版
  • 完整尊重 prefers-reduced-motion

修正一个我上一轮的失误:入场动画之前挂在 .card 上,而真实卡片类是 .option,等于没生效。

📦 渲染:离屏构建

字体列表原来逐张 append 到已在文档里的容器(每次 append 都可能触发布局),
现在全部塞进 DocumentFragment 后一次性插入,只重排一次。DOM 结构、事件、样式全部不变。

🗂 底层:引入永久索引(少算、少读、少猜)

新增 /data/adb/custom_font_lib/.index:一份纯文本的"当前真相"清单——

#CFS-INDEX 2
ver=v1.4.7.4   active=f1   pending=f110   rom=hyperos   mode=self   slots=96   fonts=6
font=f1|烈焰|44810240|size=…,vf=1,wght=400,fam=…,family=Demo Sans,group=f1
  • 谁维护:导入 / 删除 / 改名 / 应用 / 写档案 / 重扫 —— 每个会改字体库的命令结束时自动重建(临时文件 + mv 原子替换)
  • 谁读:界面首屏、诊断报告、需要清单的脚本 —— 直接 cat,不再现场 glob + 逐个读 .name/.meta
  • 自愈:索引缺失或 schema 版本不符时自动重建一次

⚡ 诊断报告提速:指纹缓存

完整报告的大头是给几百个字体算"稀疏指纹"(每个文件读头尾各 64KB)。但同一台机器上绝大多数字体是长期不变的。

新增 /data/adb/custom_font_lib/.fp.cache(路径 + 大小 + 修改时间 → 指纹):

  • 命中就直接复用,不读盘
  • 未命中才算,算完追加写回
  • 文件超过 5000 行自动压缩(保留每个路径的最后一条)
  • 缓存是可丢弃的加速层:删掉只会让下次慢一点,不影响任何结论

本机实测:

第 1 次:计算并写入缓存(1 行)
第 2 次:命中,结果一致,不读盘
内容变化(大小 200000 → 200001):判定 MISS,重新计算,哈希随之改变   ✓

🧹 卸载:真正删干净

  • 先卸挂载:按 $LIB/.mounted 逐个 umount -l,再扫 /proc/mounts 兜底 —— 卸载后字体立刻回原厂,不用重启
  • 保护共用字库:主项目与子项目共用 /data/adb/custom_font_lib。卸载前检查是否还有别的字体模块在,有就保留字库(原来会一起删掉,同时装两个模块的用户会丢数据)
  • 清临时文件:/data/local/tmp 下 .pv.* / .slots.clean.* / .oem.* / .marks.*
  • GMS 恢复失败那条路径原本也会清空字库内容,同样加了保护

🐞 修「卸载重装后 UI 还显示旧字体列表」

字体列表缓存存在管理器 App 的 localStorage 里,卸载模块不会清它 → 重装后界面先画出旧列表(文件已不存在),点切换会去操作不存在的字体(卡住),删除报「已删除 0 个」。

修法四层:

  1. 缓存带上模块版本,版本不一致直接丢弃
  2. 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
  3. 真实数据到达立刻解除未校验,并刷新缓存
  4. 缓存 TTL 24 小时 → 10 分钟

🎬 动效与手感

  • 统一缓动/时长令牌(--ease-out / --ease-emphasis / --dur-*)
  • 卡片错峰入场(18ms 级联)、按压缩放回弹
  • Toast 改为 transition(不再用 keyframes 覆盖居中);首屏骨架屏;长区块 content-visibility
  • 修正上一轮把入场动画挂在 .card(真实类是 .option)导致没生效的问题

🧠 字体预览不再吃内存

以前点开一个字体详情,会把整份字体字节留在内存里(你的字库有 40MB 级字体,
点开几个就是上百 MB)。现在:

  • 预览加载有总量上限 60MB,超了自动释放最久没用的那份(从 document.fonts 摘掉)
  • 关闭详情时立刻释放当前这份,内存可回收
  • 低内存机型上不会再因为"看了几个字体"就被系统挤掉

🎬 过渡与光效(一镜到底)

  • 面板/弹窗统一「淡入 + 轻微上浮」,关闭时反向(只动 transform/opacity,不触发布局)
  • 卡片:按压回弹、选中/待生效的外发光
  • 报告「结构化 ↔ 原文」切换加交叉淡入
  • 骨架 → 内容淡接
  • prefers-reduced-motion 下全部关闭(不跑动画)

⏱ 报告耗时改成毫秒

以前按秒计时,多数小节只能显示 0,看着"都差不多"。现在显示 12.3s / <0.1s,
一眼能看出哪一步真慢。

🧹 其它

  • .upload.log 加 64KB 上限(超了只留最后 200 行,不会写满存储)
  • 永久索引自愈:字体库里有比索引更新的字体文件(手工放入/外部改动)→ 自动重建
  • 服务端修复:上报 Worker 补上 CORS 与 OPTIONS 预检 —— 之前浏览器直接打开正常、
    但页面里的 fetch 会被拦(真机表现为"连不上服务器")

🔄 旧版升级上来会强制重扫一次(重要)

旧版本写下的档案缺字段(family / upem / subfamily),槽位清单也可能和新扫描逻辑对不上 ——
陈年档案配新代码,就是各种"用不了"。

本版把扫描要求版本提到当前版本(slot=14075 / font=14075):

  • 旧版升级上来的用户:装完第一次开机自动全量重扫槽位与字体档案(一次性)
  • 新装用户:本来就是首次扫描,不受影响
  • 同版本重装:也会重扫(方便自测,代价是这一次慢一点)
  • 想手动强制:touch /data/adb/custom_font_lib/.force_rescan 后重装

同时把永久索引的 schema 提到 3:升级后旧索引自动作废并重建,不会读到过期内容。

🐞 修「导入字体后界面不刷新」

根因是我上一版把"重建索引"写在了各命令的末尾,而那些分支几乎都是 exit 结尾 ——
退出之后的代码永远执行不到,于是索引一直旧、界面读旧数据。

现在改成打脏标记 + 退出时统一重建:不管命令是正常结束、exit 还是中途出错,
只要改过字体库,退出前都会重建一次索引;只读命令不标记,不会白白重建。

本机单测(模拟真实分支结构):

status(只读)  → 不重建索引   ✓
import(内部 exit)→ 重建      ✓
delete(正常结束)→ 重建       ✓

🗑 删除「同族字重自动配对」开关

它按字体内部族名自动把多份字体当成"同一套的不同字重"。问题是:族名相同不代表同一套字体
(拼包/改名字体很常见),混挂会缺字变方块,极端情况开不了机。

现在这件事交给字重组:用户手动勾选 + 五道校验(族名原文 / upem / 字形数 ±3% / 覆盖率 ±2 / 子族名不同),
安全得多。原有的 group= 数据继续有效,老用户的字重组不受影响。


自定义字体切换模块 v1.4.8.1

Choose a tag to compare

@github-actions github-actions released this 22 Oct 21:36

🐞 修「更新时一直卡在『正在安装中』」

现象:点「下载并安装」后进度条停在「正在安装中」,管理器里其实已经装好了。

原因:安装是把管理器命令放后台跑、等它写退出码。但 ksud / Magisk 有时候
装完不返回(被管理器接管),退出码永远不出现 → 界面一直等,600 秒后才判失败。

已修:

  • 等待期间增加版本判据:已安装模块的版本变成目标版本,或出现
    /data/adb/modules_update/<id>(管理器已接管、待重启生效)→ 立即认定装好
  • 判据要求"版本必须发生变化",所以重复安装同一版本时不会误报完成
  • 超时 600 秒 → 180 秒;超时但版本已对上,也按成功处理

🐞 魅族:把替换范围严格退回 1.4.3

上一版(1.4.8)先补了 Flyme 的厂商字体名单、并限制本机扫描只用 /system。
这一版更彻底:Flyme 上直接不做本机扫描,槽位只来自机型清单 ——
与 1.4.3 的槽位来源完全一致(当初只有这条路径时魅族没有出过问题)。

  • 影响范围:只有 Flyme 设备受影响;其它系统行为不变
  • 厂商字体名单(SFPro / SFDIN / DINPro 等)保留,作为第二层保险
  • 升级后会重扫一次(扫描印记 14081)

说明:这是"先保证不崩"的做法。若后续确认魅族系统字体也能安全替换,
再逐步放开,不一次性冒进。


以下是同一轮更新的前两次发布内容(1.4.8 / 1.4.7.5),仍然有效,一并列出。

🐞 修「魅族 Flyme 上 App 闪退 / 酷安不能跳外链 / B站视频退回桌面」

现象(两位魅族用户报告):

  • 把「卸载模块」关掉(App 能看到模块挂载)时:WebUI 闪退、酷安点外链跳不动、B站视频卡一下退回桌面
  • 把「卸载模块」单独给 WebUI 打开(App 看不到挂载)时:一切正常

根因:被替换的字体里包含 Flyme 自己的 UI 字体(SFPro / SFDIN / DINPro 这类)。
Flyme 的字体服务会校验这些文件,发现被换过就出异常,连带 App 一起崩。
识别厂商字体的名单里原本只覆盖 MeizuSans 一类,漏了上面这几个,所以它们照常被替换。

已修:补齐 Flyme 的厂商字体名单 —— 以下文件不再替换:

SFPro* / SFDIN* / SF-* / *DINPro* / *MyriadPro* / *SFRounded*
(连同原有的 MeizuSans / FlymeSans / mFlyme 等)

另外,Flyme 上「本机扫描」也不再使用 /product、/vendor、/my_product 等厂商分区的结果(只保留 /system)—— 也就是把替换范围退回 1.4.3 那种水平,厂商 UI 字体彻底不在替换列表里。

升级后会自动重扫一次(扫描印记 slot/font 提到 14080),重扫完这些槽位就从计划里消失了,
「卸载模块」关着也不会再被 Flyme 判定为“字体被改过”。

如果你不是魅族用户:这一版对你没有任何行为变化(名单只对新识别的厂商字体生效)。


性能与手感优化 + 去掉一个高风险开关。界面首屏更快(一次交互代替两次串行),字体读取改分块(顺带解决大字体把管理器 WebView 撑爆的隐患),动效统一。「同族字重自动配对」开关删除,改由更安全的「字重组」承担。

⚡ 首屏:两次 exec → 一次

KernelSU 的 exec 是同步的(执行期间 WebView 的 JS 线程被占住),原来首屏要串行跑两次:

fontctl.sh list     ← shell 启动 + 解析 common/slots/mount + 脚本本身 ≈ 250KB
fontctl.sh status   ← 再来一次,且 status 里还要跑 slot_sources_report

现在新增 fontctl.sh quick:一次输出「状态 + 字体列表」,界面解析一次就渲染;
槽位来源统计(要跑外部进程的部分)改由后台补,不再挡首屏。

顺带删掉「字体列表被解析两遍」的重复代码。

🧠 字体读取改分块(修 OOM 隐患)

原来一次读整段,od 会把 1 字节变成 3 个字符 —— 4MB 二进制 ≈ 12MB 文本,
一次性通过同步桥接回传 WebView。解析 40MB 级大字体时很容易把管理器撑爆,
用户侧表现就是「点开 WebUI 直接闪退」。

现在每次最多 256KB 二进制(≈768KB 文本)循环拼接,硬上限 8MB;
单块失败只丢这一块,不打断整次探测。cmap 读取上限 4MB → 1MB,name 表 64KB → 32KB。

🎨 动效统一(原来生硬)

  • 统一缓动/时长令牌:--ease-out / --ease-emphasis / --dur-*
  • 字体卡片:依次错峰 18ms 上浮淡入(只播一次,不会每次刷新都重放)
  • 卡片/按钮:按压缩到 0.972 回弹,不再是"瞬间变色"
  • 底部菜单:translateY 过渡,可被打断(原来直接跳到位)
  • 提示条:改用 transition(不用 keyframes,避免再覆盖 translate(-50%) 的居中)
  • 首屏骨架屏:数据回来前显示呼吸占位,不再"空白一下再刷出来"
  • 长列表/报告区:content-visibility: auto,屏幕外不排版
  • 完整尊重 prefers-reduced-motion

修正一个我上一轮的失误:入场动画之前挂在 .card 上,而真实卡片类是 .option,等于没生效。

📦 渲染:离屏构建

字体列表原来逐张 append 到已在文档里的容器(每次 append 都可能触发布局),
现在全部塞进 DocumentFragment 后一次性插入,只重排一次。DOM 结构、事件、样式全部不变。

🗂 底层:引入永久索引(少算、少读、少猜)

新增 /data/adb/custom_font_lib/.index:一份纯文本的"当前真相"清单——

#CFS-INDEX 2
ver=v1.4.7.4   active=f1   pending=f110   rom=hyperos   mode=self   slots=96   fonts=6
font=f1|烈焰|44810240|size=…,vf=1,wght=400,fam=…,family=Demo Sans,group=f1
  • 谁维护:导入 / 删除 / 改名 / 应用 / 写档案 / 重扫 —— 每个会改字体库的命令结束时自动重建(临时文件 + mv 原子替换)
  • 谁读:界面首屏、诊断报告、需要清单的脚本 —— 直接 cat,不再现场 glob + 逐个读 .name/.meta
  • 自愈:索引缺失或 schema 版本不符时自动重建一次

⚡ 诊断报告提速:指纹缓存

完整报告的大头是给几百个字体算"稀疏指纹"(每个文件读头尾各 64KB)。但同一台机器上绝大多数字体是长期不变的。

新增 /data/adb/custom_font_lib/.fp.cache(路径 + 大小 + 修改时间 → 指纹):

  • 命中就直接复用,不读盘
  • 未命中才算,算完追加写回
  • 文件超过 5000 行自动压缩(保留每个路径的最后一条)
  • 缓存是可丢弃的加速层:删掉只会让下次慢一点,不影响任何结论

本机实测:

第 1 次:计算并写入缓存(1 行)
第 2 次:命中,结果一致,不读盘
内容变化(大小 200000 → 200001):判定 MISS,重新计算,哈希随之改变   ✓

🧹 卸载:真正删干净

  • 先卸挂载:按 $LIB/.mounted 逐个 umount -l,再扫 /proc/mounts 兜底 —— 卸载后字体立刻回原厂,不用重启
  • 保护共用字库:主项目与子项目共用 /data/adb/custom_font_lib。卸载前检查是否还有别的字体模块在,有就保留字库(原来会一起删掉,同时装两个模块的用户会丢数据)
  • 清临时文件:/data/local/tmp 下 .pv.* / .slots.clean.* / .oem.* / .marks.*
  • GMS 恢复失败那条路径原本也会清空字库内容,同样加了保护

🐞 修「卸载重装后 UI 还显示旧字体列表」

字体列表缓存存在管理器 App 的 localStorage 里,卸载模块不会清它 → 重装后界面先画出旧列表(文件已不存在),点切换会去操作不存在的字体(卡住),删除报「已删除 0 个」。

修法四层:

  1. 缓存带上模块版本,版本不一致直接丢弃
  2. 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
  3. 真实数据到达立刻解除未校验,并刷新缓存
  4. 缓存 TTL 24 小时 → 10 分钟

🎬 动效与手感

  • 统一缓动/时长令牌(--ease-out / --ease-emphasis / --dur-*)
  • 卡片错峰入场(18ms 级联)、按压缩放回弹
  • Toast 改为 transition(不再用 keyframes 覆盖居中);首屏骨架屏;长区块 content-visibility
  • 修正上一轮把入场动画挂在 .card(真实类是 .option)导致没生效的问题

🧠 字体预览不再吃内存

以前点开一个字体详情,会把整份字体字节留在内存里(你的字库有 40MB 级字体,
点开几个就是上百 MB)。现在:

  • 预览加载有总量上限 60MB,超了自动释放最久没用的那份(从 document.fonts 摘掉)
  • 关闭详情时立刻释放当前这份,内存可回收
  • 低内存机型上不会再因为"看了几个字体"就被系统挤掉

🎬 过渡与光效(一镜到底)

  • 面板/弹窗统一「淡入 + 轻微上浮」,关闭时反向(只动 transform/opacity,不触发布局)
  • 卡片:按压回弹、选中/待生效的外发光
  • 报告「结构化 ↔ 原文」切换加交叉淡入
  • 骨架 → 内容淡接
  • prefers-reduced-motion 下全部关闭(不跑动画)

⏱ 报告耗时改成毫秒

以前按秒计时,多数小节只能显示 0,看着"都差不多"。现在显示 12.3s / <0.1s,
一眼能看出哪一步真慢。

🧹 其它

  • .upload.log 加 64KB 上限(超了只留最后 200 行,不会写满存储)
  • 永久索引自愈:字体库里有比索引更新的字体文件(手工放入/外部改动)→ 自动重建
  • 服务端修复:上报 Worker 补上 CORS 与 OPTIONS 预检 —— 之前浏览器直接打开正常、
    但页面里的 fetch 会被拦(真机表现为"连不上服务器")

🔄 旧版升级上来会强制重扫一次(重要)

旧版本写下的档案缺字段(family / upem / subfamily),槽位清单也可能和新扫描逻辑对不上 ——
陈年档案配新代码,就是各种"用不了"。

本版把扫描要求版本提到当前版本(slot=14075 / font=14075):

  • 旧版升级上来的用户:装完第一次开机自动全量重扫槽位与字体档案(一次性)
  • 新装用户:本来就是首次扫描,不受影响
  • 同版本重装:也会重扫(方便自测,代价是这一次慢一点)
  • 想手动强制:touch /data/adb/custom_font_lib/.force_rescan 后重装

同时把永久索引的 schema 提到 3:升级后旧索引自动作废并重建,不会读到过期内容。

🐞 修「导入字体后界面不刷新」

根因是我上一版把"重建索引"写在了各命令的末尾,而那些分支几乎都是 exit 结尾 ——
退出之后的代码永远执行不到,于是索引一直旧、界面读旧数据。

现在改成打脏标记 + 退出时统一重建:不管命令是正常结束、exit 还是中途出错,
只要改过字体库,退出前都会重建一次索引;只读命令不标记,不会白白重建。

本机单测(模拟真实分支结构):

status(只读)  → 不重建索引   ✓
import(内部 exit)→ 重建      ✓
delete(正常结束)→ 重建       ✓

🗑 删除「同族字重自动配对」开关

它按字体内部族名自动把多份字体当成"同一套的不同字重"。问题是:族名相同不代表同一套字体
(拼包/改名字体很常见),混挂会缺字变方块,极端情况开不了机。

现在这件事交给字重组:用户手动勾选 + 五道校验(族名原文 / upem / 字形数 ±3% / 覆盖率 ±2 / 子族名不同),
安全得多。原有的 group= 数据继续有效,老用户的字重组不受影响。


自定义字体切换模块 v1.4.8

Choose a tag to compare

@github-actions github-actions released this 22 Oct 21:21

🐞 修「魅族 Flyme 上 App 闪退 / 酷安不能跳外链 / B站视频退回桌面」

现象(两位魅族用户报告):

  • 把「卸载模块」关掉(App 能看到模块挂载)时:WebUI 闪退、酷安点外链跳不动、B站视频卡一下退回桌面
  • 把「卸载模块」单独给 WebUI 打开(App 看不到挂载)时:一切正常

根因:被替换的字体里包含 Flyme 自己的 UI 字体(SFPro / SFDIN / DINPro 这类)。
Flyme 的字体服务会校验这些文件,发现被换过就出异常,连带 App 一起崩。
识别厂商字体的名单里原本只覆盖 MeizuSans 一类,漏了上面这几个,所以它们照常被替换。

已修:补齐 Flyme 的厂商字体名单 —— 以下文件不再替换:

SFPro* / SFDIN* / SF-* / *DINPro* / *MyriadPro* / *SFRounded*
(连同原有的 MeizuSans / FlymeSans / mFlyme 等)

另外,Flyme 上「本机扫描」也不再使用 /product、/vendor、/my_product 等厂商分区的结果(只保留 /system)—— 也就是把替换范围退回 1.4.3 那种水平,厂商 UI 字体彻底不在替换列表里。

升级后会自动重扫一次(扫描印记 slot/font 提到 14080),重扫完这些槽位就从计划里消失了,
「卸载模块」关着也不会再被 Flyme 判定为“字体被改过”。

如果你不是魅族用户:这一版对你没有任何行为变化(名单只对新识别的厂商字体生效)。


性能与手感优化 + 去掉一个高风险开关。界面首屏更快(一次交互代替两次串行),字体读取改分块(顺带解决大字体把管理器 WebView 撑爆的隐患),动效统一。「同族字重自动配对」开关删除,改由更安全的「字重组」承担。

⚡ 首屏:两次 exec → 一次

KernelSU 的 exec 是同步的(执行期间 WebView 的 JS 线程被占住),原来首屏要串行跑两次:

fontctl.sh list     ← shell 启动 + 解析 common/slots/mount + 脚本本身 ≈ 250KB
fontctl.sh status   ← 再来一次,且 status 里还要跑 slot_sources_report

现在新增 fontctl.sh quick:一次输出「状态 + 字体列表」,界面解析一次就渲染;
槽位来源统计(要跑外部进程的部分)改由后台补,不再挡首屏。

顺带删掉「字体列表被解析两遍」的重复代码。

🧠 字体读取改分块(修 OOM 隐患)

原来一次读整段,od 会把 1 字节变成 3 个字符 —— 4MB 二进制 ≈ 12MB 文本,
一次性通过同步桥接回传 WebView。解析 40MB 级大字体时很容易把管理器撑爆,
用户侧表现就是「点开 WebUI 直接闪退」。

现在每次最多 256KB 二进制(≈768KB 文本)循环拼接,硬上限 8MB;
单块失败只丢这一块,不打断整次探测。cmap 读取上限 4MB → 1MB,name 表 64KB → 32KB。

🎨 动效统一(原来生硬)

  • 统一缓动/时长令牌:--ease-out / --ease-emphasis / --dur-*
  • 字体卡片:依次错峰 18ms 上浮淡入(只播一次,不会每次刷新都重放)
  • 卡片/按钮:按压缩到 0.972 回弹,不再是"瞬间变色"
  • 底部菜单:translateY 过渡,可被打断(原来直接跳到位)
  • 提示条:改用 transition(不用 keyframes,避免再覆盖 translate(-50%) 的居中)
  • 首屏骨架屏:数据回来前显示呼吸占位,不再"空白一下再刷出来"
  • 长列表/报告区:content-visibility: auto,屏幕外不排版
  • 完整尊重 prefers-reduced-motion

修正一个我上一轮的失误:入场动画之前挂在 .card 上,而真实卡片类是 .option,等于没生效。

📦 渲染:离屏构建

字体列表原来逐张 append 到已在文档里的容器(每次 append 都可能触发布局),
现在全部塞进 DocumentFragment 后一次性插入,只重排一次。DOM 结构、事件、样式全部不变。

🗂 底层:引入永久索引(少算、少读、少猜)

新增 /data/adb/custom_font_lib/.index:一份纯文本的"当前真相"清单——

#CFS-INDEX 2
ver=v1.4.7.4   active=f1   pending=f110   rom=hyperos   mode=self   slots=96   fonts=6
font=f1|烈焰|44810240|size=…,vf=1,wght=400,fam=…,family=Demo Sans,group=f1
  • 谁维护:导入 / 删除 / 改名 / 应用 / 写档案 / 重扫 —— 每个会改字体库的命令结束时自动重建(临时文件 + mv 原子替换)
  • 谁读:界面首屏、诊断报告、需要清单的脚本 —— 直接 cat,不再现场 glob + 逐个读 .name/.meta
  • 自愈:索引缺失或 schema 版本不符时自动重建一次

⚡ 诊断报告提速:指纹缓存

完整报告的大头是给几百个字体算"稀疏指纹"(每个文件读头尾各 64KB)。但同一台机器上绝大多数字体是长期不变的。

新增 /data/adb/custom_font_lib/.fp.cache(路径 + 大小 + 修改时间 → 指纹):

  • 命中就直接复用,不读盘
  • 未命中才算,算完追加写回
  • 文件超过 5000 行自动压缩(保留每个路径的最后一条)
  • 缓存是可丢弃的加速层:删掉只会让下次慢一点,不影响任何结论

本机实测:

第 1 次:计算并写入缓存(1 行)
第 2 次:命中,结果一致,不读盘
内容变化(大小 200000 → 200001):判定 MISS,重新计算,哈希随之改变   ✓

🧹 卸载:真正删干净

  • 先卸挂载:按 $LIB/.mounted 逐个 umount -l,再扫 /proc/mounts 兜底 —— 卸载后字体立刻回原厂,不用重启
  • 保护共用字库:主项目与子项目共用 /data/adb/custom_font_lib。卸载前检查是否还有别的字体模块在,有就保留字库(原来会一起删掉,同时装两个模块的用户会丢数据)
  • 清临时文件:/data/local/tmp 下 .pv.* / .slots.clean.* / .oem.* / .marks.*
  • GMS 恢复失败那条路径原本也会清空字库内容,同样加了保护

🐞 修「卸载重装后 UI 还显示旧字体列表」

字体列表缓存存在管理器 App 的 localStorage 里,卸载模块不会清它 → 重装后界面先画出旧列表(文件已不存在),点切换会去操作不存在的字体(卡住),删除报「已删除 0 个」。

修法四层:

  1. 缓存带上模块版本,版本不一致直接丢弃
  2. 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
  3. 真实数据到达立刻解除未校验,并刷新缓存
  4. 缓存 TTL 24 小时 → 10 分钟

🎬 动效与手感

  • 统一缓动/时长令牌(--ease-out / --ease-emphasis / --dur-*)
  • 卡片错峰入场(18ms 级联)、按压缩放回弹
  • Toast 改为 transition(不再用 keyframes 覆盖居中);首屏骨架屏;长区块 content-visibility
  • 修正上一轮把入场动画挂在 .card(真实类是 .option)导致没生效的问题

🧠 字体预览不再吃内存

以前点开一个字体详情,会把整份字体字节留在内存里(你的字库有 40MB 级字体,
点开几个就是上百 MB)。现在:

  • 预览加载有总量上限 60MB,超了自动释放最久没用的那份(从 document.fonts 摘掉)
  • 关闭详情时立刻释放当前这份,内存可回收
  • 低内存机型上不会再因为"看了几个字体"就被系统挤掉

🎬 过渡与光效(一镜到底)

  • 面板/弹窗统一「淡入 + 轻微上浮」,关闭时反向(只动 transform/opacity,不触发布局)
  • 卡片:按压回弹、选中/待生效的外发光
  • 报告「结构化 ↔ 原文」切换加交叉淡入
  • 骨架 → 内容淡接
  • prefers-reduced-motion 下全部关闭(不跑动画)

⏱ 报告耗时改成毫秒

以前按秒计时,多数小节只能显示 0,看着"都差不多"。现在显示 12.3s / <0.1s,
一眼能看出哪一步真慢。

🧹 其它

  • .upload.log 加 64KB 上限(超了只留最后 200 行,不会写满存储)
  • 永久索引自愈:字体库里有比索引更新的字体文件(手工放入/外部改动)→ 自动重建
  • 服务端修复:上报 Worker 补上 CORS 与 OPTIONS 预检 —— 之前浏览器直接打开正常、
    但页面里的 fetch 会被拦(真机表现为"连不上服务器")

🔄 旧版升级上来会强制重扫一次(重要)

旧版本写下的档案缺字段(family / upem / subfamily),槽位清单也可能和新扫描逻辑对不上 ——
陈年档案配新代码,就是各种"用不了"。

本版把扫描要求版本提到当前版本(slot=14075 / font=14075):

  • 旧版升级上来的用户:装完第一次开机自动全量重扫槽位与字体档案(一次性)
  • 新装用户:本来就是首次扫描,不受影响
  • 同版本重装:也会重扫(方便自测,代价是这一次慢一点)
  • 想手动强制:touch /data/adb/custom_font_lib/.force_rescan 后重装

同时把永久索引的 schema 提到 3:升级后旧索引自动作废并重建,不会读到过期内容。

🐞 修「导入字体后界面不刷新」

根因是我上一版把"重建索引"写在了各命令的末尾,而那些分支几乎都是 exit 结尾 ——
退出之后的代码永远执行不到,于是索引一直旧、界面读旧数据。

现在改成打脏标记 + 退出时统一重建:不管命令是正常结束、exit 还是中途出错,
只要改过字体库,退出前都会重建一次索引;只读命令不标记,不会白白重建。

本机单测(模拟真实分支结构):

status(只读)  → 不重建索引   ✓
import(内部 exit)→ 重建      ✓
delete(正常结束)→ 重建       ✓

🗑 删除「同族字重自动配对」开关

它按字体内部族名自动把多份字体当成"同一套的不同字重"。问题是:族名相同不代表同一套字体
(拼包/改名字体很常见),混挂会缺字变方块,极端情况开不了机。

现在这件事交给字重组:用户手动勾选 + 五道校验(族名原文 / upem / 字形数 ±3% / 覆盖率 ±2 / 子族名不同),
安全得多。原有的 group= 数据继续有效,老用户的字重组不受影响。


自定义字体切换模块 v1.4.7.5

Choose a tag to compare

@github-actions github-actions released this 22 Oct 21:09

性能与手感优化 + 去掉一个高风险开关。界面首屏更快(一次交互代替两次串行),字体读取改分块(顺带解决大字体把管理器 WebView 撑爆的隐患),动效统一。「同族字重自动配对」开关删除,改由更安全的「字重组」承担。

⚡ 首屏:两次 exec → 一次

KernelSU 的 exec 是同步的(执行期间 WebView 的 JS 线程被占住),原来首屏要串行跑两次:

fontctl.sh list     ← shell 启动 + 解析 common/slots/mount + 脚本本身 ≈ 250KB
fontctl.sh status   ← 再来一次,且 status 里还要跑 slot_sources_report

现在新增 fontctl.sh quick:一次输出「状态 + 字体列表」,界面解析一次就渲染;
槽位来源统计(要跑外部进程的部分)改由后台补,不再挡首屏。

顺带删掉「字体列表被解析两遍」的重复代码。

🧠 字体读取改分块(修 OOM 隐患)

原来一次读整段,od 会把 1 字节变成 3 个字符 —— 4MB 二进制 ≈ 12MB 文本,
一次性通过同步桥接回传 WebView。解析 40MB 级大字体时很容易把管理器撑爆,
用户侧表现就是「点开 WebUI 直接闪退」。

现在每次最多 256KB 二进制(≈768KB 文本)循环拼接,硬上限 8MB;
单块失败只丢这一块,不打断整次探测。cmap 读取上限 4MB → 1MB,name 表 64KB → 32KB。

🎨 动效统一(原来生硬)

  • 统一缓动/时长令牌:--ease-out / --ease-emphasis / --dur-*
  • 字体卡片:依次错峰 18ms 上浮淡入(只播一次,不会每次刷新都重放)
  • 卡片/按钮:按压缩到 0.972 回弹,不再是"瞬间变色"
  • 底部菜单:translateY 过渡,可被打断(原来直接跳到位)
  • 提示条:改用 transition(不用 keyframes,避免再覆盖 translate(-50%) 的居中)
  • 首屏骨架屏:数据回来前显示呼吸占位,不再"空白一下再刷出来"
  • 长列表/报告区:content-visibility: auto,屏幕外不排版
  • 完整尊重 prefers-reduced-motion

修正一个我上一轮的失误:入场动画之前挂在 .card 上,而真实卡片类是 .option,等于没生效。

📦 渲染:离屏构建

字体列表原来逐张 append 到已在文档里的容器(每次 append 都可能触发布局),
现在全部塞进 DocumentFragment 后一次性插入,只重排一次。DOM 结构、事件、样式全部不变。

🗂 底层:引入永久索引(少算、少读、少猜)

新增 /data/adb/custom_font_lib/.index:一份纯文本的"当前真相"清单——

#CFS-INDEX 2
ver=v1.4.7.4   active=f1   pending=f110   rom=hyperos   mode=self   slots=96   fonts=6
font=f1|烈焰|44810240|size=…,vf=1,wght=400,fam=…,family=Demo Sans,group=f1
  • 谁维护:导入 / 删除 / 改名 / 应用 / 写档案 / 重扫 —— 每个会改字体库的命令结束时自动重建(临时文件 + mv 原子替换)
  • 谁读:界面首屏、诊断报告、需要清单的脚本 —— 直接 cat,不再现场 glob + 逐个读 .name/.meta
  • 自愈:索引缺失或 schema 版本不符时自动重建一次

⚡ 诊断报告提速:指纹缓存

完整报告的大头是给几百个字体算"稀疏指纹"(每个文件读头尾各 64KB)。但同一台机器上绝大多数字体是长期不变的。

新增 /data/adb/custom_font_lib/.fp.cache(路径 + 大小 + 修改时间 → 指纹):

  • 命中就直接复用,不读盘
  • 未命中才算,算完追加写回
  • 文件超过 5000 行自动压缩(保留每个路径的最后一条)
  • 缓存是可丢弃的加速层:删掉只会让下次慢一点,不影响任何结论

本机实测:

第 1 次:计算并写入缓存(1 行)
第 2 次:命中,结果一致,不读盘
内容变化(大小 200000 → 200001):判定 MISS,重新计算,哈希随之改变   ✓

🧹 卸载:真正删干净

  • 先卸挂载:按 $LIB/.mounted 逐个 umount -l,再扫 /proc/mounts 兜底 —— 卸载后字体立刻回原厂,不用重启
  • 保护共用字库:主项目与子项目共用 /data/adb/custom_font_lib。卸载前检查是否还有别的字体模块在,有就保留字库(原来会一起删掉,同时装两个模块的用户会丢数据)
  • 清临时文件:/data/local/tmp 下 .pv.* / .slots.clean.* / .oem.* / .marks.*
  • GMS 恢复失败那条路径原本也会清空字库内容,同样加了保护

🐞 修「卸载重装后 UI 还显示旧字体列表」

字体列表缓存存在管理器 App 的 localStorage 里,卸载模块不会清它 → 重装后界面先画出旧列表(文件已不存在),点切换会去操作不存在的字体(卡住),删除报「已删除 0 个」。

修法四层:

  1. 缓存带上模块版本,版本不一致直接丢弃
  2. 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
  3. 真实数据到达立刻解除未校验,并刷新缓存
  4. 缓存 TTL 24 小时 → 10 分钟

🎬 动效与手感

  • 统一缓动/时长令牌(--ease-out / --ease-emphasis / --dur-*)
  • 卡片错峰入场(18ms 级联)、按压缩放回弹
  • Toast 改为 transition(不再用 keyframes 覆盖居中);首屏骨架屏;长区块 content-visibility
  • 修正上一轮把入场动画挂在 .card(真实类是 .option)导致没生效的问题

🧠 字体预览不再吃内存

以前点开一个字体详情,会把整份字体字节留在内存里(你的字库有 40MB 级字体,
点开几个就是上百 MB)。现在:

  • 预览加载有总量上限 60MB,超了自动释放最久没用的那份(从 document.fonts 摘掉)
  • 关闭详情时立刻释放当前这份,内存可回收
  • 低内存机型上不会再因为"看了几个字体"就被系统挤掉

🎬 过渡与光效(一镜到底)

  • 面板/弹窗统一「淡入 + 轻微上浮」,关闭时反向(只动 transform/opacity,不触发布局)
  • 卡片:按压回弹、选中/待生效的外发光
  • 报告「结构化 ↔ 原文」切换加交叉淡入
  • 骨架 → 内容淡接
  • prefers-reduced-motion 下全部关闭(不跑动画)

⏱ 报告耗时改成毫秒

以前按秒计时,多数小节只能显示 0,看着"都差不多"。现在显示 12.3s / <0.1s,
一眼能看出哪一步真慢。

🧹 其它

  • .upload.log 加 64KB 上限(超了只留最后 200 行,不会写满存储)
  • 永久索引自愈:字体库里有比索引更新的字体文件(手工放入/外部改动)→ 自动重建
  • 服务端修复:上报 Worker 补上 CORS 与 OPTIONS 预检 —— 之前浏览器直接打开正常、
    但页面里的 fetch 会被拦(真机表现为"连不上服务器")

🔄 旧版升级上来会强制重扫一次(重要)

旧版本写下的档案缺字段(family / upem / subfamily),槽位清单也可能和新扫描逻辑对不上 ——
陈年档案配新代码,就是各种"用不了"。

本版把扫描要求版本提到当前版本(slot=14075 / font=14075):

  • 旧版升级上来的用户:装完第一次开机自动全量重扫槽位与字体档案(一次性)
  • 新装用户:本来就是首次扫描,不受影响
  • 同版本重装:也会重扫(方便自测,代价是这一次慢一点)
  • 想手动强制:touch /data/adb/custom_font_lib/.force_rescan 后重装

同时把永久索引的 schema 提到 3:升级后旧索引自动作废并重建,不会读到过期内容。

🐞 修「导入字体后界面不刷新」

根因是我上一版把"重建索引"写在了各命令的末尾,而那些分支几乎都是 exit 结尾 ——
退出之后的代码永远执行不到,于是索引一直旧、界面读旧数据。

现在改成打脏标记 + 退出时统一重建:不管命令是正常结束、exit 还是中途出错,
只要改过字体库,退出前都会重建一次索引;只读命令不标记,不会白白重建。

本机单测(模拟真实分支结构):

status(只读)  → 不重建索引   ✓
import(内部 exit)→ 重建      ✓
delete(正常结束)→ 重建       ✓

🗑 删除「同族字重自动配对」开关

它按字体内部族名自动把多份字体当成"同一套的不同字重"。问题是:族名相同不代表同一套字体
(拼包/改名字体很常见),混挂会缺字变方块,极端情况开不了机。

现在这件事交给字重组:用户手动勾选 + 五道校验(族名原文 / upem / 字形数 ±3% / 覆盖率 ±2 / 子族名不同),
安全得多。原有的 group= 数据继续有效,老用户的字重组不受影响。


自定义字体切换模块 v1.4.7.3

Choose a tag to compare

@github-actions github-actions released this 22 Oct 09:45

小改:诊断报告新增【16】字重组应用情况 —— 能看到「组里有哪几档字重、每个槽位实际用了哪一份、哪些槽位被跳过」,这类「粗体没生效 / 某处还是原字体」的问题以后只看报告就能定性。

🩺 诊断报告新增【16】字重组应用情况

【16】字重组应用情况(哪个槽位用了组里哪一档)
  当前选择:f110
  所属字重组:组长 f100
  ---- 组内成员 ----
    f100   字重 300   ← 组长
    f110   字重 400
    f120   字重 700
    f130   字重 800
  ---- 槽位 → 实际使用的文件 ----
    f110   → 42 个槽位
        system/fonts/NotoSansCJK-Regular.ttc
    f120   → 5 个槽位
        system/fonts/NotoSansCJK-Bold.ttc
  ---- 中文字重相关槽位明细(前 12 条)----
    NotoSansCJK-Regular.ttc  → f110  字重 400
    NotoSansCJK-Bold.ttc     → f120  字重 700
  ---- 被跳过的槽位(合集/结构校验)----
    f100 NotoSerifCJK-Regular.ttc … via=ttcbad detail=产物结构不合格,已删除并跳过

配合已有的【13】合集校验、【14】中文字形覆盖率,现在这三类问题都能从报告直接判断:

现象 报告里看哪一节
粗体没生效 / 粗细不均 【16】该槽位用的是哪一档
某处还是原字体 / 部分应用方块 【14】覆盖率 +【16】槽位映射
合集槽位(.ttc)没换 【13】结构校验与跳过原因

自定义字体切换模块 v1.4.7.2

Choose a tag to compare

@github-actions github-actions released this 22 Oct 07:09

热修:字重组一直报「档案里没有族名原文(请刷新页面后重新导入)」——重新导入也没用。已修。

🐞 修复:族名带空格的字体永远进不了字重组

真机现象:SourceHanSansTC-Light/Medium/Normal/ExtraLight/Heavy 五份一次全选,
弹窗对每一份都报「档案里没有族名原文(请刷新页面后重新导入)」。

原因在批量写档案那一步:

界面把多个字段用空格拼成一行:   f1 family=Source Han Sans TC upem=1000
后端按空格切分:                 family=Source / Han / Sans / TC
→ 写进去的族名是 "Source",或者整条失败 → 校验读不到族名原文

修法:界面一个字段一行(每行都带 id),后端按行解析、不再二次切分。

本机实测(写入 → 读回):

写入条数=3
family=Source Han Sans TC
upem=1000
subfamily=Light
读回 family → Source Han Sans TC ✓

🔁 老字体不用重新导入

原来只在「缺族名键 fam」时才补档案。现在改成缺 fam / family / upem / subfamily
任一项都会重新探测并自动补写 —— 升级后打开一次界面,之前导入的字体就会补齐,直接可以组合。