Platform & Testing
What happens at build time
Section titled “What happens at build time”[AppFunction] records, handlers, [AppEntity] + queries, delegates │ Roslyn source generator ├─ AddAppFunctions() DI registration ├─ GeneratedAppFunctionRegistry descriptors + reflection-free binding, dispatch and result writing └─ the Swift and Android XML, as string constants │ MSBuild task, after compile: reads the constants from the compiled assembly and writes the files ├─ iOS swiftc → a static library linked into the app │ appintentsmetadataprocessor + appintentsnltrainingprocessor → Metadata.appintents in the .app, before signing └─ Android app_functions.xml, app_functions_v2.xml and the schema XSD as assetsNothing is done with reflection, so it is trim- and AOT-safe. The generator, the MSBuild task and the build targets all ship inside the Shiny.AppFunctions package; only the app project (not class libraries that reference the package) runs the build step.
| iOS | Android | |
|---|---|---|
| Code to write | none - a Shiny startup task connects the Swift bridge | none |
| Manifest / plist | none. CFBundleDevelopmentRegion is added when missing |
none - the service comes from the library’s manifest through the manifest merger |
| Entitlements | none - App Intents don’t need one | - |
| Minimum OS | iOS 16 | Android 16 (API 36); a no-op below |
The iOS build needs Xcode, since it runs swiftc and Apple’s App Intents processors.
When a call arrives
Section titled “When a call arrives”The OS can call in before your app has built its DI container - a cold start from Siri, or the Android service being bound early. The Swift bridge and the Android service wait up to 10 seconds (AppFunctionsHost.ReadyTimeout) for the host, then fail the call. Handlers run in the background with no UI, often with the app launched just for them, so persist any state they change and let pages refresh when they appear.
Build properties
Section titled “Build properties”All optional; set them in the app’s project file.
| Property | Default | |
|---|---|---|
ShinyAppFunctionsEnabled |
true |
false skips generating and building the App Intents and the Android assets |
ShinyAppFunctionsMinimumOSVersion |
the app’s SupportedOSPlatformVersion, at least 16.0 |
the iOS deployment target of the Swift intents |
ShinyAppFunctionsDevelopmentRegion |
en |
added to the built Info.plist only when it has no CFBundleDevelopmentRegion |
ShinyAppFunctionsConstProtocolsFile |
the list shipped for Xcode 27 | swiftc’s const-extraction protocol list. Xcode builds this internally, so a later Xcode may need an updated one |
Generator diagnostics
Section titled “Generator diagnostics”| Id | |
|---|---|
| SHAF001 | Invalid function or entity id |
| SHAF002 | An [AppFunction] type must implement exactly one of IAppFunction / IAppFunction<TResult> |
| SHAF003 | Unsupported parameter or result type |
| SHAF004 | The request can’t be constructed from its parameters |
| SHAF005 | No handler for a function |
| SHAF006 | More than one handler for a function |
| SHAF007 | An [AppEntity] needs a public string Id |
| SHAF008 | The entity’s display property doesn’t exist |
| SHAF009 | No IAppEntityQuery<T> for an entity |
| SHAF010 | Duplicate id |
| SHAF011 | An App Shortcut phrase must contain ${applicationName} |
| SHAF012 | More than 10 App Shortcuts |
| SHAF013 | A handler, query or delegate has no public constructor |
Testing
Section titled “Testing”Android
Section titled “Android”On an Android 16+ emulator or device, the shell can list and call your functions - every call can be a cold start:
adb shell cmd app_function list-app-functions --package com.mycompany.myapp
adb shell "cmd app_function execute-app-function --package com.mycompany.myapp \ --function create_order --parameters '{\"customer\":\"acme\",\"quantity\":2,\"priority\":\"Normal\"}'"
adb shell "cmd app_function execute-app-function --package com.mycompany.myapp \ --function search_customer --parameters '{\"query\":\"acme\"}'"Install the app on a simulator or device, then search a shortcut’s title or phrase in Spotlight (“New Order”, “Open Orders”), or find the app’s actions in the Shortcuts app. Running an App Shortcut from Spotlight starts the app in the background and shows the handler’s context.Say(...) text as the Siri dialog.
In-process
Section titled “In-process”Handlers are plain classes, and AppFunctionDispatcher runs the whole pipeline - binding, delegates, handler and result - without an OS in the loop.
Known limits
Section titled “Known limits”- Only the app project is scanned; functions declared in a class library are ignored without a diagnostic.
- Titles and descriptions are not localized.
- An iOS build with more than one runtime identifier at once (for example arm64 and x64 simulator together) is not supported by the metadata step.
AppFunctionGate.OpenAppon iOS continues in the foreground withcontinueInForegroundon iOS 26+,ForegroundContinuableIntenton iOS 17-25, and fails with the message on iOS 16.


