Repository navigation
mp-flutter 0.2.0
在 0.1.0 的基础上补齐三类运行时缺口(随机数、路由切换崩溃、图片离屏解码)、修复两处
真机启动/渲染问题(iOS 白屏、部分安卓启动失败),并完成一轮包体积与冷启动性能收尾
(分包重组、常用汉字合一字体、原生图片解码、字体缓存)。
运行时缺口补齐
Random.secure()/crypto.getRandomValues/crypto.randomUUID:小程序逻辑层没有
window.crypto,之前直接抛Unsupported。现在启动时用wx.getRandomValues取一次真随机
种子,喂给 ChaCha20(RFC 8439)当确定性随机数发生器,之后本地同步产出;重播种失败自动换钥、
取熵 10 秒超时、计数器回绕前换钥;播种提前到loadSubpackages阶段与 CanvasKit 加载并行发
起,不阻塞启动关键路径,播种失败/超时按浏览器无该 API 的标准语义处理,不伪造安全性- 路由切换崩溃修复:滚动帧密集时 push/pushReplacement 偶发触发
Null check operator used on a null value/Cannot read properties of null (reading 'cullRect')(CanvasKit 渲染管线内部)。根因是垫片缺self.scheduleImmediate,导致 Dart
微任务退化为setTimeout调度,下一帧得以插进draw()的await与 preroll 之间,读到一张
在途 dispose 的SkPicture。已修复;复测未再复现该崩溃 Image.cacheWidth/cacheHeight与toByteData():小程序画布拿不到通用离屏 2D 上下文,
改由runtime/image.js的 SoftCanvas 用 CanvasKit CPU 光栅 surface 实现(drawImage/
getImageData/toDataURL/transferToImageBitmap);toByteData(rawRgba)返回非预乘
RGBA 像素(与浏览器一致,与 Flutter 原生平台预乘不同);大图toByteData峰值内存约为
宽×高×4的 3 倍,压在 wasm 堆上
微信隐私接口
--private-info=<接口名>(可重复)/mp_flutter.yaml的private_infos:按需声明任意
隐私接口(getLocation/chooseLocation/choosePoi等),写入app.json的
requiredPrivateInfos与对应权限说明;--require-location保留为等价于
--private-info=getLocation的历史开关
体积与冷启动
- 首帧前只加载必需分包:以前 boot 在首帧前并行拉取全部分包(某真实电商小程序约 10MB);现在
只拉pkg-dart-*、pkg-wasm与新的启动资源包pkg-assets-boot(FontManifest/
AssetManifest、清单里声明的字体、回退 Roboto),其余资源按需下载。该真实电商小程序首帧前阻塞
下载 10.04MB → 6.33MB(不在预下载里的 8.26MB → 4.45MB;当前默认cjk_font: full
下的数字,含独立分包pkg-cjk的约 1.1MB——见下方"常用汉字合一字体") - 资源分包重组:NOTICES 单独放
pkg-notices;简体中文回退字体分片按"常用字优先 +
码位邻近"分进约 512KB 的pkg-fonts-*;其余资源按路径分进约 512KB 的pkg-assets-* --no-licenses/licenses: false:NOTICES 换成空占位(许可证页仍可打开,只是不列出
第三方包)font_base_url/--font-base-url:实际移到远端的是notosanssc(简体中文回退,全部
101 个分片)——roboto始终留在包内;emoji/日文/韩文/繁体等其余家族本来就不打包(不受
这个开关影响,一直是 404)。运行时从 CDN 拉取并缓存到本地文件(10MB 上限,LRU);产物下
输出待上传目录mp-fonts-remote/- 原生启动界面:首帧前显示应用名(
splash_title)、背景色(splash_color)与进度条,
启动失败时显示错误文案 - 构建成功提示里提醒:开发者工具界面打开产物时需取消「将 JS 编译成 ES5」「增强编译」
字体到达引发的整体重排
- 常用汉字合一字体(
cjk_font: level1 | full | false,--cjk-font=level1|full/--no-cjk-font,
默认 full):Noto Sans SC v37 子集(level1 = GB2312 一级 + 标点/全角/Latin-1/常用符号,TTF 1.2MB;
full = 一二级,2.2MB;入库,tools/fonts/gen_cjk_common.py可复现),brotli 后放独立分包pkg-cjk,
boot 一开始就用readCompressedFile读出、CanvasKit 就绪即预解析,引擎初始化时直接应答;
main.dart.js构建期补丁让引擎把它当作 Roboto 之后的第一个回退字体、缺字检测时算上它并只把
真正缺的码点交给选字体算法。该真实电商小程序(开发者工具,full)首屏回退分片 fetch 20→0、fontsChange 5→0、50ms 长帧 3–4→0。真机数据显示
full不在首帧关键路径上(字体读取 28–30ms,首帧 354/533ms),
而level1会因服务端下发文案命中二级字/常用符号触发额外回退分片下载与 fontsChange,因此把
默认从 level1 改为 full。注意:cjk_font默认开启会给总包增加约 1.1MB(pkg-cjk,brotli
后约 1.15MB,该真实电商小程序实测总包 10.05MB → 11.21MB);服务商代开发小程序总包上限 20MB,总包已经
接近上限的应用升级前请确认还有余量,或用--cjk-font=level1/--no-cjk-font收窄/关闭 - 常用符号子集扩充:iPhone 真机首屏仍触发一次 NotoSansSC v37 分片 119(
NexQ2w.119.woff2)
下载并引发一次 fontsChange、215ms 长帧;字表补充通用标点 U+2000–206F、箭头 U+2190–21FF、
€℃№™、常用数学运算符(∑√∞∫≈≠≤≥)、带圈数字 ①–⑳、制表符小集合(┌┐└┘├┤┬┴┼─│)与
几何图形/五角星(●○■□▲△▼▽◆◇★☆);level1 TTF 1,152,356→1,166,672 字节(br 662,319→664,089),
full TTF 2,149,868→2,170,200 字节(br 1,171,426→1,173,234),仍远低于单分包 2MB 上限 - 同一份字体字节只解析一次(引擎每注册一批回退字体都重注册全部字体,不再重复解析)
- 回退字体响应按 100ms 窗口合并,窗口内的多批缺字只触发一次 fontsChange
- 同一个未下载的按需分包只发一次
require.async(安卓真机字体 fetch 恰好 1001–1003ms 的疑因) --perf-hud:cjk-font pkg/read/parse/引擎取用等待首帧前诊断行、font-change #n与每秒行的
fontChange=、字体解析复用次数(reuse n)
修复
- iOS 真机白屏(
UnimplementedError: v8BreakIterator is not supported.)
与部分安卓真机启动失败(ReferenceError: Intl is not defined):改为打包
完整版 CanvasKit(wasm 自带 ICU 断行,不依赖Intl.Segmenter/
Intl.v8BreakIterator),iOS/安卓/模拟器统一只打这一个变体;为放进单个分包,
构建期清零 ICU 里泰/老/高棉/缅文的断词词典(这四种文字词内不再给换行机会)。
pkg-wasm分包由约 1573KB 增至约 1822KB。垫片对Intl等可能缺失的宿主
全局改为typeof探测,没有 Intl 时给引擎一个只有Locale的最小替身 --force-platform新增ios(遮蔽Intl.v8BreakIterator/Intl.Segmenter)与
android-noIntl(遮蔽整个Intl),tools/e2e/run.sh新增同名配置,在开发者
工具里复现真机 JS 引擎的能力缺失
性能批次收尾
- 原生图片解码生命周期:成功后立即释放已解码字节(按需从临时文件读回),临时文件不再
与单份SkImage.delete()绑定(真机上引擎会反复对同一原生图片对象请求/丢弃惰性
SkImage,没有真正意义上的"最后一次",绑定会在下一次请求时出错);改为总字节数
(64MB)顶到上限时才淘汰已使用且最久未用的文件,淘汰/磁盘空间不足/总字节超限均不计入
原生解码失败计数 cacheWidth缩放遇到"整块全透明"时,先用 wasm 解一遍源图确认不是真透明才判定 2D 画布
不可用,避免误判真正透明的图片--perf-hud相关代码(perf-hud.js、图片统计对象)只在开关打开时才写进产物/构造,不
影响未开启时的产物体积与运行时开销- 合一字体(
cjk_font)读取加 10 秒超时,超时按读取失败处理,不阻塞启动 - 远端字体缓存索引(
font-cache.js)命中时节流写index.json(2 秒一次)