Environment
iOS 17.2, Xcode 16.2, physical iPhone (12 Pro)
Main app in Flutter
WidgetKit extension written in Swift (Swift‑PM package)
Shared App Group: group.cool.glance.shared
Widget uses an AppIntent (FeedSelectionIntent) + custom entity (FeedAppEntity)
Flutter bridge writes JSON snapshots for the widget
Observed behaviour
Flutter prints the snapshot payload and writes /…/AppGroup/<uuid>/Library/Caches/feed_snapshots.json.
Widget gallery only shows the plain grey system placeholder (my sample placeholder never appears).
Console log every time WidgetKit runs:
chronod: Unable to resolve default intent (appintent:FeedSelectionIntent) for extension cool.glance.app.widget
Error Domain=LNMetadataProviderErrorDomain Code=9000
LinkMetadata.BundleMetadataExtractionError.aggregateMetadataIsEmpty
Added os_log in the widget + bridge (WidgetsBridgePlugin, FeedSnapshotStore, FeedEntityQuery, FeedSummaryTimeline), but none of them ever appear. That suggests the widget bundle can’t see the compiled AppIntent metadata or the snapshot file even though it’s there.
Code (trimmed to essentials)
FeedSelectionIntent.swift
struct FeedSelectionIntent: AppIntent, WidgetConfigurationIntent {
static var title: LocalizedStringResource = "Feed"
static var description = IntentDescription("Choose which feed should appear in the widget.")
@Parameter(title: "Feed",
requestValueDialog: IntentDialog("Select which feed to display."))
var feed: FeedAppEntity?
static var parameterSummary: some ParameterSummary { Summary("Show \(\.$feed)") }
init() { feed = FeedAppEntity.sample }
init(feed: FeedAppEntity?) { self.feed = feed }
static var defaultValue: FeedSelectionIntent { FeedSelectionIntent(feed: .sample) }
func perform() async throws -> some IntentResult { .result() }
}
FeedSnapshotStore.loadSnapshots()
guard let containerURL = fileManager.containerURL(
forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
os_log("FeedSnapshotStore: missing app group container %{public}s", log: Self.log, type: .error, appGroupIdentifier)
return []
}
let fileURL = SharedConstants.feedSnapshotRelativePath.reduce(containerURL) { url, component in
url.appendingPathComponent(component, isDirectory: component != SharedConstants.feedSnapshotFileName)
}
guard let data = try? Data(contentsOf: fileURL), !data.isEmpty else {
os_log("FeedSnapshotStore: no snapshot data found at %{public}s", log: Self.log, type: .info, fileURL.path)
return []
}
// decode FeedSnapshotEnvelope…
WidgetsBridgePlugin.writeSnapshots (Flutter → widget)
guard let containerURL = fileManager.containerURL(
forSecurityApplicationGroupIdentifier: SharedConstants.appGroupIdentifier) else {
result(FlutterError(code: "container-unavailable", message: "Unable to locate shared app group container.", details: nil))
return
}
let targetDir = SharedConstants.feedSnapshotRelativePath.dropLast().reduce(containerURL) {
$0.appendingPathComponent($1, isDirectory: true)
}
try fileManager.createDirectory(at: targetDir, withIntermediateDirectories: true)
let targetURL = targetDir.appendingPathComponent(SharedConstants.feedSnapshotFileName, isDirectory: false)
try data.write(to: targetURL, options: .atomic)
WidgetCenter.shared.reloadTimelines(ofKind: "GlanceSummaryWidget")
os_log("WidgetsBridgePlugin: wrote snapshots for %{public}d feeds at %{public}s",
log: WidgetsBridgePlugin.log,
type: .info,
envelope.feeds.count,
targetURL.path)
Info.plist for the widget contains only:
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>cool.glance.app</string>
</dict>
(If I add NSExtensionPrincipalClass, the install fails with “principal class not allowed for com.apple.widgetkit-extension”, so it stays out.)
What I’ve double‑checked
App Group entitlement present on Runner.app and the widget extension.
Snapshot file definitely exists under Library/Caches/feed_snapshots.json (size updates when Flutter writes).
Code matches Apple’s “Making a configurable widget” sample (custom WidgetConfigurationIntent, entity, and timeline provider).
Cleaned build folders (Flutter + Xcode), reinstalled app from scratch, but I still don’t see any of the os_log messages from the widget extension-only the LinkMetadata error above.
Placeholder entry (SampleSnapshots.recentSummary) is wired up; yet the system never uses it and always drops to the generic grey preview.
Questions
Does LinkMetadata.BundleMetadataExtractionError.aggregateMetadataIsEmpty mean WidgetKit can’t see the compiled AppIntent metadata? If so, what could cause that when the extension is built via Swift Package Manager inside a Flutter project?
Are there extra build settings or plist keys required so the AppIntent metadata gets embedded in the widget bundle?
Any reason the widget would never reach my FeedSnapshotStore logs even though the file is written and the App Group is configured?
Any help connecting the dots would be hugely appreciated.