7.1 KiB
Specialized instructions for generating Kotlin implementations of AppFunctions, handling system-wide configuration, and managing build dependencies.
Instructions
Step 1: Gradle Dependencies & KSP
Add the following to build.gradle.kts. App Functions requires the KSP (Kotlin
Symbol Processing) plugin.
- Version Check: Use the latest library versions from maven.google.com.
implementation(libs.androidx.appfunctions)
implementation(libs.androidx.appfunctions.service)
ksp(libs.androidx.appfunctions.compiler)
ksp {
arg("appfunctions:aggregateAppFunctions", "true")
}
Step 2: App Metadata XML Setup
Describe the app's capabilities to the LLM by defining
res/xml/app_metadata.xml.
<AppFunctionAppMetadata xmlns:appfn="http://schemas.android.com/apk/androidx.appfunctions"
appfn:description="This app manages personal notes.
Operational Patterns:
- Use 'listNotes' to find the correct 'noteId' before calling 'editNote'.
Constraints:
- Note editing is only possible for existing IDs returned by the system."
appfn:displayDescription="@string/user_visible_description" />
Reference this in AndroidManifest.xml within the <application> tag:
<manifest>
<application>
<property android:name="android.app.appfunctions.app_metadata"
android:resource="@xml/app_metadata" />
</application>
</manifest>
Step 3: Function Implementation
When generating Kotlin code for AppFunctions, you MUST adhere to these rules:
- Annotations :
- Annotate the function with
@AppFunction(isDescribedByKDoc = true). - Annotate associated data classes with
@AppFunctionSerializable(isDescribedByKDoc = true).
- Annotate the function with
- Parameter Strategy :
- First Parameter : MUST be
androidx.appfunctions.AppFunctionContext. - Specificity: Keep parameters specific. State objects need to be unambiguous.
- Optionality: If a parameter is not essential, make it optional with a reasonable default value.
- First Parameter : MUST be
- Execution & Threading :
- Use
suspendfunctions. - Switch to the relevant Coroutine Dispatcher (e.g.,
withContext(Dispatchers.IO)) because AppFunction implementations run on the Android UI thread by default.
- Use
- Supported Types :
- Primitives :
Int,Long,Float,Double,Boolean. - Arrays :
IntArray,LongArray,FloatArray,DoubleArray,BooleanArray. - Native Types :
String,PendingIntent,Uri,LocalTime,LocalDate,LocalDateTime,Instant. (PreferLocalDateTimeorInstantfor date/time). - Custom Objects : Classes annotated with
@AppFunctionSerializable. - Collections :
Listof any supported non-primitive type.
- Primitives :
- Default Values :
- Use defaults that align with the type's "empty" state (e.g.,
0forInt,nullfor nullable,emptyList()forList).
- Use defaults that align with the type's "empty" state (e.g.,
- Error Handling :
- Throw subclasses of
androidx.appfunctions.AppFunctionExceptionto report errors to callers.
- Throw subclasses of
- Security :
- Don't expose highly sensitive user data (passwords, financial details).
- Don't expose irreversible destructive actions without confirmation steps.
Step 4: (Optional) System Configuration for Dependency Injection
Only required for dependency injection configuration. Implement
AppFunctionConfiguration.Provider in the Application class to provide
instances of classes containing @AppFunction methods.
Example Hilt Integration:
@HiltAndroidApp
class AppFunctionApplication : Application(), AppFunctionConfiguration.Provider {
@Inject lateinit var noteFunctions: NoteFunctions
override val appFunctionConfiguration: AppFunctionConfiguration =
AppFunctionConfiguration.Builder()
.addEnclosingClassFactory(NoteFunctions::class.java) { noteFunctions }
.build()
}
Critical Constraints
Parameter Ordering
CRITICAL : The very first parameter of an @AppFunction method MUST be
androidx.appfunctions.AppFunctionContext.
KSP Compliance for Serializables
CRITICAL : For @AppFunctionSerializable data classes, KSP only extracts
documentation if it is written as inline KDoc directly for each property
definition. NEVER use class-level @param or @property tags.
Package Integrity
Configuration APIs and the @AppFunction annotation are located in
androidx.appfunctions.service.
Examples
Example: Serializable with Inline KDoc
/**
* A note.
*/
@AppFunctionSerializable(isDescribedByKDoc = true)
data class Note(
/** The note's identifier */
val id: Int,
/** The note's title */
val title: String,
/** The note's content */
val content: String
)
Example: Implementation Detail
/**
* A note app's [AppFunction]s.
*/
class NoteFunctions @Inject constructor(
private val noteRepository: NoteRepository
) {
/**
* List all available notes in the app.
*
* @param appFunctionContext The execution context.
* @return A list of [Note] objects, or null if no notes exist.
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun listNotes(appFunctionContext: AppFunctionContext): List<Note>? {
return noteRepository.appNotes.ifEmpty { null }?.toList()
}
/**
* Create a new note with a title and body content.
*
* @param appFunctionContext The execution context.
* @param title The title of the note.
* @param content The body content of the note.
* @return The created [Note] object including its generated ID.
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun createNote(
appFunctionContext: AppFunctionContext,
title: String,
content: String
): Note {
return noteRepository.createNote(title, content)
}
/**
* Update the title or content of an existing note.
* Required workflow: Call [listNotes] first to obtain valid note IDs.
*
* @param appFunctionContext The execution context.
* @param noteId The unique identifier of the note to edit.
* @param title The new title. If null, the existing title is preserved.
* @param content The new content. If null, the existing content is preserved.
* @return The updated [Note], or null if the [noteId] was not found.
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun editNote(
appFunctionContext: AppFunctionContext,
noteId: Int,
title: String?,
content: String?,
): Note? {
return noteRepository.updateNote(noteId, title, content)
}
}
Troubleshooting
Error: "AppFunction unavailable" or "Metadata missing"
Cause: The AppSearch indexing failed to extract the schema correctly.
Solution:
- Verify
@AppFunctionSerializableclasses use inline KDoc comments, NOT class-level@paramtags. - Check that the
assets/app_function_v2.xmlfile exists in the APK. - Confirm the
ksp("androidx.appfunctions:appfunctions-compiler")dependency is correctly applied. - Ensure the
kspargumentappfunctions:aggregateAppFunctionsis set to"true".