Skip to content

fix: work around broken WebAssembly streaming compile in Android WebView - #26

Open
sunbird89629 wants to merge 1 commit into
Sjj1024:mainfrom
sunbird89629:fix/webview-wasm-streaming
Open

fix: work around broken WebAssembly streaming compile in Android WebView#26
sunbird89629 wants to merge 1 commit into
Sjj1024:mainfrom
sunbird89629:fix/webview-wasm-streaming

Conversation

@sunbird89629

@sunbird89629 sunbird89629 commented Jul 23, 2026

Copy link
Copy Markdown

背景

部分网站在播放高码率 / 4K 视频时,会加载一个 wasm 软解码器(wasm-bindgen 生成的 glue),通过 WebAssembly.instantiateStreaming / compileStreaming(流式编译)来实例化。

在一部分 Android System WebView 上,这条「流式编译」管线有缺陷:即使 .wasm 文件本身已经 200 application/wasm 正常下载,流式编译仍然抛出:

TypeError: Failed to execute 'compile' on 'WebAssembly':
An argument must be provided, which must be a Response or Promise<Response> object

结果就是用 PakePlus 打包出来的 App 里,这类站点 4K 视频黑屏、播放器报错;而同一个网址在桌面 / 移动版 Chrome 里播放完全正常

根因

我在一台 Pixel 8(Android 16 / WebView 150.0.7871.124)上,通过 WebView 远程调试(chrome://inspect)在页面上下文里做了实测对比:

操作 结果
fetch(wasm) ✅ 200,application/wasm,Response 正常
是否有请求失败(loadingFailed
WebAssembly.compileStreaming(fetch(...)) ❌ 抛上面那个错
fetch → arrayBuffer → WebAssembly.compile(buffer) ✅ 成功
把 UA 伪装成真 Chrome 后重试 ❌ 仍然失败(排除了「网站按 UA 拦截」的猜测)

结论:根因是该 WebView 的流式编译实现有缺陷,与网络、UA、WebView 版本新旧都无关。而非流式路径(先把 wasm 下载成 ArrayBuffercompile)在同一个 WebView 上完全正常。Chrome 用的是完整引擎,所以流式编译不受影响。

改动

新增一个很小的 shim(app/src/main/assets/wasm-streaming-shim.js),在 onPageStarted 里、custom.js 注入之前注入。它覆盖 compileStreaming / instantiateStreaming,采用 「先试原生、抛错再降级」 策略:

  • 正常设备:原生流式编译成功 → 零影响,仍走原来的快路径(边下边编译、更省内存)。
  • 受影响设备:原生流式抛错 → catch 后降级为 fetch → arrayBuffer → compile/instantiate

只在真正失败时才兜底,不牺牲正常设备的性能。注入用的是仓库已有的 assets.open(...).evaluateJavascript(...) 套路(和现有 custom.js / vConsole.js 同款),不引入新依赖、不改打包流程。

改动只涉及两个文件:

  • app/src/main/assets/wasm-streaming-shim.js(新增)
  • app/src/main/java/com/app/pakeplus/MainActivity.kt(+3 行)

验证

在 Pixel 8 上用打包出的 release APK 做了双向验证(冷启动,无任何调试注入):

  • 修复生效:进入一部 4K 剧集点播放,不再出现 WebAssembly 报错遮罩,视频正常播放(video.readyState === 4paused === false、进度正常推进)。
  • 正常路径不回归:用一个合法 wasm 走原生 compileStreaming,编译成功、未进入 fallback 分支——说明「先试原生」确实生效,正常设备不会被无谓降级。

截图对比

修复前(报错遮罩):

before

修复后(4K 正常播放):

after

复现环境

  • 设备:Pixel 8 / Android 16 / Android System WebView 150.0.7871.124
  • 现象站点:某个用 wasm 软解码器播放 4K 的视频站(播放器为 artplayer + wasm-bindgen glue)

Some Android System WebView builds throw on WebAssembly.compileStreaming /
instantiateStreaming even when the .wasm is fetched correctly (200
application/wasm). This breaks sites that load a wasm video decoder for 4K
playback, while the same URL plays fine in Chrome.

Inject a small shim (assets/wasm-streaming-shim.js) in onPageStarted, before
custom.js, that tries native streaming first and only falls back to
fetch -> arrayBuffer -> compile on failure. Healthy engines keep the fast
path; affected ones auto-recover.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant