编程语言研究书库

WebAssembly 进移动应用 — 一份逻辑,两端原生

WebAssembly 进移动应用 — 一份逻辑,两端原生

1. 这一章讲什么

移动开发的老痛点:Android 一套(Java/Kotlin)、iOS 一套(Swift/Objective-C), 性能要原生就得双倍维护。React Native/Flutter 解决了 UI 层共享, 但计算密集的任务在 JS/Dart 里还是慢。这一章的位置:Wasm 只接管逻辑层—— 图像滤镜、加密、压缩、小模型推理写成一份模块,两端嵌;UI 照旧各端原生。 这是「Wasm 出浏览器」路线图上最后一站(设备侧)。1

2. 顶层全景

  写一次:Rust / C++ / AssemblyScript → .wasm
      │
      ├── React Native:JS 层 instantiateStreaming(Metro 要认 .wasm)
      ├── Flutter:编译成 .so/.dylib → dart:ffi 直调
      ├── Android 原生:WebView,或 JNI 加载 .so(System.loadLibrary)
      └── iOS 原生:WKWebView,或 Wasmer 嵌入 + FFI(dlopen/dlsym)
      │
      ▼
  界面不动:Jetpack Compose / SwiftUI / RN / Flutter 照旧

图说:四个落点一个产物;选择落点 = 选择「离原生多近」。

3. 核心原理

3.1 价值主张,一句话四层

  1. 逻辑统一:性能模块一份,Android/iOS 行为一致,更新只换 .wasm;
  2. 近原生速度:AOT 编译,压过 RN 的 JS 和 Flutter 的 Dart 热路径;
  3. 界面不动:Wasm 不碰 UI,互补而非替代;
  4. 多语言:Rust(安全)、C/C++(老库复用,如 OpenCV)、AssemblyScript(JS 开发者友好)。2

3.2 四个落点,各怎么接

React Native:引擎是 JavaScriptCore(iOS 系 RN 的默认 JS 引擎), 支持 Wasm,所以 Web 那套 instantiateStreaming(fetch('module.wasm')) 基本照搬。 两个工程细节:Metro 打包器要配置认 .wasm(metro.config.js 里加 assetExts: ['wasm']),文件读取靠 react-native-fs。 短板书里没藏:JavaScriptCore 的 SIMD 和多线程支持不全,要换 V8 系引擎才行。3

Flutter:Dart 没有原生 Wasm 执行,正路是编译成共享库(.so Android / .dylib iOS),dart:ffi 直调——书里的例子五行讲透:4

final dylib = DynamicLibrary.open('libwasm_math.so');
final add = dylib.lookupFunction<
    Int32 Function(Int32, Int32), int Function(int, int)>('add');
print(add(2, 3)); // 5

lookupFunction 把 C 函数签名和 Dart 函数类型一一对应,没有中间桥。 复杂交互走 platform channel(Dart ↔ 原生代码的通用消息通道)。5

Android 原生:两条路。WebView 里跑(能跑,但隔了一层浏览器); 正经路是 JNI(Java Native Interface,Java/Kotlin 调原生代码的标准桥): Rust 用 #[no_mangle] extern "C" 暴露 C 签名函数,经 NDK 编成 .so, Java 侧 System.loadLibrary("wasm_math") 加载、public native int add(int, int) 声明后直接调。6

iOS 原生:WKWebView 里 evaluateJavaScript 跑 Wasm(书里的 Swift 例); 或者更原生:Wasmer 等运行时嵌进 App,经 FFI(外部函数接口)绑定, dlopen/dlsym 那套 Unix 传统手艺。挑战两条:Android 碎片化(ARMv7/ARM64/x86_64 三套架构都要测)、iOS 沙箱严(系统资源基本不给,除非走原生绑定)。7

3.3 模块怎么造

Rust 流程(书里的完整步骤):cargo new wasm_math --lib → #[wasm_bindgen] pub fn add(a: i32, b: i32) -> i32 → wasm-pack build --target web 出 .wasm + JS 胶水;要更深集成时,不走 Wasm 产物而是直接编共享库—— Rust 编译 Android .so / iOS .dylib,用 cbindgen 生成 C 头文件给 JNI/FFI 用, wasm-opt 压体积。8

这个细节值得停一下:移动端经常跳过了 .wasm 这一步,直接上原生库 ——因为目标平台已知,不需要 Wasm 的可移植层。Wasm 在这里的价值退化为 「开发期的可移植与测试载体」和「逻辑统一的中立格式」。书里两种都讲,没替你选。

3.4 优化与用例

移动端优化五招:SIMD(std::simd / Emscripten intrinsics)、多线程 (移动 JSC 普遍不支持,书里说得很实在)、模块缓存(编译结果存 AsyncStorage/SharedPreferences,免重复解析)、流式编译、AOT 预编译 (Lucet 把模块预编译成原生码,近零启动——实时视频剪辑这类场景用)。9

四个主力用例,每个都对应一组现成库:图像/视频处理(Rust 滤镜)、端上 AI 推理 (决策树(一层层 if-else 式分类)、k-NN 这类小模型)、密码学(SHA-256/签名/加密,沙箱加持)、 压缩(zstd/Brotli 编进 Wasm,上传前压)。10

3.5 主线例子:照片编辑应用(书里的真实场景走查)

一个跨平台照片 App,核心需求:高斯模糊、边缘检测、动态裁剪、上传前压缩。 (以下步骤是把本章机制组装成的完整走查;库名与接口出自原书。)

第 1 步:写模块。 Rust 实现滤镜与压缩,#[wasm_bindgen] 标出对外函数。11

第 2 步:双产物构建。 Web/RN 侧:wasm-pack build --target web 出 .wasm;原生侧:Rust 经 NDK 编 Android .so、Xcode 工具链编 iOS .dylib, cbindgen 出头文件。12

第 3 步:两端接入。 RN 版走 JS instantiateStreaming;Flutter 版走 dart:ffi DynamicLibrary.open;原生版走 JNI / FFI。13

第 4 步:收益对账(书里的原话要点)。 两端行为一致;不送两份平台原生库, 包体更小;性能不减;更新只换 .wasm 或 .so,不用重新过审双端二进制。14

第 5 步:上线纪律。 wasm-opt 剥未用代码、模块按职责拆分(图像一个、加密一个)、 多架构全测、老 WebView 环境备 JS 兜底、.wasm 打进 assets 或走 HTTPS、CI 双端测。15

3.6 未来五条与工具

趋势:Wasm GC(让 Dart/JS 系语言进 Wasm)、移动原生运行时(Wasmer Mobile、 Lucet 嵌入,绕开 WebView)、云端 Wasm + 端上协同、WASI 上手机 (文件/网络能力)、两家 WebView 的 Wasm 支持持续变好(SIMD/线程)。16

工具认名字:wasmer-mobile(嵌入运行时)、wasm-bindgen(RN 胶水)、 wasm-pack、Emscripten、Binaryen、Lucet(AOT)。17

4. 作者的判断与证据

  • 「RN 的 JavaScriptCore 支持 Wasm」:属实,但 SIMD/线程短板写得也属实,平衡;
  • 「Wasm 模块显著小于两份原生库」:方向对(一份替代两份),「显著」无实测;
  • 「iOS 严格沙箱限制 Wasm 系统访问」:准确;
  • 工具一节的质量参差(把 ScyllaDB/PostgreSQL 列为「移动工具」), 是本书编辑粗糙的典型痕迹。

判断(我们的,不是书里的): 本章最诚实也最容易被读漏的一点,是 3.3 那个 「跳过 .wasm」的分叉:一旦目标平台固定为 Android+iOS,直接编共享库往往比 嵌入 Wasm 运行时更简单更快——Wasm 在移动端的真实卖点其实是 「逻辑的中立载体 + 跨端一致性」,而不是性能(性能上原生库不吃亏)。 如果错,会错在: 如果 Wasm GC 与 Component Model 成熟到「一份组件四端直跑、 免 FFI 胶水」,性能与体积的天平才会真正倒向 Wasm 产物——那是本章「未来趋势」 里押注的方向,落地时间未定。

5. 边界与局限

  • 没有实测性能表:全书移动端零 benchmark,「near-native」始终是无数据断言;
  • JS 引擎差异只说了一半:不同 RN 版本/不同厂商引擎的 Wasm 行为差异没有展开;
  • Flutter 的 Wasm 官方路线(Dart 编译到 Wasm,WasmGC 落地后)未提,是重要遗漏;
  • 更新分发只说「换二进制」,应用商店的审核与热更新政策约束没讲。

6. 可带走的

  1. 移动端 Wasm 的正确定位:逻辑层共享,UI 照旧原生;别拿它替 UI。
  2. 四个落点按「离原生远近」选:RN/Flutter 框架内 → WebView → JNI/FFI 原生。
  3. RN:Metro 认 .wasm + react-native-fs;JSC 无 SIMD/线程。
  4. Flutter:编译 .so/.dylib,dart:ffi lookupFunction 直调,复杂交互走 platform channel。
  5. Android JNI:System.loadLibrary + public native 声明;Rust 侧 #[no_mangle] extern "C"。
  6. iOS:WKWebView 能跑但隔层;要原生用 Wasmer 嵌入 + dlopen/dlsym。
  7. 平台固定时,直接编共享库可能比嵌 Wasm 运行时更简单——Wasm 的卖点转向「中立格式 + 一致性」。
  8. 优化五招:SIMD、线程(受限)、模块缓存、流式、AOT(Lucet)。
  9. 用例四件套:图像、端上小模型、密码学、压缩。
  10. 上线:多架构(ARMv7/ARM64/x86_64)、模块拆分、JS 兜底、CI 双端。

7. 原文地图

主题原书章原文位置
移动端问题与 Wasm 定位WebAssembly in Mobile Appstext/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:51(搜「separate codebases」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:57(搜「write logic once」)
集成点:JNI/NDK/FFI/WebView同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:253(搜「Java Native Interface」)
RN 配置与限制同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:497(搜「assetExts」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:555(搜「lack SIMD」)
Flutter dart:ffi 例同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:601(搜「DynamicLibrary.open」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:605(搜「Outputs 5」)
Android JNI 例同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:785(搜「System.loadLibrary」)
iOS WKWebView 与 FFI同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:837(搜「evaluateJavaScript」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:853(搜「dlopen/dlsym」)
模块构建与 cbindgen同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:705(搜「--target web」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:741(搜「cbindgen」)
优化五招同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:873(搜「SIMD Extensions」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:911(搜「Lucet」)
用例四件套同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:931(搜「Image/Video Processing」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:953(搜「zstd」)
部署最佳实践同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:973(搜「Module Size」) · text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:987(搜「ARMv7」)
未来趋势同上text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:1045(搜「Future Trends」)

Footnotes

  1. 出处:「WebAssembly in Mobile Apps」第 49–57 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:51,搜「separate codebases」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:57(搜「write logic once」)。 ↩

  2. 出处:「WebAssembly in Mobile Apps」第 59–151 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:65,搜「performance-critical modules」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:101(搜「logic layer」)。 ↩

  3. 出处:「WebAssembly in Mobile Apps」第 455–557 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:497,搜「assetExts」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:555(搜「lack SIMD」)。 ↩

  4. 出处:「WebAssembly in Mobile Apps」第 559–623 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:601,搜「DynamicLibrary.open」)。 ↩

  5. 出处:「WebAssembly in Mobile Apps」第 607–623 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:607,搜「Platform Channels」)。 ↩

  6. 出处:「WebAssembly in Mobile Apps」第 755–809 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:785,搜「System.loadLibrary」)。 ↩

  7. 出处:「WebAssembly in Mobile Apps」第 811–865 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:853,搜「dlopen/dlsym」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:863(搜「fragmented ecosystem」)。 ↩

  8. 出处:「WebAssembly in Mobile Apps」第 631–753 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:705,搜「--target web」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:741(搜「cbindgen」)。 ↩

  9. 出处:「WebAssembly in Mobile Apps」第 867–923 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:911,搜「near-zero startup time」)。 ↩

  10. 出处:「WebAssembly in Mobile Apps」第 925–965 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:953,搜「zstd」)。 ↩

  11. 出处:「WebAssembly in Mobile Apps」第 423–447 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:433,搜「Gaussian blur」)。步骤编排为演示结构,机制与工具名均出自原书。 ↩

  12. 出处:「WebAssembly in Mobile Apps」第 723–735 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:729,搜「.dylib」)。 ↩

  13. 出处:「WebAssembly in Mobile Apps」第 165–175 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:169,搜「native bridge」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:173(搜「platform channels」)。 ↩

  14. 出处:「WebAssembly in Mobile Apps」第 439–447 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:441,搜「Runs identically on Android and iOS」)。 ↩

  15. 出处:「WebAssembly in Mobile Apps」第 967–1043 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:985,搜「multiple architectures」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:1005(搜「JavaScript implementation」)。 ↩

  16. 出处:「WebAssembly in Mobile Apps」第 1045–1085 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:1051,搜「Wasm GC」)与 text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:1059(搜「Wasmer Mobile」)。 ↩

  17. 出处:「WebAssembly in Mobile Apps」第 1087–1143 段(text/23-fm-ultimate-webassembly-for-high-performance-apps-b.txt:1117,搜「wasmer-mobile」)。 ↩

On this page