Introduction : pourquoi WebAssembly pour un développeur iOS/macOS ?
WebAssembly (Wasm) est un format d'instructions binaires initialement conçu pour les navigateurs, mais qui a rapidement trouvé des applications dans le développement natif. Pour les développeurs Swift sous iOS et macOS, l'intégration de WebAssembly ouvre des possibilités uniques : vous pouvez réutiliser du code haute performance en C/C++, Rust ou Go sans le réécrire en Swift, et l'exécuter à une vitesse quasi native. C'est particulièrement pertinent pour le travail avec les graphismes, la cryptographie, les simulations et les algorithmes complexes.
Dans cet article, nous allons voir comment compiler du code en Wasm, l'intégrer dans un projet Swift pour iOS/macOS, transférer des données et gérer les erreurs. Tous les exemples sont écrits en Swift 5.9+ et destinés à Xcode 15+.
1. Compilation du code en WebAssembly pour un projet Swift
La première étape consiste à obtenir un module Wasm. La méthode la plus courante est de compiler du code C/C++ avec Emscripten ou WasmEdge. Prenons un exemple en C.
Créez le fichier 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);}Compilez-le en Wasm avec Emscripten (installez via 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"]' -O3En résultat, vous obtiendrez les fichiers math_ops.wasm et math_ops.js (l'enveloppe js ne sera pas nécessaire, nous travaillerons directement avec Wasm).
2. Intégration du module Wasm dans Swift (iOS/macOS)
Pour travailler avec WebAssembly en Swift natif, nous utiliserons le framework WasmKit ou SwiftWasm. Nous recommandons WasmKit — il prend en charge iOS 15+ et macOS 12+.
2.1. Installation de WasmKit via Swift Package Manager
Ajoutez la dépendance dans Package.swift ou via Xcode : File → Add Packages → https://github.com/swiftwasm/WasmKit.
2.2. Chargement et exécution du module Wasm
Créez le fichier Swift WasmEngine.swift :
import WasmKitimport Foundation
class WasmEngine { private var instance: Instance? private var store: Store? /// Charge le module Wasm à partir d'un fichier 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() // Ici, vous pouvez ajouter des fonctions d'importation depuis Swift (voir section 3) instance = try Instance(module: module, imports: imports, store: store!) } /// Appelle une fonction exportée 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. Utilisation dans une application SwiftUI
import SwiftUI
struct ContentView: View { @State private var result: String = "0" private let engine = WasmEngine() var body: some View { VStack(spacing: 20) { Text("Résultat : \\(result)") .font(.title) Button("Calculer la factorielle de 5") { 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 = "Erreur : \\(error.localizedDescription)" } } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) } .padding() }}