Skip to content

Distribute prebuilt mobile FFI binaries (Releases) + a warden_ffi_flutter plugin — consume Veil without a Rust toolchain #4

Description

@nandal

Problem

After the monorepo split, the Dart binding (warden_ffi) is published to pub.dev, but the native libraries it binds to are not distributed anywhere. ffi/build-mobile.sh builds them, and the outputs are git-ignored (correctly — we don't commit binaries). So today every machine that wants to build a consuming Flutter app for a device must check out warden and cross-compile the binary itself, which requires a full Rust + iOS/Android cross toolchain (Xcode targets, NDK, cargo-ndk).

The binary is platform-specific but not machine-specific — an xcframework/.so built once works everywhere. So there's no reason every consumer should rebuild it. We should build once, publish, and let consumers pull it.

Proposal

Three parts, phased:

1. Publish prebuilt mobile binaries as GitHub Release assets ← Phase 1 (this issue's first PR)

A tag-triggered workflow (v*) cross-compiles via build-mobile.sh on the right runners and attaches to the GitHub Release:

  • WardenFfi.xcframework.zip (iOS, built on macos-latest)
  • warden-ffi-android-jniLibs.zip (Android 4-ABI, built on ubuntu-latest)
  • SHA256SUMS

Tag-triggered (not per-merge) so the binary version stays in lockstep with the warden_ffi pub.dev version — both are cut from the same tag. A redeploy of any consuming app is irrelevant here (the gate crypto bakes in no on-chain addresses). Also add a path-filtered build-check CI (PR + push to main, scoped to core/**, ffi/**) that cross-compiles both platforms and runs the FFI host test, so a break in the mobile build surfaces early without cutting a release.

2. Publish a warden_ffi_flutter wrapper plugin to pub.dev ← Phase 2 (follow-up PR)

A thin Flutter plugin that depends on the pure warden_ffi binding and adds the ios/ podspec + android/ gradle that download the Phase-1 release binary at build time. Consuming apps then add one dependency — flutter pub get + flutter build pulls everything, no Rust toolchain on any dev/CI machine. The pure warden_ffi stays pure (desktop/CLI/host tests keep supplying a dylib path).

Open decision for that PR: iOS currently ships a static lib force-loaded via OTHER_LDFLAGS (symbols resolved at runtime through DynamicLibrary.process()). A pod is friendlier with a dynamic framework (cdylib packaged as .framework, loaded via DynamicLibrary.open), which removes the -force_load wiring from the consumer. This needs real-device verification, which is why it's a separate PR.

3. Docs

Update ffi/README.md, ffi/dart/README.md, and the top README.md so "how to consume on mobile" reflects: download the release binary (Phase 1) and eventually just add warden_ffi_flutter (Phase 2). Build-from-source instructions stay for warden developers.

Why GitHub Releases (not GitHub Packages)

GitHub Packages has no pub or CocoaPods/SwiftPM registry (only its Maven registry would fit Android), and its Maven registry requires a token even for public reads. A GitHub Release asset downloads anonymously on a public repo and is consumable from both a podspec and gradle — one store, all platforms, no auth.

Tasks

  • Phase 1: mobile-release.yml (tag v* → build iOS + Android → Release assets + checksums)
  • Phase 1: mobile-ci.yml (PR/main build-check, path-filtered, + FFI host test)
  • Phase 1: docs — releases are the artifact source
  • Phase 2: warden_ffi_flutter plugin (podspec + gradle download the pinned release) → pub.dev
  • Phase 2: decide + verify iOS static-force_load vs dynamic-framework on a real device
  • Phase 2: docs — warden_ffi_flutter as the turn-key Flutter path; update consumer (maktub-app) CLAUDE.md

Non-goals

  • Auto-tagging / releasing on every merge (decouples binary from the published binding version).
  • Committing binaries into any repo.
  • Touching the wasm/ (JS SDK) track — that's a separate consumer.

Status: Phase 0 PoC — these binaries are publishable, not audited. The "preview" framing is unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions