Einleitung: Warum WebAssembly für iOS/macOS-Entwickler?
WebAssembly (Wasm) ist ein binäres Befehlsformat, das ursprünglich für Browser entwickelt wurde, aber schnell Anwendung in der nativen Entwicklung gefunden hat. Für Swift-Entwickler unter iOS und macOS eröffnet die Integration von WebAssembly einzigartige Möglichkeiten: Sie können hochperformanten Code in C/C++, Rust oder Go wiederverwenden, ohne ihn in Swift umschreiben zu müssen, und ihn mit nahezu nativer Geschwindigkeit ausführen. Dies ist besonders relevant für die Arbeit mit Grafik, Kryptographie, Simulationen und komplexen Algorithmen.
In diesem Artikel werden wir behandeln, wie man Code in Wasm kompiliert, ihn in ein Swift-Projekt für iOS/macOS integriert, Daten übergibt und Fehler behandelt. Alle Beispiele sind in Swift 5.9+ geschrieben und für Xcode 15+ ausgelegt.
1. Kompilierung von Code in WebAssembly für ein Swift-Projekt
Der erste Schritt ist, ein Wasm-Modul zu erhalten. Der gängigste Weg ist die Kompilierung von C/C++-Code mit Emscripten oder WasmEdge. Betrachten wir ein Beispiel in C.
Erstellen Sie eine Datei 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);}Kompilieren Sie es mit Emscripten in Wasm (Installation über 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"]' -O3Als Ergebnis erhalten Sie die Dateien math_ops.wasm und math_ops.js (der js-Wrapper wird nicht benötigt, wir arbeiten direkt mit Wasm).
2. Integration des Wasm-Moduls in Swift (iOS/macOS)
Für die Arbeit mit WebAssembly in nativem Swift verwenden wir das Framework WasmKit oder SwiftWasm. Wir empfehlen WasmKit – es unterstützt iOS 15+ und macOS 12+.
2.1. Installation von WasmKit über den Swift Package Manager
Fügen Sie die Abhängigkeit in Package.swift oder über Xcode hinzu: File → Add Packages → https://github.com/swiftwasm/WasmKit.
2.2. Laden und Ausführen des Wasm-Moduls
Erstellen Sie eine Swift-Datei WasmEngine.swift:
import WasmKitimport Foundation
class WasmEngine { private var instance: Instance? private var store: Store? /// Lädt das Wasm-Modul aus einer Datei 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() // Hier können Importe von Funktionen aus Swift hinzugefügt werden (siehe Abschnitt 3) instance = try Instance(module: module, imports: imports, store: store!) } /// Ruft eine exportierte Funktion auf 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. Verwendung in einer SwiftUI-Applikation
import SwiftUI
struct ContentView: View { @State private var result: String = "0" private let engine = WasmEngine() var body: some View { VStack(spacing: 20) { Text("Ergebnis: \\(result)") .font(.title) Button("Fakultät von 5 berechnen") { do { let wasmURL = Bundle.main.url(forResource: "math_ops", withExtension: "wasm")! try engine.loadModule(from: wasmURL) let output = try engine.callFunction("_factorial", args: [.i32(5)]) if case let .i32(value) = output.first { result = String(value) } } catch { result = "Fehler: \\(error.localizedDescription)" } } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) } .padding() }}