引言:为什么 iOS/macOS 开发者需要 WebAssembly?
WebAssembly (Wasm) 是一种二进制指令格式,最初为浏览器创建,但很快在原生开发中找到了用武之地。对于从事 iOS 和 macOS 开发的 Swift 开发者来说,WebAssembly 集成开辟了独特的机会:您可以重用使用 C/C++、Rust 或 Go 编写的高性能代码,而无需用 Swift 重写,并能以接近原生的速度运行它。这尤其适用于处理图形、密码学、模拟和复杂算法。
在本文中,我们将介绍如何将代码编译为 Wasm,将其集成到针对 iOS/macOS 的 Swift 项目中,传递数据以及处理错误。所有示例均使用 Swift 5.9+ 编写,并针对 Xcode 15+。
1. 为 Swift 项目将代码编译成 WebAssembly
第一步是获取 Wasm 模块。最流行的方法是使用 Emscripten 或 WasmEdge 编译 C/C++ 代码。让我们看一个 C 语言的示例。
创建一个文件 math_ops.c:
// math_ops.c#include <emscripten.h>
EMSCRIPTEN_KEEPALIVEint add(int a, int b) { return a + b;}
EMSCRIPTEN_KEEPALIVEdouble multiply(double a, double b) { return a * b;}
EMSCRIPTEN_KEEPALIVEint factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);}使用 Emscripten 将其编译成 Wasm(通过 Homebrew 安装:brew install emscripten):
emcc math_ops.c -o math_ops.wasm -s WASM=1 -s EXPORTED_FUNCTIONS='["_add", "_multiply", "_factorial"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -O3结果,您将得到文件 math_ops.wasm 和 math_ops.js(js 包装器不需要;我们将直接使用 Wasm)。
2. 将 Wasm 模块集成到 Swift 中 (iOS/macOS)
为了在原生 Swift 中处理 WebAssembly,我们将使用 WasmKit 或 SwiftWasm 框架。我们推荐 WasmKit——它支持 iOS 15+ 和 macOS 12+。
2.1. 通过 Swift Package Manager 安装 WasmKit
在 Package.swift 或通过 Xcode 添加依赖项:文件 → 添加包 → https://github.com/swiftwasm/WasmKit。
2.2. 加载并执行 Wasm 模块
创建一个 Swift 文件 WasmEngine.swift:
import WasmKitimport Foundation
class WasmEngine { private var instance: Instance? private var store: Store? /// 从文件加载 Wasm 模块 func loadModule(from url: URL) throws { let data = try Data(contentsOf: url) let module = try Module(data: data) let engine = Engine() store = Store(engine: engine) let imports = Imports() // 这里可以添加来自 Swift 的函数导入(参见第 3 节) instance = try Instance(module: module, imports: imports, store: store!) } /// 调用导出的函数 func callFunction(_ name: String, args: [Value]) throws -> [Value] { guard let instance = instance else { throw WasmError.moduleNotLoaded } let function = instance.exports[name] as! Function return try function(args) }}
enum WasmError: Error { case moduleNotLoaded case functionNotFound}2.3. 在 SwiftUI 应用程序中使用
import SwiftUI
struct ContentView: View { @State private var result: String = "0" private let engine = WasmEngine() var body: some View { VStack(spacing: 20) { Text("结果: \\(result)") .font(.title) Button("计算 5 的阶乘") { do { let wasmURL = Bundle.main.url(forResource: "math_ops", withExtension: "wasm")!