app_intents_codegen 0.17.0
app_intents_codegen: ^0.17.0 copied to clipboard
Code generator for Flutter AppIntents. Produces Swift and Dart code from @IntentSpec and @EntitySpec annotations.
0.17.0 #
Behavior change for CLI users.
generate_swift,generate_widget_swiftandgenerate_kotlinnow fail with exit code 1 when an annotation is invalid. Previously the analyzer's error was printed as aWarning: Could not analyze …line, the spec was left out of the output, and the command still exited 0 — so a project whose only specs were invalid got empty output with no failure. If a build that used to pass now stops here, the printed error names the file and the problem; that spec was never being generated.
Fix for FlutterBridge-mode intents — regenerate your Swift. 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. URL scheme and foreground (cache) intents were already correct.
analyzeSourceFilesthrowsInvalidAnnotationsExceptioninstead of swallowing the analyzers'InvalidGenerationSourceError. All files are scanned before it throws, so every invalid spec is reported in one run. A file that fails to resolve is still skipped with a warning, as before.- Place export (#128).
@EntitySpec(exportAs: EntityExportType.place)exports the entity as aGeoToolbox.PlaceDescriptor, built from fields marked@EntityExportField(EntityExportRole.latitude / .longitude / .address).IntentCurrencyAmountis deliberately not an export type:ValueRepresentation(exporting:)is only declared forIntentPersonand_SystemIntentValueconformers, and it is neither (measured against the iOS 27.0 SDK). - Import (#129).
@EntitySpec(importable: true)generatesValueRepresentation(exporting:importing:). The import rides the value-query bridge under<identifier>#import; register the Dart side withAppIntents().registerValueImportHandler. - Progress, cancellation and
requestValue(#130, #131, ADR 0010). Long-running intents open an execution scope, pass its id to Dart, and forwardonCancel:instead of leaving a comment stub.@IntentParam(requestValue: true)lets the handler prompt for an optional primitive parameter mid-run. Generated handler signatures are unchanged — the handler reaches the scope throughAppIntentExecution.current. - Dual identifiers (#132).
@EntityStableId+@EntitySpec(syncable: true)makes the entity's id aSyncableEntityIdentifier<String, String>; the entity and its query dual-branch. Using such an entity as an@IntentParam(entityType:)value is a generation error. - Relevant-entity removal, re-indexing and union value queries (#133). The generated relevant-entities donator takes an
operationargument;IndexedEntityQueryre-indexing is emitted behind--experimental=reindexing;@UnionValueSpec(valueQuery: true)generates anIntentValueQueryreturning the union.generate_swiftnow also collects@UnionValueSpecclasses that no intent parameter references. - The
--app-intents-packagehelp text warns against using it on a statically linked target, where it has been observed to stop App Intents being ingested in TestFlight / App Store builds only (ADR 0008). - Bumps
app_intents_annotationsdependency to^0.17.0.
0.16.0 #
Heads-up for
@EntitySpec(valueQuery: true)users. TheIntentValueQuerytype is now generated by default. If you had that flag set but were not passing--experimental=value-query, the query appears in your generated Swift for the first time — make sure a Dart<entity>ValueQueryhandler exists. Everyone else is unaffected.
generate_widget_swift --publicemits the generated declarations aspublic, for the shared-module setup ADR 0009 documents. Without it Swift's defaultinternalhides the configuration intent, its parameters, the entities and the donator registration from an importing target — which a single-fileswiftc -typecheckcannot reveal, since the file compiles fine on its own.scripts/verify_widget_module_swift.shbuilds the output as a module and compiles a consumer that imports it.- Fixes two ways a relevant-intent donation lost its dates. The generated decoder used a default
ISO8601DateFormatter, which rejects the fractional secondsDateTime.toIso8601String()always emits — everydate/dateRangedonation was silently dropped, and since the API replaces the app's whole set, a batch of only date donations cleared it instead. It now tries fractional and second precision. ADateTimewidget parameter is also carried as an ISO-8601 string, because Flutter's standard codec cannot encodeDateTimeat all. RelevantIntentdonation (#55, ADR 0009).@WidgetConfigurationSpec(relevantIntents: true)makesgenerate_widget_swiftemit aregisterRelevantIntentDonator()plus aRelevantContextdecoder. One donator per file, not per configuration, becauseRelevantIntentManager.updateRelevantIntentsreplaces the app's whole set. Entity parameters are resolved through the cache-backed widget query so the donated intent carries a full entity; scalar parameters absent from a donation are left unset rather than defaulted. Not experimental —RelevantIntentManageris iOS 17; only thekind:date refinements are iOS 26 and they sit behindif #available.scripts/verify_experimental_swift.shnow type-checks the example's generated Widget Extension Swift too. Nothing compiled that output before except an Xcode build.- Placeholder parsing for dialog and snippet templates is shared between the analyzer, the Dart generator and the Swift generator, and tolerates padding (
{ result.x }). Previously each 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. AppIntentsPackagegeneration (ADR 0008).generate_swiftandgenerate_widget_swiftgain--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 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, and is not a fix for a type missing fromMetadata.appIntents.- Declarative snippet cards (
@IntentSpec(snippet:), ADR 0007). Generates a self-contained SwiftUI<Intent>SnippetViewfrom a fixed layout (optional SF Symbol, title, optional subtitle,LabeledContentrows) and returns it with.result(view:), so a Flutter app can put a card in Siri's result without supplying a SwiftUI view. Templates interpolate{paramName}(any execution mode) and{result.key}(the Dart handler's returned map — FlutterBridge mode only; using it on a URL scheme or foreground intent is a generation error instead of a card that renders empty).{result.key}works inresultDialogTemplatetoo. Row labels are collected into the String Catalog. Not experimental —ShowsSnippetViewis iOS 16; the generated file gainsimport SwiftUIbecause.result(view:)lives in the_AppIntents_SwiftUIoverlay. - For an intent whose snippet or dialog reads
{result.…}, the generated registration now returns the handler's value throughintentResultPayloadinstead of discarding it. Every other intent's generated Dart is unchanged. IntentDialog(full:supporting:)support (ADR 0006).@IntentSpecgainsresultDialogSupportingTemplate(the on-screen half, so the spoken line can carry context a reader already has) andresultDialogSystemImageName(an SF Symbol). Both requireresultDialogTemplateand 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 behindif #available(iOS 17.2, *)with the symbol-less dialog as the fallback. The supporting template is collected into the String Catalog like the main one. Not experimental —IntentDialog(full:supporting:)is iOS 16.IntentValueQuery(#51) graduated out of the experimental opt-in. The protocol is declared at iOS 26.0 and ships in the released iOS 26.5 SDK (Xcode 26.6), so#if APP_INTENTS_WWDC26was never the right guard — the<Entity>ValueQuerystruct is now emitted whenever@EntitySpec(valueQuery: true)is set, under@available(iOS 26.0, *). Action required: none if you already passed--experimental=value-query(the flag is still accepted and now reported as a no-op); if you setvalueQuery: truewithout the flag, the query now appears in your generated Swift for the first time. An entity that also opts into App Schema (#49) keeps the#if/#elsepair, because the entity type itself is iOS 27 only in that branch.- CLI:
--experimental=value-queryis still accepted and now prints why it is a no-op, instead of being rejected outright once the feature graduated out of the flag list. scripts/verify_experimental_swift.sh: fixed a staleAppIntentsBridgesource path that had been broken since the module moved into the plugin's Swift package (#102), and taught it to run against a stable Xcode (it then checks only the non-#ifbranch, which is what proves an ungated feature compiles without the iOS 27 SDK).
0.15.0 #
- No codegen changes. The
import AppIntentsBridgeline thatgenerate_widget_swiftemits now resolves on the CocoaPods route too (#105), and the module ships as a product of the plugin's Swift package (#102 follow-up) — see theapp_intentschangelog anddocs/usage.md→ "Consuming AppIntentsBridge". - Bumps
app_intents_annotationsdependency to^0.15.0.
0.14.0 #
- Widens the
analyzerconstraint to>=7.0.0 <15.0.0, so this package can be used alongsideanalyzer14.x. Verified againstanalyzer14.1.0 /_fe_analyzer_shared105.0.0: analysis is clean, the full test suite passes, andbuild_runner,generate_swift,generate_widget_swiftandgenerate_kotlinall produce byte-identical output to the 13.x resolution. - Bumps
app_intents_annotationsdependency to^0.14.0. - Docs: the Swift emitted by
generate_widget_swiftopens withimport AppIntentsBridge; that package now ships inside theapp_intentspub package, so a Widget Extension target can resolve it. Seedocs/usage.md→ "Consuming AppIntentsBridge" (#102).
0.13.0 #
- Fix: entity
@EntityIdfields not namedidgenerated Swift that does not compile.AppEntityrefinesIdentifiable, which requires a stored property literally namedid;SwiftGeneratoremitted the Dart field name verbatim, so@EntityIdon e.g.teamIdproducedtype 'X' does not conform to protocol 'AppEntity'/'Identifiable'(and a confusing'ObjectIdentifier' does not conform to 'EntityIdentifierConvertible'). The Swift identifier property is now always emitted asid, while the Dart field name survives as the cache/dictionary key (dict["teamId"]) — matching what the Dart cache projection writes, and matching the rest of the generator, which already read<entity>.idunconditionally when serializing entity-typed intent parameters. Entities whose field is already namedidgenerate byte-identical output. The unnormalizable case (@EntityIdon a non-idfield plus a separate field namedid) now throwsInvalidGenerationSourceErrorinstead of emitting twovar iddeclarations. @WidgetConfigurationSpeccodegen + thegenerate_widget_swiftCLI — emits aWidgetConfigurationIntentplus a cache-backedEntityQueryfor a Widget Extension target, which reads the App Group entity cache instead of going throughFlutterBridge(#98).WidgetSwiftGeneratorapplies the sameidnormalization described above.- Bumps
app_intents_annotationsdependency to^0.13.0.
0.12.0 #
@IntentSpec(donatable: true)(#55, requires--experimental=donation): emits a#if APP_INTENTS_WWDC26-gatedregister<Intent>Donator()reverse-executor that reconstructs the concrete intent from a[String: Any]params dict and callsintent.donate()(stable iOS 16+). Analyzer enforces the MVP primitive-only contract; rejectsentityType/enumType/fileType/entityCollectionType/@UnionValue/ non-primitive Dart types at codegen time.@IntentParam(useValueState: true)(#52): emitsif #available(iOS 18.2, *) { switch $field.valueState { … @unknown default … } }inperform()and adds a sibling"<field>State": "unset" | "cleared" | "set"entry to the wire dict. The state key is added viaif letin 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 defaultto 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 (theapp-schemaexperimental gate is unchanged); no codegen change beyond the typed accessor that lives inapp_intents_annotations.- Bumps
app_intents_annotationsdependency to^0.12.0.
0.11.0 #
- WWDC26 experimental code generation (opt-in, default OFF). Master switch
--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_WWDC26with a mandatory stable#elsefallback, so released-SDK builds (without the flag) still compile.- Intent execution control (#52):
LongRunningIntent/CancellableIntent/ execution targets. - App Schema (#49) + semantic indexing (#50):
@AppEntity/@AppIntent/@AppEnum(schema:)and@Property(indexingKey:)(indexing ships as a normal iOS 18.4 feature). - Entity ownership (#55): additive
OwnershipProvidingEntityconformance. - Rich parameter types (#53): native
Duration/PersonNameComponents/EntityCollection/@UnionValueparameters with compile-everywhere fallbacks, plus a generated unionfromMapfactory. - IntentValueQuery (#51), cross-app export (#54,
IntentPerson), andSyncableEntity/RelevantEntitiesdonation (#55). - Dual-branch output verified via
swiftc -typecheck(with and withoutAPP_INTENTS_WWDC26) against the Xcode 27 beta SDK; seescripts/verify_experimental_swift.sh.
- Intent execution control (#52):
- AppIntentsTesting scaffold for the example app (#57, compile-checked, inert on stable Xcode).
- Docs: correct the
@EnumSpec/@EnumCaseDisplayexamples, the Dart SDK constraint (^3.10.0) and dependency ranges, the Android toolchain versions, and add theownershipexperimental flag to the feature tables.
0.10.1 #
- No codegen changes; version bump aligns with
app_intents0.10.1 (AndroidcompilerOptionsDSL fix for Kotlin 2.3+ / AGP 9.1.0+, #20) - Maintenance: dependency bumps (
analyzer,source_gen,build,build_test,dart_style,test)
0.10.0 #
- No codegen changes; version bump aligns with
app_intents0.10.0 (Swift Package Manager support for the iOS plugin, #29)
0.9.0 #
- Generated Swift
EntityQuerynow reads cached entities from App GroupUserDefaultsbefore waiting on the Flutter executor, mitigating the cold-startentityQueryNotConfigurederror when iOS has killed the host app (#26) SwiftGeneratoremits the new App Group fallback path when@EntitySpec(persistedCacheKey: ...)is set, or whenenumerable: true/indexed: trueprovides a default keyapp_intents.entities.<identifier>- Generated Swift
AppShortcutsstruct now uses the@AppShortcutsBuilderresult builder annotation per Apple'sAppShortcutsProviderprotocol requirement (#25)
0.8.0 #
- Upgrade
androidx.appfunctionsfrom1.0.0-alpha07to1.0.0-alpha09in the example app (#23) KotlinGeneratornow emits@AppFunction(isDescribedByKDoc = true)and@AppFunctionSerializable(isDescribedByKDoc = true)(uppercaseD) to match the renamed parameter introduced in alpha08- Breaking for downstream Android hosts: alpha09's AAR metadata requires AGP 9.1.0+, Gradle 9.3.1+, and
compileSdk = 37. Hosts also needandroid.newDsl=false(Flutter Gradle plugin compatibility) andandroid.builtInKotlin=false(KSP compatibility) inandroid/gradle.properties. Regenerate Kotlin output withdart run app_intents_codegen:generate_kotlinafter upgrading. Seedocs/usage.mdfor the full setup.
0.7.8 #
- No codegen changes; version bump to align with plugin fix release (Android cache no-op handlers)
0.7.7 #
- No codegen changes; version bump to align with plugin fix release
0.7.6 #
- No codegen changes; version bump to align with plugin bug fix release (App Group storage fix)
0.7.5 #
- Fix: Kotlin codegen file parameter (
IntentFile) now includesmimeTypeandfilenamein generated map (#15) - Docs: Add
waitForPlugin()pattern explanation with timeout rationale and failure behavior (#16) - Docs: Document
processPendingActions()initialization order and cold start race condition (#17) - Docs: Add
updateAppShortcutParameters()migration guide for users migrating from other libraries (#18)
0.7.4 #
- Fix: Use
${param}placeholder format in xcstrings keys for ParameterSummary and AppShortcut phrases (#14)- Swift key-path syntax
\(\.$param)requires${param}in xcstrings keys, not{param} - YAML translations support both
{param}and${param}key formats
- Swift key-path syntax
- Revert: Remove
LocalizedStringResourcewrapper fromIntentDescription(unnecessary for localization)
0.7.3 #
- Fix: Wrap
IntentDescriptionwithLocalizedStringResourcefor proper localization support (#14)
0.7.2 #
- Fix: Escape newlines in Swift
IntentDescription("...")string literal to prevent compile errors
0.7.1 #
- Fix: Kotlin KDoc multiline description now correctly adds
*prefix to continuation lines - Fix: Add missing
import AppIntentsBridgein generated Swift code for FlutterBridge mode and entity queries
0.7.0 #
- Add
.xcstringsString Catalog generation for iOS localization- New
XcstringsGeneratorclass collects all localizable strings from annotations - Translations YAML file support for multi-language localization
- Merge mode preserves existing translations when regenerating
{param}placeholders converted to%@/%1$@format;${applicationName}preserved
- New
- Add CLI options to
generate_swift:--xcstrings,--translations,--source-language - Add
yamlpackage dependency
0.6.2 #
- Fix:
_toUpperSnakeCaseno longer prepends underscore to uppercase-starting enum names in KotlinGenerator - Fix: Add missing
returnkeyword indisplayRepresentationfor entities without nullable image - Fix: Deduplicate
generateAppShortcutsProvider/_generateShortcutsProviderBodyin SwiftGenerator - Fix: Simplify
_cleanClassNameto single-passSpecsuffix removal - Fix: Extract
_isNullableParamhelper to eliminate triple-computation in DartGenerator - Fix: Remove unnecessary intermediate
StringBufferingenerateAll - Fix: Add temp file cleanup in generated Swift code for FlutterBridge execution mode
- Improve: Analyzer error reporting —
InvalidGenerationSourceErrorinstead of silent null for missing required fields - Improve: Fix
_toDisplayTitledocstring accuracy in EnumAnalyzer - Improve: Inline
_formatTypedead abstraction in EntityAnalyzer - Improve: Type
_extractPhrasesparameter asDartObject?instead ofdynamicin ShortcutAnalyzer
0.6.1 #
- Fix: Map
IntentFile/IntentFile?toString/String?in KotlinGenerator for KSP compatibility (#11)- KSP compiler does not support
IntentFileas@AppFunctionparameter type - File parameters now generate
mapOf("path" to value)for Dart-sideIntentFile.fromMap()compatibility
- KSP compiler does not support
- Documentation fixes: correct outdated code examples and API references
0.6.0 #
- BREAKING: Remove
inputType/outputTypefromIntentInfomodel - Generate type-safe
XxxParamsclass for each intent with parametersfromMap(Map<String, dynamic>)for MethodChannel / cache modefromQueryParameters(Map<String, String>)for URL scheme deep links- Supports String, int, double, bool, DateTime, IntentFile types
- Handler registration now uses Params class and always returns empty map
- Remove
_extractTypeArguments()from IntentAnalyzer
0.5.2 #
- Fix Swift 6 strict concurrency errors in
FlutterBridge.swiftwhen used as SPM package- Add
sendingkeyword to all non-Sendable parameters and return types crossing actor boundaries - Affects
invoke(),queryEntities(),suggestedEntities(), and all executor/handler closures
- Add
0.5.1 #
- Add root
Package.swiftso AppIntentsBridge can be fetched via standard SPM from repository URL
0.5.0 #
- Fix AppShortcut phrase
{paramName}to generate\(\.$paramName)Swift syntax - Add
imageNamesupport in@EnumCaseDisplaycode generation (asset bundle image) - Add
displayImageNamesupport in@EntitySpecfor entityDisplayRepresentationimage- Static image via
named:for entity type, per-instance@EntityImageviasystemName:takes priority
- Static image via
- Add
EnumerableEntityQueryextension generation whenenumerable: true - Add
IndexedEntityextension generation whenindexed: true(iOS 26+,import CoreSpotlight) - Update
EnumAnalyzerto extractimageNamefrom@EnumCaseDisplay - Update
EntityAnalyzerto extractdisplayImageName,indexed,enumerablefrom@EntitySpec - 189 tests (28 new tests for all new features)
0.4.1 #
- Widen dependency constraints to resolve conflicts with other codegen packages (e.g.,
go_router_builder)source_gen: ">=2.0.0 <5.0.0"(was^2.0.0)analyzer: ">=7.0.0 <11.0.0"(was^7.0.0)build: ">=2.4.0 <5.0.0"(was^2.4.0)build_test: ">=2.2.0 <4.0.0"(was^2.2.0)
- Migrate to
TypeChecker.fromUrl()for compatibility with source_gen 4.x - Migrate to
LibraryElement.classes/.enumsAPI for compatibility with analyzer 10.x - Fix nullable
element.namehandling for analyzer 10.x
0.4.0 #
- Add
supportedModessupport in SwiftGenerator- Generates
@available(iOS 26.0, *) static var supportedModes: IntentModes { .foreground } - Generates
static var openAppWhenRun: Bool { true }for backward compatibility - Both properties generated when
supportedModes: foregroundorurlSchemeis set
- Generates
- Add
IntentFileparameter support in SwiftGenerator@Parameter(supportedTypeIdentifiers:)for file type parameters- File serialization code generation (write to temp file, extract path/mimeType/filename)
import UniformTypeIdentifierswhen file params present
- Add cache mode in SwiftGenerator (
_writeCachePerformMethod)- Auto-generated when
supportedModes: foregroundwithouturlScheme - Caches params to UserDefaults via
AppIntentsPlugin.setPendingAction() processPendingActions()delivers cached actions via existingexecuteIntentmechanism
- Auto-generated when
- Add
IntentFile.fromMap()extraction in DartGenerator for file parameters - Fix: Use
Map.from()for IntentFile params from MethodChannel (avoid type cast errors) - Add
IntentModeTypeenum andfileTypefield to codegen models - Update IntentAnalyzer to parse
supportedModesandfileTypeannotations
0.3.0 #
- Add
KotlinGeneratorfor Android AppFunctions code generation@AppFunction(isDescribedByKdoc = true)annotated methods@AppFunctionSerializabledata classes for entitiesAppFunctionsBridgesingleton for MethodChannel communication- Enum class generation with
fromValue()companion object
- Add CLI command
generate_kotlinfor Kotlin file output - Extract shared
analyzeSources()utility for Swift/Kotlin CLI commands - 154 tests (38 new Kotlin generator tests)
- Update documentation for cross-platform support
0.2.1 #
- Documentation updates to reflect v0.2.0 features
- No code changes
0.2.0 #
- BREAKING: Raise iOS minimum to 17.0
- Add
IntentResult & ProvidesDialogsupport viaresultDialogTemplate - Add
ParameterSummarygeneration viaparameterSummary - Add
AppEnumcode generation (@EnumSpec,EnumAnalyzer,_generateEnumBody) - Add entity image support in
DisplayRepresentation(SF Symbol icons) - Add
{applicationName}to\(.applicationName)phrase conversion for AppShortcuts - Fix AppShortcutsProvider to use Swift result builder pattern (no array literals)
- Fix error handling:
throw AppIntentError.custom(...)instead of silentreturn .result() - Fix double-quote escaping in dialog templates
- Fix shortcut
intentIdentifiertoclassNameresolution in CLI - 116 tests covering all analyzers, generators, and builder
0.1.0 #
- Initial release
IntentAnalyzerandEntityAnalyzerfor annotation parsingShortcutAnalyzerfor@AppShortcutand@AppShortcutsProvidersupportSwiftGeneratorfor iOS 17+ App Intent Swift code generationDartGeneratorfor handler initialization code generation- CLI tool
generate_swiftfor Swift code output - Integration with
build_runnerviaAppIntentsBuilder