Add script and workflow to build Swift XCFramework
Seto Elkahfi committed
Mar 30, 2026 at 19:59 UTC
547cdb344c4a19991968c7c51515ab790da2241c
2 files changed
+127
.github/scripts/build-swift-xcframework.sh
new
+74
@@ -0,0 +1,74 @@
1
+#!/usr/bin/env bash
2
+set -euo pipefail
3
+
4
+ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
5
+cd "$ROOT_DIR"
6
+
7
+DIST_DIR="$ROOT_DIR/dist/swift"
8
+PACKAGE_DIR="$DIST_DIR/Package"
9
+HEADERS_DIR="$DIST_DIR/Headers"
10
+FRAMEWORK_DIR="$DIST_DIR/OndeFramework.xcframework"
11
+ZIP_PATH="$DIST_DIR/OndeFramework.xcframework.zip"
12
+CHECKSUM_PATH="$DIST_DIR/OndeFramework.checksum.txt"
13
+VERSION_PATH="$DIST_DIR/version.txt"
14
+BINDGEN="$ROOT_DIR/uniffi-bindgen/target/release/uniffi-bindgen"
15
+
16
+mkdir -p "$DIST_DIR" "$PACKAGE_DIR/Sources/Onde" "$HEADERS_DIR"
17
+
18
+cargo build --manifest-path uniffi-bindgen/Cargo.toml --release
19
+
20
+# Build staticlibs only. Avoid the cdylib link step; the XCFramework consumes .a slices.
21
+cargo rustc --target aarch64-apple-ios --release --lib --crate-type staticlib
22
+cargo rustc --target x86_64-apple-ios --release --lib --crate-type staticlib
23
+cargo rustc --target aarch64-apple-ios-sim --release --lib --crate-type staticlib
24
+cargo rustc --target aarch64-apple-darwin --release --lib --crate-type staticlib
25
+cargo rustc --target x86_64-apple-darwin --release --lib --crate-type staticlib
26
+cargo +nightly rustc -Z build-std --target aarch64-apple-tvos --release --lib --crate-type staticlib
27
+cargo +nightly rustc -Z build-std --target x86_64-apple-tvos --release --lib --crate-type staticlib
28
+cargo +nightly rustc -Z build-std --target aarch64-apple-tvos-sim --release --lib --crate-type staticlib
29
+
30
+"$BINDGEN" generate "$ROOT_DIR/target/aarch64-apple-ios/release/libonde.a" --language swift --out-dir "$PACKAGE_DIR/Sources/Onde"
31
+
32
+cp "$PACKAGE_DIR/Sources/Onde/ondeFFI.h" "$HEADERS_DIR/ondeFFI.h"
33
+cp "$PACKAGE_DIR/Sources/Onde/ondeFFI.modulemap" "$HEADERS_DIR/module.modulemap"
34
+
35
+lipo -create "$ROOT_DIR/target/x86_64-apple-ios/release/libonde.a" "$ROOT_DIR/target/aarch64-apple-ios-sim/release/libonde.a" -output "$DIST_DIR/libonde-ios-sim.a"
36
+
37
+lipo -create "$ROOT_DIR/target/x86_64-apple-tvos/release/libonde.a" "$ROOT_DIR/target/aarch64-apple-tvos-sim/release/libonde.a" -output "$DIST_DIR/libonde-tvos-sim.a"
38
+
39
+lipo -create "$ROOT_DIR/target/aarch64-apple-darwin/release/libonde.a" "$ROOT_DIR/target/x86_64-apple-darwin/release/libonde.a" -output "$DIST_DIR/libonde-macos.a"
40
+
41
+xcodebuild -create-xcframework -library "$ROOT_DIR/target/aarch64-apple-ios/release/libonde.a" -headers "$HEADERS_DIR" -library "$DIST_DIR/libonde-ios-sim.a" -headers "$HEADERS_DIR" -library "$ROOT_DIR/target/aarch64-apple-tvos/release/libonde.a" -headers "$HEADERS_DIR" -library "$DIST_DIR/libonde-tvos-sim.a" -headers "$HEADERS_DIR" -library "$DIST_DIR/libonde-macos.a" -headers "$HEADERS_DIR" -output "$FRAMEWORK_DIR"
42
+
43
+export FRAMEWORK_DIR ZIP_PATH
44
+python3 - <<'ZIP'
45
+import os
46
+import zipfile
47
+from pathlib import Path
48
+root = Path(os.environ['FRAMEWORK_DIR'])
49
+out = Path(os.environ['ZIP_PATH'])
50
+with zipfile.ZipFile(out, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
51
+ for folder, _, files in os.walk(root):
52
+ for name in files:
53
+ path = Path(folder) / name
54
+ zf.write(path, path.relative_to(root.parent))
55
+ZIP
56
+
57
+CHECKSUM=$(swift package compute-checksum "$ZIP_PATH")
58
+printf '%s
59
+' "$CHECKSUM" > "$CHECKSUM_PATH"
60
+
61
+VERSION=$(python3 - <<'VER'
62
+from pathlib import Path
63
+import tomllib
64
+cargo = Path('Cargo.toml').read_text().encode()
65
+print(tomllib.loads(cargo.decode())['package']['version'])
66
+VER
67
+)
68
+printf '%s
69
+' "$VERSION" > "$VERSION_PATH"
70
+
71
+echo "XCFramework: $FRAMEWORK_DIR"
72
+echo "Zip: $ZIP_PATH"
73
+echo "Checksum: $CHECKSUM"
74
+echo "Version: $VERSION"
.github/workflows/build-swift-xcframework.yml
new
+53
@@ -0,0 +1,53 @@
1
+name: Build Swift XCFramework
2
+
3
+on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+permissions:
9
+ contents: write
10
+
11
+jobs:
12
+ build-swift-xcframework:
13
+ runs-on: macos-15
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Install stable Rust toolchain
19
+ uses: dtolnay/rust-toolchain@stable
20
+ with:
21
+ toolchain: 1.92.0
22
+ targets: aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim,aarch64-apple-darwin,x86_64-apple-darwin
23
+
24
+ - name: Install nightly Rust toolchain for tvOS
25
+ uses: dtolnay/rust-toolchain@nightly
26
+ with:
27
+ components: rust-src
28
+ targets: aarch64-apple-tvos
29
+
30
+ - name: Verify Xcode
31
+ run: xcodebuild -version
32
+
33
+ - name: Build Swift XCFramework
34
+ run: .github/scripts/build-swift-xcframework.sh
35
+
36
+ - name: Upload XCFramework artifacts
37
+ uses: actions/upload-artifact@v4
38
+ with:
39
+ name: onde-swift-xcframework
40
+ path: |
41
+ dist/swift/OndeFramework.xcframework.zip
42
+ dist/swift/OndeFramework.checksum.txt
43
+ dist/swift/version.txt
44
+ dist/swift/Package/Sources/Onde/onde.swift
45
+ if-no-files-found: error
46
+
47
+ - name: Upload release assets
48
+ if: github.event_name == 'release'
49
+ uses: softprops/action-gh-release@v2
50
+ with:
51
+ files: |
52
+ dist/swift/OndeFramework.xcframework.zip
53
+ dist/swift/OndeFramework.checksum.txt