Skip to content

feat(ffi): warden_ffi_flutter plugin + dynamic-framework iOS build (#4)#6

Merged
nandal merged 1 commit into
mainfrom
feat/warden-ffi-flutter-plugin
Jun 23, 2026
Merged

feat(ffi): warden_ffi_flutter plugin + dynamic-framework iOS build (#4)#6
nandal merged 1 commit into
mainfrom
feat/warden-ffi-flutter-plugin

Conversation

@nandal

@nandal nandal commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Phase 2 of #4 — a Flutter plugin so any app (incl. maktub-app) consumes the Veil bridge with one pub.dev dependency: no Rust toolchain, no manual binary download, no Xcode/Gradle wiring.

What's in it

  • ffi/flutter/warden_ffi_flutter plugin. Re-exports the warden_ffi binding; its only job is delivering the native lib per platform:
    • iOS — the podspec's prepare_command downloads the prebuilt dynamic WardenFfi.xcframework from the warden release; CocoaPods embeds + signs it. dyld loads it at launch, so WardenFfi.load() resolves symbols via DynamicLibrary.process()no -force_load, no xcconfig.
    • Androidbuild.gradle downloads jniLibs/<abi>/libwarden_ffi.so and adds them as a source set; Gradle bundles them.
    • The native release tag is pinned in both (warden_tag / WARDEN_NATIVE_TAG).
  • build-mobile.sh — new ios-framework mode builds a dynamic xcframework (cdylib.framework with an @rpath install name → xcframework). The static ios mode is kept for back-compat.
  • CImobile-ci/mobile-release now build the dynamic framework, assert the five warden_* symbols are exported (nm), and a new plugin-check job runs dart analyze + flutter pub publish --dry-run.

Why dynamic framework (vs the static .a + -force_load)

A dynamic framework is what makes the plugin self-contained: CocoaPods embeds + signs vendored dynamic frameworks automatically and dyld loads them at launch, so the runtime-only warden_* symbols are present with zero linker flags on the consumer. The static path needs the app to inject -force_load (what maktub-app does today in ios/Flutter/*.xcconfig) — fine for one app, wrong for a reusable plugin.

Verification

  • ✅ Plugin validated locally: flutter pub get, dart analyze clean, flutter pub publish --dry-run0 warnings.
  • build-mobile.sh syntax-checked; actionlint clean.
  • ⏳ CI here will build the dynamic xcframework on macos-latest and assert symbol export (my proxy for the build being correct, since I can't run a device build locally).
  • ⚠️ On-device runtime load not yet verified — that DynamicLibrary.process() finds the symbols in the embedded framework is confirmed only by a real-device flutter build. That's the gate before pub.dev publish.

Sequence after merge

  1. Cut v0.1.0-dev.2mobile-release publishes the dynamic WardenFfi.xcframework + jniLibs (the tag the plugin pins).
  2. Point maktub-app at this plugin via a git dependency, run a real-device build to confirm load.
  3. On success: publish warden_ffi_flutter to pub.dev and switch maktub-app to the hosted dep. (Supersedes the interim fetch-script PR, maktub-app#2.)

🤖 Generated with Claude Code

Phase 2 of #4: a Flutter plugin so any app (incl. maktub-app) consumes the Veil
bridge with one pub.dev dependency — no Rust toolchain, no manual binary
download, no Xcode/Gradle wiring.

- ffi/flutter: warden_ffi_flutter plugin. Re-exports the warden_ffi binding;
  delivers the native lib per platform. iOS — the podspec's prepare_command
  downloads the prebuilt dynamic WardenFfi.xcframework from the warden release
  and CocoaPods embeds+signs it (dyld loads at launch → symbols resolve via
  DynamicLibrary.process(), no -force_load). Android — build.gradle downloads
  jniLibs and adds them as a source set. Native release tag pinned in both.
- build-mobile.sh: add `ios-framework` mode building a DYNAMIC xcframework
  (cdylib → .framework with @rpath install name → xcframework). Static `ios`
  mode kept for back-compat.
- mobile-ci/mobile-release: build the dynamic framework, assert the five warden_*
  symbols are exported (nm), and add a plugin analyze + `pub publish --dry-run`
  job. Verified locally: analyze clean, dry-run 0 warnings.

The plugin downloads from warden release v0.1.0-dev.2 (the first dynamic-iOS
build) — cut after this merges. pub.dev publish + the maktub-app swap follow once
a real-device build confirms the dynamic framework loads.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nandal
nandal merged commit 66bef7a into main Jun 23, 2026
4 checks passed
@nandal
nandal deleted the feat/warden-ffi-flutter-plugin branch June 23, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant