iOS: ship the native comrak bridge through native assets#23
Merged
Conversation
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>
There was a problem hiding this comment.
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 frameworkdlopenwith@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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 nativemarkdown from
flutter pub getalone, 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.dylibfor the iOS triples (aarch64-apple-ios, simulatoraarch64-apple-ios-sim/x86_64-apple-ios, chosen fromcode.iOS.targetSdk)and emits
DynamicLoadingBundled. Flutter's pipeline lipos the slices, wrapsthem into
flark_comrak_bridge.framework(@rpathinstall name), codesigns,and embeds it.
rustcresolves the Apple SDK sysroot itself viaxcrun.native_comrak_bridge_factory_ffi.dart— the framework is embedded, notlinked, so its symbols aren't in the process image. The iOS branch now
dlopens the framework via its@rpathinstall name (absolute<app>/Frameworks/…fallback) instead ofDynamicLibrary.process().FlarkComrakAnchor.cand its XCFramework project wiring.flutter run -d ioson older Flutter fails at the native-assets target withTarget 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 iosworks on older Flutter too — onlythe dev
runloop needed the fix. CI that runs iOSflutter runmust be on 3.44+.Verification
flutter run -d ioson 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), noNativeComrakBridgeLoadException.flutter build ios --simulatorbundlesflark_comrak_bridge.framework.Notes for review
flark_v2_surfaces,flark_v2_blockquotes) drift by0.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.
scripts/build_comrak_ios.sh(the static XCFramework build)is retained for consumers who can't move to 3.44 and use
flutter build.docs/production_readiness/native_packaging_2026-05-01.mdgets a"superseded" banner rather than a rewrite (historical record).
🤖 Generated with Claude Code