Skip to content

iOS: ship the native comrak bridge through native assets#23

Merged
danReynolds merged 2 commits into
mainfrom
ios-native-assets
Jul 4, 2026
Merged

iOS: ship the native comrak bridge through native assets#23
danReynolds merged 2 commits into
mainfrom
ios-native-assets

Conversation

@danReynolds

Copy link
Copy Markdown
Owner

Summary

Ships flark's native comrak bridge on iOS through the same native-assets
build hook as macOS/Android/Linux
— no CocoaPods podspec, no prebuilt
XCFramework, and no per-app FlarkComrakAnchor.c. Consuming apps get native
markdown from flutter pub get alone, with zero manual Xcode steps.

Previously iOS was the one platform that couldn't use the hook: it shipped a
static XCFramework whose FFI-only symbols get dead-stripped, so each consumer
had to force-load it (or link an anchor). That special case is gone.

How it works

  • hook/build.dart — the iOS branch cross-compiles the Rust crate to a
    .dylib for the iOS triples (aarch64-apple-ios, simulator
    aarch64-apple-ios-sim / x86_64-apple-ios, chosen from code.iOS.targetSdk)
    and emits DynamicLoadingBundled. Flutter's pipeline lipos the slices, wraps
    them into flark_comrak_bridge.framework (@rpath install name), codesigns,
    and embeds it. rustc resolves the Apple SDK sysroot itself via xcrun.
  • native_comrak_bridge_factory_ffi.dart — the framework is embedded, not
    linked
    , so its symbols aren't in the process image. The iOS branch now
    dlopens the framework via its @rpath install name (absolute
    <app>/Frameworks/… fallback) instead of DynamicLibrary.process().
  • Removed the example's FlarkComrakAnchor.c and its XCFramework project wiring.
  • Updated the native packaging contract test and the platform docs.

⚠️ Requires Flutter ≥ 3.44

flutter run -d ios on older Flutter fails at the native-assets target with
Target native_assets required define SdkRoot but it was not provided
(flutter/flutter#180603),
fixed by #181542 (in 3.44.0+;
verified by git ancestry). flutter build ios works on older Flutter too — only
the dev run loop needed the fix. CI that runs iOS flutter run must be on 3.44+.

Verification

  • flutter run -d ios on the flark example and on a downstream consumer
    (dune_minimal) — both clean: framework bundled, all 5 ABI symbols exported
    from the fat arm64+x86_64 binary (nm), no NativeComrakBridgeLoadException.
  • flutter build ios --simulator bundles flark_comrak_bridge.framework.
  • Full flark suite green (899); macOS/Android/Linux hook paths unchanged.

Notes for review

  • Goldens: two goldens (flark_v2_surfaces, flark_v2_blockquotes) drift by
    0.01% / 0.04% purely from the Flutter 3.44 engine's antialiasing, not this
    change — regolded here. Worth an eyeball via the usual golden workflow.
  • Fallback kept: scripts/build_comrak_ios.sh (the static XCFramework build)
    is retained for consumers who can't move to 3.44 and use flutter build.
  • The dated docs/production_readiness/native_packaging_2026-05-01.md gets a
    "superseded" banner rather than a rewrite (historical record).

🤖 Generated with Claude Code

Unify iOS with macOS/Android/Linux. The build hook now cross-compiles the
Rust bridge to a .dylib for the iOS triples (device + simulator) and emits
DynamicLoadingBundled, so Flutter bundles it as flark_comrak_bridge.framework
with no podspec, prebuilt XCFramework, or per-app anchor file. Consumers get
markdown from `flutter pub get` alone.

- hook/build.dart: add the iOS branch (aarch64-apple-ios / -sim / x86_64),
  DynamicLoadingBundled + IPHONEOS_DEPLOYMENT_TARGET; rustc resolves the Apple
  SDK sysroot via xcrun.
- native_comrak_bridge_factory_ffi.dart: the framework is embedded, not linked,
  so dlopen it via its @rpath install name (absolute Frameworks/ fallback)
  instead of DynamicLibrary.process().
- Drop the example's FlarkComrakAnchor.c + XCFramework project wiring.
- Update the native packaging contract test and platform docs to the new path.
- Regold two goldens for the Flutter 3.44 engine's antialiasing (0.01%/0.04%).

Requires Flutter >= 3.44 for `flutter run -d ios` (flutter/flutter#180603,
fixed by #181542); `flutter build ios` already worked on older Flutter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 4, 2026 04:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates flark’s iOS native Comrak integration to ship via the same Flutter native-assets build hook used on macOS/Android/Linux, producing a hook-built Rust dynamic library that Flutter bundles as flark_comrak_bridge.framework and loading it on iOS via dlopen, eliminating the prior XCFramework + per-app anchor workaround.

Changes:

  • Build-hook: add iOS cross-compile support (device + simulator triples) and emit bundled dynamic loading assets.
  • Runtime loading: switch iOS FFI loading from DynamicLibrary.process() to explicit framework dlopen with @rpath + absolute fallback.
  • Cleanup & contract/docs: remove the example iOS anchor/XCFramework wiring and update packaging contract tests + platform docs.

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/v2/packaging/flark_v2_native_packaging_contract_test.dart Updates packaging contract assertions to reflect hook-built iOS dylib/framework shipping and removes anchor checks.
lib/src/v2/native/native_comrak_bridge_factory_ffi.dart Implements iOS framework dlopen loading path and updates iOS remediation guidance.
hook/build.dart Removes iOS XCFramework special-casing and adds iOS Rust cross-compile plan emitting a .dylib for native-assets bundling.
example/ios/Runner/FlarkComrakAnchor.c Removes the per-app “anchor” symbol force-load workaround.
example/ios/Runner.xcodeproj/project.pbxproj Removes XCFramework + anchor references from the example Xcode project.
docs/production_readiness/native_packaging_2026-05-01.md Marks prior iOS packaging approach as superseded and documents the new hook-based approach.
docs/parser_and_platforms.md Updates iOS backend description to the bundled-framework native bridge.
doc/parser_and_platforms.md Mirrors the same iOS backend description update.
Comments suppressed due to low confidence (1)

hook/build.dart:23

  • The unsupported-target BuildError message still says iOS uses “process-linked XCFramework builds”, but this PR moves iOS to hook-built bundled dynamic libraries. That makes the error misleading when a user hits an unsupported OS/arch combination.
    final plan = _RustBuildPlan.resolve(code);
    if (plan == null) {
      throw BuildError(
        message:
            'Flark native comrak bridge does not support '

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +152 to +156
Object? lastError;
for (final candidate in candidates) {
try {
return _LoadedLibraryContext(
library: DynamicLibrary.open(candidate),
- Revert the two goldens regolded for Flutter 3.44: CI pins 3.41.9, so the
  regold belongs to a separate Flutter bump, not this native-assets migration.
- hook/build.dart: the unsupported-target BuildError still named the removed
  "process-linked XCFramework" iOS path; now lists the real iOS triples.
- loader: report loadFailed (not libraryNotFound) when the framework is on disk
  but won't open (codesign/arch/rpath), matching the other load paths.
- Strengthen the packaging contract test — it asserted only whole-file
  contains() that matched unrelated lines; now checks the iOS simulator triple
  and the absence of any LookupInProcess fallback.
- scripts/verify_example_packaging.sh: the --ios path require_file'd the deleted
  FlarkComrakAnchor.c (hard fail). Rewrote it to verify the native-assets
  reality (no anchor/XCFramework wiring; hook declares the iOS build) and
  dropped the now-obsolete --strict-ios flag. Updated example/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@danReynolds danReynolds merged commit 9c69632 into main Jul 4, 2026
0 of 2 checks passed
@danReynolds danReynolds deleted the ios-native-assets branch July 4, 2026 16:11
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.

2 participants