NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev
Flutter plugin for iOS App Intents and Android AppFunctions integration. Enables Siri, Shortcuts, Spotlight, and AI agent support.
Last release 6 days ago
02 Oct 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 32 of 32 stable releases
Nothing withdrawn
no release was ever pulled
9 months old
32 releases · first in 2026
One column per month.
Three fixes reported from a production app: parameterized App Shortcuts now appear, a widget that navigates on an intent no longer misses it on a cold
Three fixes reported from a production app: parameterized App Shortcuts now appear, a widget that navigates on an intent no longer misses it on a cold start, and an entity type can suggest a short list of App Shortcuts while the Shortcuts editor's picker still shows every entity. Android AppFunctions also start registering their functions again. Two of these need a change in your app. See Heads-up below.
With the alpha12 compiler, the previous generate_kotlin output built fine but registered zero functions. androidx.appfunctions.service.AppFunction is no longer recognized, so the generated XML was empty and no service was generated. GeneratedAppFunctions is now an abstract AppFunctionService annotated with @AppFunctionServiceEntryPoint, and KSP generates the concrete GeneratedAppFunctionService. After regenerating:
androidx.appfunctions:appfunctions-service dependency and the appfunctions:aggregateAppFunctions KSP argument;<service> at GeneratedAppFunctionService, with the new permission (BIND_APP_FUNCTION_SERVICE), the two <property> entries and the android.app.appfunctions.AppFunctionService action. The exact block is in docs/usage.md.The generated @AppFunction methods also drop the AppFunctionContext parameter, which alpha12 marks @RestrictTo(LIBRARY_GROUP).
AppShortcuts.registerParameterUpdater() (#149)The docs used to call updateAppShortcutParameters() an optional "force refresh". It is required: a phrase that references an entity parameter does not appear at all until the system has fetched the entities once (WWDC23 10102). generate_swift now emits AppShortcuts.registerParameterUpdater() alongside the provider. Call it from AppDelegate, after AppIntentsPlugin.configure(appGroupIdentifier:) and the FlutterBridge executors. The generated file also gains import app_intents whenever it declares shortcuts.
registerParameterUpdater() refreshes the parameters immediately (first launch). It refreshes them again after every Dart setCachedValue / clearCachedValue on an entity cache key, once the write has landed. Order matters: the generated suggestedEntities() reads the App Group cache first, so a refresh that ran before the write would re-read the stale list. For entities whose source is the Dart handler rather than the cache, call AppIntents().updateAppShortcutParameters(). It throws SHORTCUT_UPDATER_NOT_CONFIGURED when the wiring is missing, instead of leaving you with shortcuts that silently never show up.@EntitySpec(suggestedLimit: 10) makes suggestedEntities() return the first ten. allEntities(), entities(for:) and re-indexing still see the full list, through a new completeEntities(). The limit applies to the cache and the Dart handler alike, so write the list in priority order. Without a limit, the generated Swift is byte-for-byte unchanged.onIntentExecution on a cold start (#150)On a cold start, processPendingActions() dispatches from main(), but the code that navigates subscribes from a widget once a router exists. The event was dropped, and the native side had already consumed the action. onIntentExecution now keeps requests emitted before the stream has ever had a listener (up to 16) and replays them, in order, to the first subscriber. After that it drops unheard events as before, so a screen opened minutes later never navigates on a stale intent. The docs now separate registerIntentHandler (do the work, from main()) from onIntentExecution (navigate, from the widget that owns the router), with an example.
androidx.appfunctions 1.0.0-alpha12, AGP 9.4.1, Gradle wrapper 9.8.0 (#139, #144, #148).Whether a parameterized App Shortcut actually shows up in Shortcuts after registerParameterUpdater() has been compiled into the example app and unit-tested, not observed on hardware.
Full Changelog: v0.17.0...v0.18.0
Action required if you declare
@AppShortcutsProviderwith an entity parameter in a phrase. Call the newly generatedAppShortcuts.registerParameterUpdater()from AppDelegate, afterAppIntentsPlugin.configure(appGroupIdentifier:)and the FlutterBridge executors. Without it the phrase never appears: the system shows it only after it has fetched the entities once (#149).
AppIntentsPlugin.registerShortcutParameterUpdater(entityCacheKeys:_:). It refreshes App Shortcut parameters once on registration, and again after every Dart setCachedValue / clearCachedValue on one of the entity cache keys, once the write has landed (#149).AppIntents().updateAppShortcutParameters() refreshes them from Dart. On iOS it throws SHORTCUT_UPDATER_NOT_CONFIGURED when the updater was never registered; on Android it does nothing (#149).onIntentExecution keeps requests emitted before the stream has ever had a listener (up to 16) and replays them, in order, to the first subscriber. On a cold start, a widget that navigates in response to an intent no longer misses the intent processPendingActions() dispatched from main(). Once anyone has listened, unheard requests are dropped as before, so stale intents are never replayed (#150).The last of the Xcode 27 work that a Simulator can settle: entities can travel between apps in both directions, long-running intents report progress a
The last of the Xcode 27 work that a Simulator can settle: entities can travel between apps in both directions, long-running intents report progress and hear about cancellation, and a handler can ask the user for a missing value mid-run. Two fixes change behavior you may notice — see Heads-up below.
The generated perform() invoked the Dart handler with the Swift struct name, while the generated Dart registers under @IntentSpec.identifier. So no background (FlutterBridge) intent could ever find its handler. The golden test asserted the same wrong string, which is why it went unnoticed. Regenerate with generate_swift; URL scheme and foreground (cache) intents were already correct.
generate_swift, generate_widget_swift and generate_kotlin exit 1 when an analyzer rejects an annotation, printing the file and the problem. Previously the error became a Warning: Could not analyze … line, the spec was left out of the output, and the command still exited 0 — a project whose only specs were invalid got empty output and a green build. If a build that used to pass stops here, that spec was never being generated. A file that fails to resolve is still skipped with a warning.
operation argumentIf you wired #55, AppIntentsPlugin.relevantEntitiesDonationForwarder and the closure passed to FlutterBridge.registerRelevantEntitiesDonator now take an operation (update / remove / removeAll). Update AppDelegate — see docs/usage.md.
requestValue (ADR 0010)A long-running intent's perform() now opens an execution scope and hands its id to Dart. Inside the handler, AppIntentExecution.current gives you:
reportProgress(fraction) / reportProgressUnits(completed, total) (#130)isCancelled / cancelled — onCancel: is forwarded to Dart instead of being a comment stub (#130). AppIntents().onIntentCancellation observes the same from outside a handler.requestValue<T>(parameter) for a parameter declared @IntentParam(requestValue: true) — the system prompts the user and the call resumes with the answer (#131). Optional primitive parameters only: the system already asks for a missing non-optional one on its own.Generated handler signatures did not change — the scope reaches the handler through a Zone, not a new argument. Wire AppIntentsPlugin.intentProgressForwarder, intentValueRequestForwarder and FlutterBridge.setCancellationNotifier in AppDelegate.
@EntitySpec(exportAs: EntityExportType.place) exports a GeoToolbox.PlaceDescriptor, built from fields marked @EntityExportField(EntityExportRole.latitude / .longitude / .address).@EntitySpec(importable: true) generates ValueRepresentation(exporting:importing:); resolve the incoming value with AppIntents().registerValueImportHandler. It rides the value-query bridge, so there is no new native wiring.ValueRepresentation(exporting:) is only declared for IntentPerson and _SystemIntentValue conformers. IntentCurrencyAmount exists in the SDK but is neither, so generated Swift using it does not compile — measured against the iOS 27.0 SDK, not assumed.@EntityStableId + @EntitySpec(syncable: true) gives the entity a SyncableEntityIdentifier<String, String> for entities whose @EntityId is local to the device. Using such an entity as an @IntentParam(entityType:) value is a generation error.AppIntents().removeRelevantEntities / removeAllRelevantEntities. Unlike donating an empty list, these can clear across every context.IndexedEntityQuery behind --experimental=reindexing.@UnionValueSpec(valueQuery: true) generates an IntentValueQuery that can answer with several entity types.AppIntentsPackage on a statically linked target (ADR 0008)No code change, but a documented hazard: in a sibling project, declaring AppIntentsPackage on a statically linked target stopped App Intents from being ingested in TestFlight / App Store builds only — the same build ran fine from Xcode. Removing the declaration fixed it. Static linking already merges the metadata without it, so don't reach for --app-intents-package unless you cross a dynamic link boundary. The CLI help now says so.
Siri's progress UI for a long-running intent, the actual IntentCancellationReason strings, and the prompt requestValue raises have been compiled and unit-tested, not seen on hardware.
Full Changelog: v0.16.0...v0.17.0
Action required if you wired relevant-entity donation (#55).
AppIntentsPlugin.relevantEntitiesDonationForwarderand the closure passed toFlutterBridge.registerRelevantEntitiesDonatorgain anoperationargument. Update the AppDelegate wiring — seedocs/usage.md.
AppIntentExecution.current — inside a long-running intent's handler: reportProgress / reportProgressUnits, isCancelled / cancelled, and requestValue<T>(parameter) (#130, #131, ADR 0010). AppIntents().onIntentCancellation observes cancellations from outside the handler.AppIntents().registerValueImportHandler (#129).AppIntents().removeRelevantEntities / removeAllRelevantEntities and RelevantEntitiesOperation (#133).FlutterBridge.beginExecution / endExecution / updateProgress / requestValue / setCancellationNotifier, plus AppIntentsPlugin.intentProgressForwarder / intentValueRequestForwarder to wire in AppDelegate.Siri's result card and Smart Stack are both reachable from Dart now, without writing a SwiftUI view or a line of Swift. Four features that had been pa
Siri's result card and Smart Stack are both reachable from Dart now, without writing a SwiftUI view or a line of Swift. Four features that had been parked waiting on Xcode 27 turned out not to need it, so they ship ungated. If you use @EntitySpec(valueQuery: true), see Heads-up below.
IntentValueQuery graduated out of the experimental opt-inIntentValueQuery (#51) is declared at iOS 26.0 and ships in the released iOS 26.5 SDK (Xcode 26.6), so #if APP_INTENTS_WWDC26 was never the right guard. The <Entity>ValueQuery struct is now emitted whenever @EntitySpec(valueQuery: true) is set, under @available(iOS 26.0, *).
--experimental=value-query? No action required. The flag is still accepted and now reports itself as a no-op instead of being rejected.valueQuery: true without the flag? The query appears in your generated Swift for the first time — make sure a Dart <entity>ValueQuery handler exists.An entity that also opts into App Schema (#49) keeps its #if/#else pair, because the entity type itself is iOS 27 only in that branch.
@IntentSpec(snippet:) — a card in Siri's result without a SwiftUI view (ADR 0007)SnippetTemplate / SnippetRow describe a fixed layout — optional SF Symbol, title, optional subtitle, LabeledContent rows — and codegen emits a self-contained SwiftUI <Intent>SnippetView returned with .result(view:). A Flutter app gets a Siri result card without supplying a SwiftUI view of its own.
Templates interpolate two things:
| Placeholder | Available in |
|---|---|
{paramName} |
any execution mode |
{result.key} — the Dart handler's returned map |
FlutterBridge mode only |
Using {result.…} on a URL scheme or foreground intent is a generation error, not a card that renders empty at runtime. {result.key} works in resultDialogTemplate too, and for any intent whose snippet or dialog reads it, the generated registration now returns the handler's value through the new intentResultPayload instead of discarding it. Every other intent's generated Dart is unchanged. Row labels are collected into the String Catalog.
Not experimental — ShowsSnippetView is iOS 16. The generated file gains import SwiftUI because .result(view:) lives in the _AppIntents_SwiftUI overlay.
IntentDialog(full:supporting:) (ADR 0006)@IntentSpec gains resultDialogSupportingTemplate — the on-screen half, so the spoken line can skip context a reader already has — and resultDialogSystemImageName for an SF Symbol. Both require resultDialogTemplate and are a code generation error on their own rather than a silently dropped field. The symbol initializers are iOS 17.2+ while generated intents target iOS 17.0, so the symbol form is built behind if #available(iOS 17.2, *) with the symbol-less dialog as the fallback.
Not experimental — IntentDialog(full:supporting:) is iOS 16.
RelevantIntent donation for Smart Stack (#55, ADR 0009)@WidgetConfigurationSpec(relevantIntents: true) makes generate_widget_swift emit a registerRelevantIntentDonator() plus a RelevantContext decoder, and Dart drives it with AppIntents().donateRelevantIntents(...) using RelevantIntentDonation / RelevantContextSpec.
Things worth knowing:
RelevantIntentManager.updateRelevantIntents is whole-set.RelevantContext.location(_ exact: CLRegion) is deliberately not exposed — a CLRegion cannot be rebuilt from a map.AppIntentsBridge still imports only Foundation: the closure names RelevantIntent, the actor does not.Not experimental — RelevantIntentManager is iOS 17; only the kind: date refinements are iOS 26 and they sit behind if #available.
The generated decoder used a default ISO8601DateFormatter, which rejects the fractional seconds DateTime.toIso8601String() always emits. Every date / dateRange donation was silently dropped — and since the API replaces the whole set, a batch of only date donations cleared it instead of updating it. The decoder now tries fractional and second precision.
Separately, RelevantIntentDonation.toMap() now encodes DateTime parameter values as ISO-8601 strings, and a DateTime widget parameter is carried the same way: Flutter's standard method-channel codec cannot encode a DateTime at all, so a donation with one would have thrown before reaching iOS.
AppIntentsPackage generation (ADR 0008)generate_swift and generate_widget_swift gain --app-intents-package <Name> and repeatable --include-package <Module.Type>, for sharing generated intents through a Swift package that several targets link.
Note what the declaration is actually for: metadata from a statically linked module already merges without it (Xcode SPM links statically by default). The declaration is what a dynamic link boundary needs — it is not a fix for a type missing from Metadata.appIntents.
generate_widget_swift --public is the companion flag: it emits the generated declarations as public, which that shared-module setup requires. Without it Swift's default internal hides the configuration intent, its parameters, the entities and the donator registration from an importing target — and a single-file swiftc -typecheck cannot reveal that, since the file compiles fine on its own.
{ result.x }). Each previously had its own regex, so a dialog reading {result.…} without a snippet had its handler result discarded on the Dart side while the generated Swift still read keys from it.scripts/verify_widget_module_swift.sh (new) builds the widget output as a module and compiles a consumer that imports it — the check that would have caught the --public gap.scripts/verify_experimental_swift.sh now type-checks the example's generated Widget Extension Swift too (nothing compiled that output before except an Xcode build), fixes a stale AppIntentsBridge source path broken since the module moved into the plugin's Swift package (#102), and can run against a stable Xcode — where it checks only the non-#if branch, which is what proves an ungated feature compiles without the iOS 27 SDK.make verify-swift runs the Swift type-checks against both Xcodes.androidx.appfunctions 1.0.0-alpha11, AGP, Gradle wrapper 9.7.1, actions/setup-java 6, source_gen, build_test.app_intents_annotations is released in lockstep with the annotations the above require: @WidgetConfigurationSpec(relevantIntents:), SnippetTemplate / SnippetRow / @IntentSpec(snippet:), and @IntentSpec(resultDialogSupportingTemplate:, resultDialogSystemImageName:). All are additive and optional; existing specs are unaffected.
Full Changelog: v0.15.0...v0.16.0
RelevantIntentDonation.toMap() encodes DateTime parameter values as ISO-8601 strings; Flutter's standard method-channel codec cannot carry a DateTime, so a donation with one would have thrown before reaching iOS.AppIntents().donateRelevantIntents(...) with RelevantIntentDonation / RelevantContextSpec (#55, ADR 0009). Each call replaces the app's entire set of relevant widget intents; an empty list clears it. iOS-only. RelevantContext.location(_ exact: CLRegion) is deliberately not exposed — a CLRegion cannot be rebuilt from a map.FlutterBridge.setRelevantIntentDonator / donateRelevantIntents and AppIntentsPlugin.relevantIntentDonationForwarder. AppIntentsBridge still imports only Foundation — the closure, not the actor, names RelevantIntent.intentResultPayload(Object?) — normalizes an intent handler's return value (a Map, anything with toJson(), or null) into the map a generated snippet template reads. Throws ArgumentError on anything else rather than yielding a silently empty card.Two follow-ups to the AppIntentsBridge distribution work in v0.14.0. If you added the Swift package by path in 0.14.0, see Migration below.
Two follow-ups to the AppIntentsBridge distribution work in v0.14.0. If you added the Swift package by path in 0.14.0, see Migration below.
import AppIntentsBridge did not resolve on the CocoaPods route (#105)app_intents_bridge.podspec had no s.module_name, so CocoaPods derived the module name from s.name and emitted framework module app_intents_bridge. Every generate_widget_swift output opens with import AppIntentsBridge, so the generated code could not be built as generated by a CocoaPods consumer.
The failure was easy to misread: the import line itself often reported nothing, and only the types surfaced, as Cannot find 'AppIntentsEntityCache' in scope.
Fixed by declaring s.module_name = 'AppIntentsBridge'. All three routes now take the same import line. Verified against the generated modulemap, which now reads framework module AppIntentsBridge.
AppIntentsBridge is now a product of the plugin's own Swift packagev0.14.0 recommended adding the bridge from ios/.symlinks/plugins/…, but .symlinks is created only by flutter_install_all_ios_pods while CocoaPods evaluates a Podfile. An app that had migrated to Swift Package Manager and run pod deintegrate — which the Flutter tool itself suggests once every plugin is a Swift Package — had no version-following local path at all, and was left with .package(url:), the one route that is not pinned to the pub version.
AppIntentsBridge is now a second product of the plugin's own Swift package, so the recommended route is:
File → Add Package Dependencies… → Add Local… →
ios/Flutter/ephemeral/Packages/.packages/app_intents→ add theAppIntentsBridgelibrary
Flutter's Swift Package Manager integration generates that symlink, so the path needs no Podfile and survives app_intents upgrades. Add only AppIntentsBridge to an extension target — the sibling app-intents library links Flutter.
It has to be that package rather than a sibling directory: Xcode normalizes local-package paths lexically, so …/.packages/app_intents/../AppIntentsBridge collapses to .packages/AppIntentsBridge and fails to resolve.
| Route | Needs a Podfile? | Follows the pub version? |
|---|---|---|
| Local Swift package (recommended) | no | yes |
CocoaPods app_intents_bridge pod |
yes | yes |
Remote .package(url:) |
no | no — pin the vX.Y.Z tag |
The CocoaPods pod and the root-manifest .package(url:) route are otherwise unchanged. app_intents.podspec still globs app_intents/Sources/app_intents/** only, so the two pods carry no duplicate symbols.
If you added the Swift package by path in 0.14.0 (ios/.symlinks/plugins/app_intents/ios/AppIntentsBridge), re-point it at ios/Flutter/ephemeral/Packages/.packages/app_intents and select the AppIntentsBridge library.
CocoaPods and .package(url:) users need no change beyond the version bump — though CocoaPods users can now drop any import app_intents_bridge workaround.
No code changes; released in lockstep.
The example app gained a real TaskWidget app-extension target. app/ios/TaskWidget was previously a bare directory of generated Swift verified only by swiftc -typecheck; it now compiles in a genuine extension target, links the AppIntentsBridge product over the path above, and carries its own App Groups entitlement — so the downstream integration story is exercised on every example-app build.
Note for contributors: swift test in the bridge directory is gone. The plugin's package is iOS-only because it links Flutter, so the Swift tests run via xcodebuild test -scheme AppIntentsBridge on a simulator, which is what CI already did.
Full Changelog: v0.14.0...v0.15.0
Fix: on the CocoaPods route the module was named app_intents_bridge, so import AppIntentsBridge did not resolve (#105). app_intents_bridge.podspec now declares s.module_name = 'AppIntentsBridge', so all three routes take the same import line — the one every generate_widget_swift output emits. The old failure was easy to misread: the import itself often reported nothing and only the types surfaced, as Cannot find 'AppIntentsEntityCache' in scope. Verified by reading the generated modulemap, which now says framework module AppIntentsBridge.
AppIntentsBridge is now a second product of the plugin's own Swift package rather than a separate package beside it (#102 follow-up). This is what lets an app that has moved off CocoaPods reach it: Flutter's Swift Package Manager integration symlinks each plugin at ios/Flutter/ephemeral/Packages/.packages/<plugin_name>, which is the only stable path a downstream Xcode project can name, and Xcode normalizes local-package paths lexically so a ../ hop out of that symlink does not resolve. The recommended route is now:
File → Add Package Dependencies… → Add Local… → ios/Flutter/ephemeral/Packages/.packages/app_intents → add the AppIntentsBridge library (not app-intents, which links Flutter).
The path needs no Podfile, and it survives app_intents upgrades. The CocoaPods pod and the root-manifest .package(url:) route are unchanged and still work.
Migration: if you added the package by path in 0.14.0 (ios/.symlinks/plugins/app_intents/ios/AppIntentsBridge), re-point it at ios/Flutter/ephemeral/Packages/.packages/app_intents and select the AppIntentsBridge library. CocoaPods and .package(url:) users need no change beyond the version bump.
Fix: AppIntentsBridge could not be reached from a downstream app ( #102 ). The Swift package now ships inside the pub package at ios/AppIntentsBridge/
Fix: AppIntentsBridge could not be reached from a downstream app (#102). The Swift package now ships inside the pub package at ios/AppIntentsBridge/, so import AppIntentsBridge — which the generate_widget_swift output requires — resolves without a separately versioned dependency. Three consumption routes, all building the same sources:
| Route | How |
|---|---|
| Local Swift package (recommended, projects with a Podfile) | File → Add Package Dependencies… → Add Local… → ios/.symlinks/plugins/app_intents/ios/AppIntentsBridge |
| CocoaPods | pod 'app_intents_bridge', :path => '.symlinks/plugins/app_intents/ios' |
| Remote Swift package (required for Podfile-less SPM projects) | https://github.com/touyou/flutter_intents → AppIntentsBridge |
A new standalone app_intents_bridge podspec carries no Flutter dependency, so an App Extension target — which must not link Flutter and therefore sits outside flutter_install_all_ios_pods — can take it. app_intents.podspec deliberately does not include these sources, so a target may take both pods without duplicate symbols. The repository root Package.swift keeps the same AppIntentsBridge product, so existing .package(url:) consumers are unaffected.
Previously the package lived only in the repository's ios-spm/ subdirectory, which neither pub nor CocoaPods shipped and which SPM cannot resolve over a Git URL — a Widget Extension target failed with No such module 'AppIntentsBridge'.
Docs: AppIntentsEntityCacheKey.forEntity now states that its result is the cache key, not the raw UserDefaults key. The plugin namespaces it as app_intents.<storageIdentifier>.cache.<cacheKey>; reading with the un-namespaced key returns nil silently, which only surfaces as an empty widget configuration picker. Same note added to docs/usage.md / docs/usage.ja.md.
analyzer constraint to >=7.0.0 <15.0.0, so the package can be used alongside analyzer 14.x. Verified against analyzer 14.1.0 / _fe_analyzer_shared 105.0.0: analysis clean, full test suite passing, and build_runner, generate_swift, generate_widget_swift and generate_kotlin all producing byte-identical output to the 13.x resolution.app_intents_annotations to ^0.14.0.AppIntentsBridge sources (#104).build 4.0.8, build_test 3.5.17, dart_style 3.1.12.RELEASING.md now lists the two podspecs, the three per-package READMEs, and the ^X.Y.Z pins in docs/ — all of which the checklist had been omitting.Full Changelog: v0.13.0...v0.14.0
Fix: AppIntentsBridge could not be reached from a downstream app (#102). The Swift package now ships inside this pub package at ios/AppIntentsBridge/, so import AppIntentsBridge — which the generate_widget_swift output requires — resolves without a separately versioned dependency. Three consumption routes, all building the same sources:
ios/.symlinks/plugins/app_intents/ios/AppIntentsBridge via File → Add Package Dependencies… → Add Local….app_intents_bridge podspec (no Flutter dependency, so an App Extension target can take it): pod 'app_intents_bridge', :path => '.symlinks/plugins/app_intents/ios'.AppIntentsBridge product for .package(url:).app_intents.podspec deliberately does not include these sources, so a target may take both pods without duplicate symbols. Previously the package lived only in the repository's ios-spm/ subdirectory, which neither pub nor CocoaPods shipped and which SPM cannot resolve over a Git URL.
Docs: AppIntentsEntityCacheKey.forEntity now states that its result is the cache key, not the raw UserDefaults key — the plugin namespaces it as app_intents.<storageIdentifier>.cache.<cacheKey>. Reading with the un-namespaced key returns nil silently, which only surfaces as an empty widget configuration picker (#102). Same note added to docs/usage.md.
feat: App Extension entity access + WidgetConfigurationIntent codegen ( #97 / #98 , #99 )
id for AppEntity conformance (#100)Also fixes version references that were missed in the 0.12.0 release:
the iOS podspec (left at 0.11.0) and the ^0.11.0 dependency snippets in
docs/ and the per-package READMEs.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Published to pub.dev on 2026-08-21, about two hours before v0.14.0. This GitHub Release was added retroactively, so its creation date does not reflect the original release.
Entity data becomes reachable from an App Extension, and a WidgetKit configuration screen can be declared from Dart. Also fixes a code generation bug that made any entity whose @EntityId field is not literally named id produce Swift that does not compile.
@EntityId on a field not named id generated Swift that does not compileAppEntity refines Identifiable, which requires a stored property literally named id. SwiftGenerator emitted the Dart field name verbatim, so @EntityId on e.g. teamId produced:
type 'X' does not conform to protocol 'AppEntity'
type 'X' does not conform to protocol 'Identifiable'
'ObjectIdentifier' does not conform to 'EntityIdentifierConvertible'
— the last of which is especially misleading, since nothing in the spec mentions ObjectIdentifier.
The Swift identifier property is now always emitted as id, while the Dart field name survives as the cache/dictionary key (dict["teamId"]). That matches what the Dart cache projection writes, and matches the rest of the generator, which already read <entity>.id unconditionally when serializing entity-typed intent parameters.
id generate byte-identical output.@EntityId on a non-id field plus a separate field named id — now throws InvalidGenerationSourceError instead of emitting two var id declarations.WidgetSwiftGenerator applies the same normalization.
A Widget Extension cannot start a Flutter engine, so it cannot go through FlutterBridge for an entity list. The App Group entity cache is now a supported, documented surface on both sides:
AppIntentsBridge): AppIntentsEntityCache / AppIntentsCachedEntity let an extension read the cached entity list directly.app_intents): AppIntentsEntityCacheKey.forEntity mirrors the App Group cache key, so it is no longer an undocumented internal string that callers have to hand-write.WidgetConfigurationIntent codegen (#98)@WidgetConfigurationSpec / @WidgetParameter + WidgetConfigurationSpecBase declare a WidgetKit WidgetConfigurationIntent in Dart, so a widget's configuration UI can offer entity pickers. The new generate_widget_swift CLI lowers them to Swift, emitting the configuration intent plus a cache-backed EntityQuery for the Widget Extension target — which reads the App Group cache above instead of going through FlutterBridge.
The widget itself is still native SwiftUI; these annotations only describe the configuration surface.
0.11.0 through the entire 0.12.0 release.androidx.appfunctions 1.0.0-alpha10, Gradle wrapper 9.6.1, actions/checkout 7, test.Full Changelog: v0.12.0...v0.13.0
AppIntentsEntityCacheKey.forEntity — Dart-side mirror of the App Group cache key used by the persisted-entity fallback, so the key is no longer an undocumented internal string that callers must hand-write (#97). Symmetric with AppIntentsEntityCache / AppIntentsCachedEntity in the AppIntentsBridge Swift package, which lets an App Extension (e.g. a Widget Extension, which cannot start a Flutter engine) read the cached entity list.0.11.0 during the 0.12.0 release.Follow-up release after v0.11.0 reflecting the matsudate WWDC 2026 review #4 survey: three additive, opt-in items ( #55 intent donation, #52 IntentPar
Follow-up release after v0.11.0 reflecting the matsudate WWDC 2026 review #4 survey: three additive, opt-in items (#55 intent donation, #52 IntentParameter.ValueState, and the system.searchInApp schema rename) plus the deferred-items punch list in CLAUDE.md. All three packages are released together at the same version.
AppIntents().donateIntent(identifier, params) (#55): wraps AppIntent.donate() (stable iOS 16+) so the Dart side can record an executed intent for Siri / Apple Intelligence to learn from. The call is forwarded through AppIntentsPlugin.intentDonationForwarder (set in AppDelegate, mirroring relevantEntitiesDonationForwarder) to FlutterBridge.shared.donateIntent, which invokes the per-intent reverse-executor emitted by @IntentSpec(donatable: true) codegen. iOS-only; a no-op on other platforms.AppIntentsPlugin.intentDonationForwarder static hook for AppDelegate wiring. The donateIntent MethodChannel case returns DONATION_NOT_CONFIGURED when the forwarder is not set.FlutterBridge.shared.registerIntentDonator(intentIdentifier:_:) / donateIntent(intentIdentifier:params:) / hasIntentDonator(for:); the donators dictionary is cleared by clearExecutors() alongside the other executor slots.docs/usage.md): adds the intentDonationForwarder wiring example next to the existing relevantEntitiesDonationForwarder block, plus the matching register<Intent>Donator() call site.@IntentSpec(donatable: true) — opt-in for AppIntent.donate() so Siri / Apple Intelligence learns the user performed the action in-app (#55). Inert unless the donation experimental feature is enabled in app_intents_codegen. MVP restricts to primitive parameter types (String / int / double / bool / DateTime, optionals allowed); entity / file / enum / union / collection params are rejected at codegen time.@IntentParam(useValueState: true) — opt-in for IntentParameter.ValueState (@available(iOS 18.2, *) stable — no #if gating required). Distinguishes unset / set / cleared for an optional update parameter so the Dart handler can tell "don't touch" from "explicitly cleared." Only valid on a nullable Dart type; analyzer rejects use on non-optional params.AppSchemas.system.searchInApp — typed accessor for the iOS 27 system search-in-app schema (iOS 17 used .system.search; iOS 27 renamed it). The iOS-17 identifier remains reachable via AppSchemas.of(AppSchemaDomain.system, 'search'). Also adds AppSchemas.system.open.@IntentSpec(donatable: true) (#55, requires --experimental=donation): emits a #if APP_INTENTS_WWDC26-gated register<Intent>Donator() reverse-executor that reconstructs the concrete intent from a [String: Any] params dict and calls intent.donate() (stable iOS 16+). Analyzer enforces the MVP primitive-only contract; rejects entityType / enumType / fileType / entityCollectionType / @UnionValue / non-primitive Dart types at codegen time.@IntentParam(useValueState: true) (#52): emits if #available(iOS 18.2, *) { switch $field.valueState { … @unknown default … } } in perform() and adds a sibling "<field>State": "unset" | "cleared" | "set" entry to the wire dict. The state key is added via if let in both FlutterBridge and cache-mode emit paths, so it is absent on iOS < 18.2 and the Dart handler can distinguish "no state info" from a present state. Analyzer rejects opt-in on non-optional Dart params. The Swift output uses @unknown default to future-proof against Swift 6's non-frozen enum errors. No experimental flag — this is a normal feature (the SDK symbol is stable iOS 18.2).AppSchemas.system.searchInApp — codegen consumes the schema string verbatim through the existing @AppIntent(schema:) / @AppEntity(schema:) macro emission (the app-schema experimental gate is unchanged); no codegen change beyond the typed accessor that lives in app_intents_annotations.app_intents_annotations dependency to ^0.12.0.CLAUDE.md adds a new Deferred WWDC26 punch list section reserving ADR numbers 0005–0010 for the seven defer-with-ADR items uncovered by the matsudate review #4 audit (snippetView, dialogFullSupporting, requestValue, PlaceDescriptor export, LongRunningIntent progress/cancel forwarding, SyncableEntityIdentifier dual-id, @AppIntentsPackage). One document-only item (notificationEntity) is also tracked.
AppIntentsBridge suite green (26 tests, .serialized trait fixed the shared-singleton race when adding the new intent-donator tests).swiftc -typecheck of the useValueState emit pattern against the Xcode 27 beta iOS 27 SDK (target iOS 17.0): exit 0, no warnings.First release since v0.10.1 to ship the accumulated WWDC26 App Intents work (opt-in, default OFF), plus a documentation audit pass. All three packages
First release since v0.10.1 to ship the accumulated WWDC26 App Intents work (opt-in, default OFF), plus a documentation audit pass. All three packages are released together at the same version.
registerValueQueryHandler + platform queryValuesAsync (generic inbound value query; the visual SemanticContentDescriptor variant is out of scope)donateRelevantEntities(id, entities, context:) via a reverse executor, wired through AppIntentsPlugin.relevantEntitiesDonationForwardersetOnscreenEntity(typeId, instanceId, title:) / clearOnscreenEntity() backed by NSUserActivity, plus AppIntentsPlugin.onscreenEntityBinderAppIntentsPlugin.swift accordinglycompileSdk/targetSdk 37, minSdk 36 — the previous "36" would fail the appfunctions:1.0.0-alpha09 AAR-metadata check) and replace the placeholder example app READMEs with real contentapp_intents_codegen):
@IntentSpec(longRunning:, cancellable:, executionTargets:) + the IntentExecutionTarget enumschema: on @EntitySpec / @IntentSpec / @EnumSpec, plus the AppSchemas catalog (messages / mail / photos)@EntityProperty(title:, indexingKey:)@EntitySpec(ownership:) + EntityOwnershipStateDuration parameters, the new PersonName value type, @IntentParam(entityCollectionType:), and @UnionValueSpec / @UnionCase (which codegen lowers to a native @UnionValue enum)@EntitySpec(exportAs:) + EntityExportType@EntitySpec(valueQuery:, syncable:, relevantEntities:)--experimental-wwdc26 + per-feature --experimental=<flag> (app-schema, ownership, long-running, rich-types, value-query, value-representation, donation). Experimental Swift is emitted inside #if APP_INTENTS_WWDC26 with a mandatory stable #else fallback, so released-SDK builds (without the flag) still compile.
LongRunningIntent / CancellableIntent / execution targets@AppEntity/@AppIntent/@AppEnum(schema:) and @Property(indexingKey:) (indexing ships as a normal iOS 18.4 feature)OwnershipProvidingEntity conformanceDuration / PersonNameComponents / EntityCollection / @UnionValue parameters with compile-everywhere fallbacks, plus a generated union fromMap factoryIntentPerson), and SyncableEntity / RelevantEntities donation (#55)swiftc -typecheck (with and without APP_INTENTS_WWDC26) against the Xcode 27 beta SDK; see scripts/verify_experimental_swift.sh@EnumSpec / @EnumCaseDisplay examples, the Dart SDK constraint (^3.10.0) and dependency ranges, the Android toolchain versions, and add the ownership experimental flag to the feature tablesPublished to pub.dev:
Full Changelog: v0.10.1...v0.11.0
Fix Android build on Kotlin 2.3+ / AGP 9.1.0+: migrate the plugin's android/build.gradle.kts from the deprecated kotlinOptions DSL to the modern compi…
android/build.gradle.kts from the deprecated kotlinOptions DSL to the modern compilerOptions DSL (#20, thanks @cpbritton)
kotlinOptions block now causes "Script compilation errors" with recent Kotlin Gradle Plugin / AGP toolchains; compilerOptions { jvmTarget.set(JvmTarget.JVM_17) } is the supported replacementapp_intents 0.10.1analyzer, source_gen, build, build_test, dart_style, test)Published to pub.dev:
Full Changelog: v0.10.0...v0.10.1
Add Swift Package Manager (SPM) support for the iOS plugin ( #29 , #30 )
ios/app_intents/Package.swift; native sources moved to ios/app_intents/Sources/app_intents/ (SPM-standard layout)app_intents.podspec now points source_files/resource_bundles at the shared Sources/ location, so CocoaPods and SPM build the same files (both remain supported during the transition)app_intents as "does not support Swift Package Manager" when host apps enable SPMflutter: '>=3.3.0' unchanged)NSPrivacyAccessedAPICategoryUserDefaults required-reason API in PrivacyInfo.xcprivacy
CA92.1 (UserDefaults accessible only to the app itself) and 1C8F.1 (UserDefaults shared within the App Group, for cross-process cache/EntityQuery data)app_intents 0.10.0Published to pub.dev:
ios/app_intents/Package.swift; native sources moved to ios/app_intents/Sources/app_intents/ (SPM-standard layout)app_intents.podspec now points source_files/resource_bundles at the shared Sources/ location, so CocoaPods and SPM build the same files (both remain supported during the transition)app_intents as "does not support Swift Package Manager" when host apps enable SPMflutter: '>=3.3.0' constraint is unchangedNSPrivacyAccessedAPICategoryUserDefaults required-reason API in PrivacyInfo.xcprivacy
CA92.1 (UserDefaults accessible only to the app itself — the UserDefaults.standard fallback) and 1C8F.1 (UserDefaults shared within the App Group — UserDefaults(suiteName:) used for cross-process cache/EntityQuery data)@AppShortcutsBuilder annotation in generated AppShortcuts
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
0.9.0 which adds EntityQuery cold-start fallback via App Group UserDefaults (#26) and the @AppShortcutsBuilder annotation in generated Swift (#25)Bump all packages to v0.8.0 to publish the AppFunctions alpha09 upgrade ( #23 ). Downstream Android hosts need AGP 9.1.0+, Gradle 9.3.1+, compileSdk 3
Bump all packages to v0.8.0 to publish the AppFunctions alpha09
upgrade (#23). Downstream Android hosts need AGP 9.1.0+, Gradle
9.3.1+, compileSdk 37, and the android.newDsl=false /
android.builtInKotlin=false shims in gradle.properties. Regenerate
Kotlin output with dart run app_intents_codegen:generate_kotlin
after upgrading.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
app_intents_codegen (#23)compileSdk = 37, and the android.newDsl=false / android.builtInKotlin=false shims in gradle.properties. See docs/usage.md for the full migration.Fix: Android AppIntentsPlugin now handles iOS-only cache methods (getCachedValue/setCachedValue/clearCachedValue/configureStorage/ processPendingActio
Fix: Android AppIntentsPlugin now handles iOS-only cache methods
(getCachedValue/setCachedValue/clearCachedValue/configureStorage/
processPendingActions) as no-ops returning null, instead of throwing
MissingPluginException. Prevents silent failures in release builds
where PlatformDispatcher.onError swallows the exception (#22).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
AppIntentsPlugin now handles iOS-only cache methods as no-ops instead of throwing MissingPluginException (#22)
getCachedValue, setCachedValue, clearCachedValue, configureStorage, and processPendingActions return null on AndroidPlatformDispatcher.onError may swallow the exceptionPlatform.isIOSFix: Return empty list instead of throwing when entity query handler is not yet registered
handleEntityQuery() and handleSuggestedEntitiesQuery() now return [] for unregistered entitiesFix: Use App Group UserDefaults to prevent cross-process data resets on iOS
WFIsolatedShortcutRunner) now share storage with the main appBundle.main.bundleIdentifier (which differs across processes)synchronize() after all UserDefaults read/writes for cross-process reliabilityconfigureStorage(appGroupIdentifier:) API for Dart-side App Group configuration (iOS only, no-op on other platforms)AppIntentsPlugin.configure(appGroupIdentifier:) static method for Swift-side configurationstorageIdentifier is not set.
If you use extension processes where Bundle.main.bundleIdentifier differs, set
storageIdentifier explicitly in configure() to ensure consistent cache key prefixes.No API changes; version bump to align with codegen bug fix release
No API changes; version bump to align with codegen bug fix release
No API changes; version bump to align with codegen bug fix release
No API changes; version bump to align with codegen bug fix release
No API changes; version bump to align with codegen bug fix release
No API changes; version bump to align with codegen package (xcstrings generation feature)
Fix: Safe casts for all MethodChannel input — prevents crash on malformed native data
processPendingActions() now processes all queued actions in a loopFlutterBridge.clearExecutors() for invalidating stale executors after Flutter engine restartDocumentation fixes: correct outdated code examples and API references
Version bump to align with annotations/codegen packages
No API changes; version bump to align with other packages
No API changes; version bump to align with codegen package
Version bump to align with annotations/codegen packages
Add caching API: getCachedValue(), setCachedValue(), clearCachedValue()
getCachedValue(), setCachedValue(), clearCachedValue()processPendingActions() for delivering cached intent actions after Flutter startuppendingActionsStream via FlutterEventChannel for buffered pending action notificationssetPendingAction() for caching intent params in UserDefaultsPendingActionStreamHandler with thread-safe buffered pushprocessPendingActions instead of nested MethodChannel callAdd Android AppFunctions support via AppIntentsPlugin.kt
AppIntentsPlugin.ktpubspec.yaml (com.example.app_intents)Fix podspec: update iOS platform from 13.0 to 17.0
BREAKING: Raise iOS minimum to 17.0
Intent handler registration via registerIntentHandler
registerIntentHandlerregisterEntityQueryHandler and registerSuggestedEntitiesHandleronIntentExecutionYour coding agent can read these notes before it upgrades. Set up the MCP server →