@Retention(CLASS) @Target({METHOD})
public @interface AppIntent
Exposes a capability of your application to the system: Siri, Spotlight, the Shortcuts app, an Android launcher shortcut, a widget button, or a language model.
@AppIntent(value = "log_workout", title = "Log a workout",
description = "Records a completed workout",
phrases = {"Log a workout in ${applicationName}"},
headless = true, timeoutSeconds = 5)
public static IntentResult logWorkout(
@IntentParam(value = "kind", title = "What kind of workout?",
options = {"run", "ride", "swim"}) String kind,
@IntentParam(value = "minutes", title = "How many minutes?") int minutes) {
WorkoutStore.append(kind, minutes);
return IntentResult.spoken("Logged a " + minutes + " minute " + kind + ".");
}
The handler must be public static
This is not a style preference. The build generates a direct static call
to your method, and a direct call is the only form that survives the iOS
translator’s dead-code elimination and Android’s obfuscation – a reflective
lookup would be stripped on iOS and renamed on Android, in both cases
silently. static also makes the contract visible: a handler can be asked to
run in a process that exists only to answer it, where no instance of yours
has been constructed and nothing is on screen.
The method returns com.codename1.intents.IntentResult, or void when it
has nothing to report. It may take com.codename1.intents.IntentContext as
its first parameter to see the deadline, the source and the cancellation
flag. Every other parameter must carry IntentParam.
At build time
The Codename One Maven plugin scans the project’s compiled bytecode,
validates every @AppIntent, and generates both the reflection-free dispatch
table and the native declarations each platform compiles into the app. A
malformed declaration fails the build rather than going quiet on a device.
Phrases
Apple enforces three rules on a spoken phrase, all of them as build failures
that produce no App Intents metadata at all. The build checks them here
instead, so the message names your declaration rather than arriving as an
opaque failure from appintentsmetadataprocessor:
- Every phrase must contain
${applicationName}. - A phrase may reference at most one parameter. Write one phrase per parameter rather than combining them.
- A phrase parameter must be an
IntentEntitytype. A primitive cannot appear in a phrase, which is not much of a loss: leave it out and the platform still asks for it, using the title on itsIntentParam.
An intent that declares phrases must also be discoverable, since a phrase
is only reachable through an App Shortcut.
Phrases are ignored on platforms with no voice invocation, which today means Android.
Methods
public abstract String value() | The stable id, matching [a-z][a-z0-9_]{2,63}. |
public abstract String title() | The human-readable name shown in the Shortcuts app. |
public abstract String description() default "" | A longer explanation shown alongside the title. |
public abstract String[] phrases() default {} | Spoken phrases that invoke this intent. |
public abstract boolean headless() default false | True when this intent may run without bringing the app to the foreground. |
public abstract boolean discoverable() default true | True when the platform may offer this intent before the user has ever run it. |
public abstract boolean destructive() default false | True when the platform should confirm with the user before running this. |
public abstract String opensRoute() default "" | A route template to open instead of answering in place, for example /orders/{orderId}, where each {name} names one of this intent’s parameters. |
public abstract Exposure[] exposure() default {Exposure.ASSISTANT} | Which consumers this intent is offered to. |
public abstract int timeoutSeconds() default 20 | How long the handler may run before the framework reports a failure. |
Method details
value
public abstract String value()The stable id, matching [a-z][a-z0-9_]{2,63}. Required.
It is stable in the strong sense: the system stores it in donated shortcuts and the user’s own Shortcuts workflows, so renaming one breaks what people already built.
title
public abstract String title()description
public abstract String description() default ""phrases
public abstract String[] phrases() default {}${applicationName}.headless
public abstract boolean headless() default falseTrue when this intent may run without bringing the app to the foreground.
A headless handler must not touch Form, Dialog, or anything else
needing a window; see the com.codename1.intents package documentation
for the full contract.
Leaving it false brings the app forward, which gives the handler a window to act on –
not permission to touch one from the handler’s own thread. No handler runs on the event
dispatch thread, so a foreground handler updates the user interface through
Display#callSerially, as any background thread does.
discoverable
public abstract boolean discoverable() default truedestructive
public abstract boolean destructive() default falseTrue when the platform should confirm with the user before running this. Set it on anything that deletes, sends, or spends.
It also closes the paths that cannot confirm. A destructive intent is not published as an Android launcher shortcut, is refused when an unauthenticated caller asks for it, and is not donated – each of those runs on a single tap with nothing in between. The capability stays fully available through the assistant and the Shortcuts app, which confirm first; what goes away is the one-tap route to it.
opensRoute
public abstract String opensRoute() default ""A route template to open instead of answering in place, for example
/orders/{orderId}, where each {name} names one of this intent’s
parameters.
The URL is resolved through the same Route table that handles deep
links, so an intent and a link to the same screen cannot drift apart.
A non-empty value is also what tells the platform to open the app.
exposure
public abstract Exposure[] exposure() default {Exposure.ASSISTANT}Exposure.MODEL to also offer it to a language model through
com.codename1.intents.Intents#asTools().timeoutSeconds
public abstract int timeoutSeconds() default 20How long the handler may run before the framework reports a failure.
The platform usually allows around twenty seconds. Do not use them: a
spoken interaction that takes ten seconds has already failed as an
interaction. Aim under two, and return IntentResult.opens(...) for
anything genuinely slower.