במדריך הזה מוסבר איך לשלב את AppFunctions API באפליקציה ל-Android, להטמיע את הלוגיקה של פונקציה ולוודא שהשילוב פועל בצורה תקינה.
תאימות בין גרסאות
כדי להטמיע את התכונה הזו, צריך להגדיר את הפרויקט compileSdk לרמת API 37 ומעלה. בפרויקט צריך להשתמש בפלאגין של Android Gradle מגרסה 9.1.0 ואילך.
האפליקציה לא צריכה לבדוק אם יש תמיכה ב-AppFunctions. זה קורה באופן אוטומטי בספריית Jetpack של AppFunctions.
הפונקציה AppFunctionManager מחזירה מופע אם התכונה נתמכת, ומחזירה ערך null אם לא.
פניות קשורות
מוסיפים את יחסי התלות הנדרשים של הספרייה לקובץ build.gradle.kts (או build.gradle) של המודול, ומגדירים את הפלאגין של KSP במודול האפליקציה ברמה העליונה, כמו שמוצג כאן:
dependencies {
implementation("androidx.appfunctions:appfunctions:1.0.0-beta01")
// 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-beta01")
}
הטמעת הלוגיקה של AppFunctions
כדי להטמיע AppFunction באפליקציה ל-Android, צריך ליצור מחלקה שמטמיעה את הלוגיקה הספציפית של AppFunctions. כדי לעשות את זה, צריך ליצור מחלקות נתונים שניתנות לסריאליזציה בשביל הפרמטרים והתשובות, ואז לספק את הלוגיקה העיקרית בתוך ה-method של הפונקציה.
הקוד הבא מציג דוגמה להטמעה של יצירת משימה באפליקציית TODO, כולל הגדרת פרמטרים מותאמים אישית וסוגי תגובות, והלוגיקה של הפונקציה הראשית באמצעות מאגר.
@RequiresApi(36) @AndroidEntryPoint @AppFunctionServiceEntryPoint( serviceName = "TaskAppFunctionService", appFunctionXmlFileName = "task_app_function_service", ) abstract class BaseTaskAppFunctionService : AppFunctionService() { @Inject internal lateinit var taskRepository: TaskRepository /** * Creates a task based on [createTaskParams]. * * @param createTaskParams The parameter to describe how to create the task. */ @AppFunctionDeclaration(isDescribedByKDoc = true) suspend fun createTask( 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@withContext 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) }
מידע חשוב על הקוד
- כברירת מחדל, הטמעה של AppFunction פועלת בשרשור UI של Android.
לכן, פעולה ממושכת צריכה לבצע את הפעולות הבאות:
- מצהירים על AppFunction כפונקציית השעיה.
- עוברים למשלח קורוטינה מתאים כשהפעולה עלולה לחסום את השרשור.
- כשהערך של
isDescribedByKDocמוגדר כ-true, תיאור הפונקציה או התיאור שניתן לסריאליזציה מקודד כחלק מ-AppFunctionMetadataכדי לעזור לסוכן להבין איך להשתמש ב-AppFunction של האפליקציה. החל מגרסה 1.0.0-beta01, אין ערך ברירת מחדל ל-isDescribedByKDoc, לכן צריך להגדיר אותו באופן מפורש.
הצהרה על שירות AppFunction במניפסט
רושמים את הצהרת השירות שנוצרה על ידי KSP ואת המאפיין app_metadata במניפסט של המודול, למשל ב-src/main/AndroidManifest.xml. הקומפיילר של KSP יוצר את מחלקת השירות הקונקרטית (TaskAppFunctionService) שמרחיבה את מחלקת נקודת הכניסה המופשטת, יחד עם סכימת ה-XML התואמת בספרייה assets/.
<service android:name="com.example.snippets.ai.TaskAppFunctionService" android:permission="android.permission.BIND_APP_FUNCTION_SERVICE" android:exported="true" tools:targetApi="36"> <property android:name="android.app.appfunctions.schema" android:value="app_functions_schema.xsd" /> <property android:name="android.app.appfunctions.v2" android:value="task_app_function_service.xml" /> <intent-filter> <action android:name="android.app.appfunctions.AppFunctionService" /> </intent-filter> </service> <property android:name="android.app.appfunctions.app_metadata" android:resource="@xml/app_metadata" />
אופציונלי: הפעלה או השבתה של הזמינות של AppFunction בזמן הריצה
כדי להפעיל או להשבית פונקציות באופן מפורש כשאתם מגבילים את הגישה ל-AppFunctions, השתמשו ב-API של AppFunctionManager. הגבלת הגישה יכולה להיות שימושית כשחלק מהתכונות באפליקציה לא זמינות לכל המשתמשים. הפעלה או השבתה דינמית של AppFunctions מאפשרת למערכת החכמה לדעת בדיוק אילו תכונות זמינות למשתמש בכל זמן נתון.
כדי להגביל בצורה בטוחה את הגישה לפונקציות AppFunctions שדורשות מצב חשבון ספציפי, צריך לבצע תהליך דו-שלבי:
שלב 1. הפונקציה מושבתת כברירת מחדל
כדי למנוע גישה לפונקציה לפני אימות ה-feature flag, מגדירים את הפרמטר isEnabled של ההערה @AppFunctionDeclaration לערך false.
@AppFunctionDeclaration(isEnabled = false, isDescribedByKDoc = true) suspend fun createTask( createTaskParams: CreateTaskParams, ): Task = TODO()
שלב 2. הפעלה דינמית של הפונקציה בזמן הריצה
לכל מחלקה של @AppFunctionServiceEntryPoint, המקמפל יוצר מחלקה תואמת שמכילה קבועים של מזהי פונקציות (באמצעות הסיומת Ids).
אתם יכולים להשתמש בקבועי המזהים שנוצרו לצד ה-method setAppFunctionEnabled מ-AppFunctionManager כדי לשנות את מצב ההפעלה של פונקציה בזמן הריצה.
suspend fun onFeatureEnabled(context: Context) { try { AppFunctionManager.getInstance(context) ?.setAppFunctionEnabled( BaseTaskAppFunctionServiceIds.CREATE_TASK_ID, AppFunctionManager.APP_FUNCTION_STATE_ENABLED, ) } catch (e: Exception) { // Handle exception: AppFunctions indexation may not be fully completed // upon initial app startup. } } suspend fun onFeatureDisabled(context: Context) { try { AppFunctionManager.getInstance(context) ?.setAppFunctionEnabled( BaseTaskAppFunctionServiceIds.CREATE_TASK_ID, AppFunctionManager.APP_FUNCTION_STATE_DISABLED, ) } catch (e: Exception) { // Handle exception } }
שיקולים לגבי סוגי הפונקציות שרוצים להציע
האבטחה תמיד נמצאת בראש סדר העדיפויות. כשאתם בוחרים אילו יכולות של האפליקציה יהיו זמינות כ-AppFunctions, חשוב לזכור שסוכני המערכת עשויים לעבד שאילתות של משתמשים בשרת כדי לנצל את היכולות המתקדמות של מודל ה-LLM.
כדי לספק חוויית משתמש מעולה וגם להימנע מחשיפת מידע רגיש, מומלץ לפעול לפי ההנחיות הבאות:
- פונקציונליות שמתאימה לשפה טבעית: כדאי להציע משימות שקל יותר למשתמשים לבטא בשיחה מאשר באמצעות ניווט ידני בממשק המשתמש.
- גישה מצומצמת: יוצרים פונקציות AppFunctions שנותנות לסוכן גישה רק לנתונים ולפעולות שנדרשים כדי למלא את הבקשה הספציפית של המשתמש.
- מידע לא רגיש: מותר לשתף רק נתונים שהם לא אישיים או סודיים, או נתונים שהמשתמש הסכים במפורש לשתף בהקשר של הפעולה.
- אישור חד-משמעי לכל פעולה הרסנית: צריך להיזהר מאוד עם פונקציות שמבצעות פעולות הרסניות (כמו מחיקת נתונים). למרות שהסוכן עשוי להפעיל אותן, האפליקציה צריכה לכלול שלב אישור משלה ולהשתמש בשפה ברורה וחד-משמעית לגבי הכוונות. כדאי גם להוסיף יותר משלב אישור אחד כדי לוודא שהמשתמש מודע למה שהוא מתבקש לעשות.
אימות השילוב של AppFunction
כדי לבדוק אם שילבתם את AppFunctions בצורה נכונה, אתם יכולים להשתמש ב-adb
shell cmd app_function.
אפשר להשתמש ב-adb shell cmd app_function list-app-functions --package $myPackageName כדי לראות פרטים על הפונקציות שהאפליקציה מספקת.
אפשר גם להריץ AppFunction ישירות משורת הפקודה באמצעות המזהה המפורש שלה ("$enclosingClassName#$methodName"):
adb shell "cmd app_function execute-app-function \
--package com.example.android.appfunctions \
--function 'com.example.android.appfunctions.BaseTaskAppFunctionService#createTask' \
--parameters '{\"createTaskParams\": {\"title\": \"Buy milk\", \"content\": \"From grocery store\"}}'"
כדי לראות את Android MCP בפעולה ולבדוק תהליכי עבודה מקצה לקצה בלי להזין הנחיות, התקינו והפעילו במכשיר את אפליקציית Android AppFunctions testing agent.
אם אתם מאמתים את השילוב באמצעות עוזרים דיגיטליים מבוססי-צ'אט כמו Gemini ב-Android Studio, אתם יכולים להשתמש במיומנות הפיתוח של AppFunctions או לספק הנחיה כמו:
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.
Use the AppFunction descriptions to choose functions and parameters.
מעבר מגרסאות API ישנות יותר
בגרסה 1.0.0-alpha10, הוספנו ל-AppFunctions ארכיטקטורה של @AppFunctionServiceEntryPoint בזמן הידור, שמאחדת את יחסי התלות של הספרייה ומחליפה את ספקי ההגדרות הקודמים (AppFunctionConfiguration.Provider). בגרסה 1.0.0-alpha12 הסרנו את הספקים הקודמים. בגרסה 1.0.0-alpha13, השם של ההערה @AppFunction שונה ל-@AppFunctionDeclaration, ובגרסה 1.0.0-beta01, השם של המאפיין appfn:description בקובץ ה-XML של המטא-נתונים של האפליקציה שונה ל-appfn:instructions.
אם האפליקציה שלכם משתמשת בגרסה קודמת של AppFunctions (כמו 1.0.0-alpha09 או 1.0.0-alpha10), אתם יכולים להעביר אותה באופן אוטומטי באמצעות מיומנות הסוכן של AppFunctions ב-IDE עם AI כמו Gemini ב-Android Studio. היכולת מכילה כללי העברה ייעודיים שמנחים את הנציג לאחד את יחסי התלות של ה-build, ליצור את מעטפת השירות הנדרשת של @AppFunctionServiceEntryPoint, להפריד בין פרמטרים של הקשר, לעדכן את הצהרות המניפסט ולהחיל את שינויי השמות של 1.0.0-beta01.
מיומנויות ב-Android
הצגת הקוד ב-GitHubהטמעת AppFunctions
android skills add appfunctionsUse the AppFunctions skill to upgrade my app's AppFunctions implementation to 1.0.0-beta01.