WidgetKit and ActivityKit extensions
Enabled Apple extensions are generated as separate Swift/Xcode application-extension targets, built as target dependencies, embedded under <app>.app/PlugIns/, and independently validated. Users do not create or edit Swift or Xcode files.
WidgetKit
Configuration requires an application group:
[extensions.widget]
enabled = true
app_group = "group.com.example.weather"
Generation adds:
FerryWidgetExtensionXcode target;FerryWidgetExtension.appexproduct;- WidgetKit/SwiftUI timeline provider and a small-system-family view;
- main-app and extension app-group entitlements;
- extension identifier
<app identifier>.widget; - embed-target dependency and
Embed App Extensionsphase.
The Rust widgets::update path validates and writes the serialized snapshot plus title, value, caption, progress, deep link, and constrained action data to the configured app-group UserDefaults suite, then requests a WidgetKit timeline reload. The generated provider reads that snapshot and renders the supported fields. The current Ferry* publisher, framework, provider, and embedded extension compiled and passed artifact inspection in Platform artifacts run 30719811812, including exact application-group entitlements. Their behavior has not been observed in a running Simulator.
ActivityKit and Dynamic Island
[ios]
min_version = "16.1"
[extensions.live_activity]
enabled = true
android_fallback = "ongoing-notification"
Generation adds:
FerryLiveActivityExtensionXcode target;FerryLiveActivityExtension.appexproduct;ActivityAttributescontent state;- Lock Screen and expanded/compact/minimal Dynamic Island presentations;
- main-app
NSSupportsLiveActivitiesmetadata; - extension identifier
<app identifier>.liveactivity; - embed-target dependency and
Embed App Extensionsphase.
The Rust start, update, end, and list_active paths call the generated ActivityKit application bridge. The current Ferry* main-app framework and presentation extension compiled, linked, embedded, and passed artifact inspection in Platform artifacts run 30719811812. No ActivityKit session has been started in a running Simulator or device, so this is not runtime validation. Push-based updates remain unavailable.
Artifact validation
For each enabled extension, the build requires:
- expected
.appexbeneathPlugIns/; - valid plist and exact bundle identifier;
CFBundleExecutablematching a non-empty executable;NSExtensionPointIdentifier=com.apple.widgetkit-extension;- exact arm64 Simulator Mach-O architecture;
- sealed plist/resources, exact signature identifier, and strict-valid ad-hoc signature;
- exact configured application-group entitlement on the widget signature;
- no unexpected extra
.appexbundles.
At commit 8ed0192, Platform artifacts run 30719811812 built a RustFerry-named Kitchen Sink app embedding FerryWidgetExtension.appex and FerryLiveActivityExtension.appex. Both arm64 products passed identifier, plist, extension-point, resource-sealing, and strict ad-hoc signature checks; the ActivityKit product also passed exact runtime-framework linkage inspection, and the widget and containing app carried the exact configured application-group entitlement. Before the rename, the equivalent legacy-named targets, standalone .appex products, and combined app were also built and validated with Xcode 26.6/iPhoneSimulator 26.5 without a Simulator runtime.
Physical-device signing status
Simulator builds use local ad-hoc signing and require no team. Widget builds re-sign the widget and then the containing app with their generated application-group entitlements; non-widget builds retain Xcode’s signatures unchanged.
The physical-development flow is implemented with explicit Team selection, Apple Development identity/profile resolution, generated entitlements, recursive signature/profile/entitlement inspection, and devicectl install/launch services. Remote manual setup accepts one exact profile for the application and every enabled extension, up to three profiles, and requires a common registered device. Extension-bearing device builds must preserve the configured application-group capability in the app and widget profiles. The multi-profile continuation passes local integration tests. This environment had no identity, Team, provisioning profile, signed device artifact, or attached iPhone, so physical signing, installation, launch, and extension behavior remain unvalidated.