Panduan ini menjelaskan cara mengintegrasikan AppFunctions API ke dalam aplikasi Android Anda, menerapkan logika untuk suatu fungsi, dan memverifikasi bahwa integrasi berfungsi dengan benar.
Kompatibilitas versi
Implementasi ini mengharuskan compileSdk project Anda ditetapkan ke API level 36 atau yang lebih tinggi.
Aplikasi Anda tidak diwajibkan untuk memverifikasi apakah AppFunctions didukung atau tidak. Hal ini ditangani secara otomatis dalam library Jetpack AppFunctions.
AppFunctionManager menampilkan instance jika fitur didukung, dan menampilkan null jika tidak.
Dependensi
Tambahkan dependensi library yang diperlukan ke file build.gradle.kts (atau build.gradle) modul Anda, dan konfigurasi plugin KSP di modul aplikasi tingkat atas seperti yang ditunjukkan:
# Add this to your app module at the top level. For multi module applications,
# you only need to specify this once.
ksp {
arg("appfunctions:aggregateAppFunctions", "true")
}
dependencies {
implementation("androidx.appfunctions:appfunctions:1.0.0-alpha09")
implementation("androidx.appfunctions:appfunctions-service:1.0.0-alpha09")
// If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP)
// See Add the KSP plugin to your project
ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha09")
}
Mengimplementasikan logika AppFunctions
Untuk mengimplementasikan AppFunction untuk aplikasi Android Anda, buat class yang mengimplementasikan logika AppFunctions tertentu. Hal ini melibatkan pembuatan class data yang dapat diserialisasi untuk parameter dan respons, lalu menyediakan logika inti dalam metode fungsi.
Kode berikut menunjukkan contoh implementasi untuk membuat tugas di aplikasi TODO, termasuk menentukan parameter dan jenis respons kustom serta logika fungsi utama menggunakan repositori.
package com.example.android.appfunctions
import androidx.appfunctions.AppFunctionSerializable
import androidx.appfunctions.AppFunctionContext
import androidx.appfunctions.AppFunctionElementNotFoundException
import androidx.appfunctions.AppFunctionInvalidArgumentException
import androidx.appfunctions.service.AppFunction
import javax.inject.Inject
...
// Developers can provide additional parameters in the constructor if needed.
// This requires a custom factory setup in the next step.
class TaskFunctions @Inject constructor(
private val taskRepository: TaskRepository
) {
/** The parameter to create the task. */
@AppFunctionSerializable(isDescribedByKDoc = true)
data class CreateTaskParams(
/** The title of the task. */
val title: String,
/** The content of the task. */
val content: String
)
/** The user-created task. */
@AppFunctionSerializable(isDescribedByKDoc = true)
data class Task(
/** The ID of the task. */
val id: String,
/** The title of the task. */
val title: String,
/** The content of the task. */
val content: String
)
/**
* Creates a task based on [createTaskParams].
*
* @param createTaskParams The parameter to describe how to create the task.
*/
@AppFunction(isDescribedByKDoc = true)
suspend fun createTask(
appFunctionContext: AppFunctionContext,
createTaskParams: CreateTaskParams,
): Task = withContext(Dispatchers.IO) {
// Developers can use predefined exceptions to let the agent know
// why it failed.
if (createTaskParams.title == null && createTaskParams.content == null) {
throw AppFunctionInvalidArgumentException("Title or content should be non-null")
}
val id = taskRepository.createTask(
createTaskParams.title,
createTaskParams.content)
return taskRepository
.getTask(id)
?.toTask()
?: throw AppFunctionElementNotFoundException("Task not found for ID = $id")
}
// Maps internal TaskEntity
private fun TaskEntity.toTask() = Task(id = id, title = title, content = description)
}
Poin penting tentang kode
- Secara default, implementasi AppFunction berjalan di UI thread Android.
Oleh karena itu, operasi yang berjalan lama harus melakukan hal berikut:
- Mendeklarasikan AppFunction sebagai fungsi penangguhan.
- Beralih ke coroutine dispatcher yang sesuai saat operasi dapat memblokir thread.
- Jika
isDescribedByKDocditetapkan ketrue, deskripsi fungsi atau deskripsi yang dapat diserialisasi akan dienkode sebagai bagian dariAppFunctionMetadatauntuk membantu agen memahami cara menggunakan AppFunction aplikasi.
Opsional: Menggunakan Hilt untuk menyediakan factory AppFunction kustom
Jika class implementasi AppFunction Anda memerlukan dependensi dalam konstruktornya (seperti dalam TaskRepository pada contoh sebelumnya), Anda harus menyediakan factory kustom agar sistem mengetahui cara membuat instance-nya. Langkah ini bersifat opsional dan hanya diperlukan jika class fungsi Anda memiliki parameter konstruktor. Contoh ini menunjukkan cara membuat AppFunctionFactory kustom dan mengonfigurasinya dalam class Application Anda, menggunakan Hilt untuk injeksi dependensi.
import android.app.Application
import androidx.appfunctions.service.AppFunctionConfiguration
import com.example.android.appfunctions.TaskFunctions
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
@HiltAndroidApp
class TodoApplication : Application(), AppFunctionConfiguration.Provider {
@Inject lateinit var taskFunctions: TaskFunctions
override fun onCreate() {
super.onCreate()
}
// This shows how AppFunctions works with Hilt.
override val appFunctionConfiguration: AppFunctionConfiguration
get() =
AppFunctionConfiguration.Builder()
.addEnclosingClassFactory(TaskFunctions::class.java) { taskFunctions }
.build()
}
Opsional: Mengalihkan ketersediaan AppFunction saat runtime
Gunakan AppFunctionManager API untuk mengaktifkan atau menonaktifkan fungsi secara eksplisit saat membatasi AppFunctions Anda. Pembatasan dapat berguna jika fitur tertentu dari aplikasi Anda tidak tersedia untuk semua pengguna. Dengan mengaktifkan atau menonaktifkan AppFunctions secara dinamis, sistem kecerdasan akan mengetahui fitur mana yang tersedia untuk pengguna Anda pada waktu tertentu.
Untuk membatasi AppFunctions yang memerlukan status akun tertentu dengan aman, ikuti proses dua langkah berikut:
Langkah 1. Menonaktifkan fungsi secara default
Untuk mencegah fungsi dapat diakses sebelum flag fitur Anda diverifikasi, tetapkan parameter isEnabled anotasi @AppFunction ke false.
@AppFunction(isEnabled = false, isDescribedByKDoc = true)
suspend fun createTask(...) { ... }
Langkah 2. Mengaktifkan fungsi secara dinamis saat runtime
Untuk setiap class AppFunction, compiler akan menghasilkan class yang sesuai yang berisi konstanta ID fungsi (menggunakan akhiran Ids). Anda dapat menggunakan konstanta ID yang dihasilkan ini bersama dengan metode setAppFunctionEnabled dari AppFunctionManagerCompat untuk mengubah status aktif fungsi saat runtime.
import androidx.appfunctions.AppFunctionManager
// Assuming there is a hook API to observe user state or feature flags
suspend fun onFeatureEnabled() {
try {
AppFunctionManager.getInstance(context)
.setAppFunctionEnabled(
// Function ID is generated for developer to get
TaskFunctionsIds.CREATE_TASK_ID,
AppFunctionManagerCompat.APP_FUNCTION_STATE_ENABLED,
)
} catch (e: Exception) {
// Handle exception: AppFunctions indexation may not be fully completed
// upon initial app startup.
}
}
suspend fun onFeatureDisabled() {
AppFunctionManagerCompat.getInstance(context)
.setAppFunctionEnabled(
TaskFunctionsIds.CREATE_TASK_ID,
AppFunctionManagerCompat.APP_FUNCTION_STATE_DISABLED,
)
}
Pertimbangan jenis fungsi yang akan disediakan
Keamanan selalu menjadi yang terpenting. Saat memilih kemampuan aplikasi yang akan disediakan sebagai AppFunctions, penting untuk diingat bahwa agen sistem dapat memproses kueri pengguna di server untuk memanfaatkan kemampuan LLM lanjutan.
Untuk memberikan pengalaman pengguna yang baik dan juga menghindari pengungkapan informasi sensitif, sebaiknya ikuti panduan berikut:
- Fungsi yang memanfaatkan bahasa alami: Sediakan tugas yang lebih mudah diungkapkan pengguna dalam percakapan daripada melalui UI manual navigasi.
- Akses terbatas: Buat AppFunctions yang hanya memberikan akses agen ke data dan tindakan yang diperlukan untuk memenuhi permintaan spesifik pengguna.
- Informasi non-sensitif: Hanya bagikan data yang tidak bersifat sangat pribadi atau rahasia, atau data yang secara eksplisit disetujui pengguna untuk dibagikan dalam konteks tindakan.
- Konfirmasi yang jelas untuk tindakan destruktif apa pun: Berhati-hatilah dengan fungsi yang melakukan tindakan destruktif (seperti menghapus data). Meskipun agen dapat memanggilnya, aplikasi Anda harus menyertakan langkah konfirmasi sendiri dan menggunakan bahasa yang jelas dan tidak ambigu tentang maksudnya. Sebaiknya tambahkan lebih dari satu langkah konfirmasi untuk benar-benar memastikan bahwa pengguna mengetahui apa yang diminta untuk dilakukan.
Memverifikasi integrasi AppFunction
Untuk memverifikasi apakah Anda telah mengintegrasikan AppFunctions dengan benar, Anda dapat menggunakan adb
shell cmd app_function.
Gunakan adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName untuk melihat detail AppFunctions yang disediakan aplikasi Anda.
Di Gemini di Android Studio, atau agen lain pilihan Anda, berikan perintah seperti berikut.
Execute `adb shell cmd app_function` to learn how the tool works, then act as a
chat agent aiming to invoke AppFunctions to fulfil user prompts for this app.
Rely on the AppFunction description as instructions.