Repository navigation
Releases: ayss2188/custom-font-switcher
Release list
自定义字体切换模块 v1.4.9.5
本版修复:更新流程(与子项目同步的那套修法),界面和功能与 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
对比基准:线上版本 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
🐞 大 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 自己闪退时的三个备用入口:
- 管理器模块卡片的「操作」按钮
- 模块目录里的
抓日志-开始.sh/抓日志-停止导出.sh(MT 管理器点执行即可) - 命令行:
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
🐞 修「魅族上什么都替换不了」(槽位计划变成 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
🐞 修「切换字体后界面不刷新」
现象:选完配色/字体,提示条说"已选择…",但卡片还标着旧的「当前」,顶部数字也不动。
原因:刷新函数开头有"已在刷新就跳过"的闸门(防止并发刷新),而切换完成时正好撞上
另一次刷新在跑(补族键/定时刷新),这次调用直接返回、也不报错 → 界面停在旧状态。
已修:切完立刻本地更新卡片状态 → 直接刷顶部 → 再全量刷新 → 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 个」。
修法四层:
- 缓存带上模块版本,版本不一致直接丢弃
- 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
- 真实数据到达立刻解除未校验,并刷新缓存
- 缓存 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
🐞 修「更新时一直卡在『正在安装中』」
现象:点「下载并安装」后进度条停在「正在安装中」,管理器里其实已经装好了。
原因:安装是把管理器命令放后台跑、等它写退出码。但 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 个」。
修法四层:
- 缓存带上模块版本,版本不一致直接丢弃
- 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
- 真实数据到达立刻解除未校验,并刷新缓存
- 缓存 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
🐞 修「魅族 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 个」。
修法四层:
- 缓存带上模块版本,版本不一致直接丢弃
- 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
- 真实数据到达立刻解除未校验,并刷新缓存
- 缓存 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
性能与手感优化 + 去掉一个高风险开关。界面首屏更快(一次交互代替两次串行),字体读取改分块(顺带解决大字体把管理器 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 个」。
修法四层:
- 缓存带上模块版本,版本不一致直接丢弃
- 缓存画出的列表标记为未校验:此时点卡片只提示"正在校验字体列表…",绝不下发命令
- 真实数据到达立刻解除未校验,并刷新缓存
- 缓存 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
小改:诊断报告新增【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
热修:字重组一直报「档案里没有族名原文(请刷新页面后重新导入)」——重新导入也没用。已修。
🐞 修复:族名带空格的字体永远进不了字重组
真机现象: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
任一项都会重新探测并自动补写 —— 升级后打开一次界面,之前导入的字体就会补齐,直接可以组合。