افزودن «میانای برنامه‌سازی کاربردی AppFunctions» به برنامه

این راهنما توضیح می‌دهد که چگونه AppFunctions API را در برنامه Android خود ادغام کنید، منطق یک تابع را پیاده‌سازی کنید، و تأیید کنید که ادغام به‌درستی کار می‌کند.

سازگاری نسخه

این پیاده‌سازی مستلزم این است که پروژه شما compileSdk روی سطح میانای برنامه‌سازی کاربردی ۳۶ یا بالاتر تنظیم شود.

برنامه شما ملزم به درستی‌سنجی پشتیبانی از «کارکردهای برنامه» نیست؛ این کار به‌طور خودکار در کتابخانه AppFunctions Jetpack انجام می‌شود. AppFunctionManager اگر از ویژگی پشتیبانی شود نمونه‌ای برمی‌گرداند، و اگر پشتیبانی نشود مقدار null برمی‌گرداند.

وابستگی‌ها

وابستگی‌های کتابخانه موردنیاز را به فایل build.gradle.kts (یا build.gradle) واحدتان اضافه کنید و افزایه KSP را در واحد برنامه سطح بالای خودتان همان‌طور که نشان داده شده است پیکربندی کنید:

dependencies {
  implementation("androidx.appfunctions:appfunctions:1.0.0-alpha10")
  // 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-alpha10")
}

پیاده‌سازی منطق AppFunctions

برای پیاده‌سازی AppFunction برای برنامه Android، کلاسی ایجاد کنید که منطق AppFunctions خاص را پیاده‌سازی کند. این کار شامل ایجاد کلاس‌های داده سریال‌شدنی برای پارامترها و پاسخ‌ها، و سپس ارائه منطق اصلی در روش تابع است.

کد زیر نمونه‌ای از پیاده‌سازی برای ایجاد تکلیف در برنامه «کارها» را نشان می‌دهد، ازجمله تعریف پارامترهای سفارشی و انواع پاسخ و منطق تابع اصلی بااستفاده از مخزن.

@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.
     */
    @AppFunction(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 در رشته واسط کاربری Android اجرا می‌شود. بنابراین، یک عملیات طولانی‌مدت باید موارد زیر را انجام دهد:
    • ‫AppFunction را به‌عنوان تابع تعلیق‌کننده اعلام کنید.
    • وقتی عملیات می‌تواند رشته را مسدود کند، به توزیع‌کننده روتین همکار مناسبی بروید.
  • وقتی isDescribedByKDoc روی true تنظیم می‌شود، شرح تابع یا شرح سریال‌پذیر به‌عنوان بخشی از AppFunctionMetadata کدبندی می‌شود تا به عامل کمک کند نحوه استفاده از AppFunction برنامه را درک کند.

سرویس 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 را در زمان اجرا تغییر دهید

از AppFunctionManager API برای فعال یا غیرفعال کردن صریح عملکردها هنگام دروازه‌بانی AppFunctions استفاده کنید. درب ورودی می‌تواند زمانی مفید باشد که ویژگی‌های خاصی از برنامه شما برای همه کاربران دردسترس نباشد. با فعال یا غیرفعال کردن پویای AppFunctions، سیستم هوشمند دقیقاً می‌داند که در هر زمان معین کدام ویژگی‌ها برای کاربر شما دردسترس است.

برای دروازه‌بانی ایمن «توابع برنامه» که به وضعیت حساب خاصی نیاز دارند، فرایندی دو مرحله‌ای را دنبال کنید:

مرحله ۱. انتخاب تابع به‌عنوان پیش‌فرض غیرفعال

برای جلوگیری از دسترسی به تابع قبل‌از تأیید پرچم ویژگی، پارامتر isEnabled گزارش @AppFunction را روی false تنظیم کنید.

@AppFunction(isEnabled = false, isDescribedByKDoc = true)
suspend fun createTask(
    createTaskParams: CreateTaskParams,
): Task = TODO()

مرحله ۲. فعال کردن پویا تابع در زمان اجرا

برای هر کلاس AppFunction، کامپایلر کلاس متناظری تولید می‌کند که حاوی ثابت‌های شناسه تابع است (بااستفاده از پسوند Ids). می‌توانید از این ثابت‌های شناسه تولیدشده درکنار روش setAppFunctionEnabled از AppFunctionManagerCompat برای تغییر وضعیت فعال یک تابع در زمان اجرا استفاده کنید.

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
    }
}

ملاحظات مربوط به انواع کارکردهایی که باید دردسترس قرار گیرد

امنیت همیشه در اولویت است. وقتی درحال انتخاب قابلیت‌های برنامه‌تان برای دردسترس قرار دادن به‌عنوان «عملکردهای برنامه» هستید، باید به‌یاد داشته باشید که کارگزاران سیستم ممکن است پُرسمان‌های کاربر را در سرور پردازش کنند تا از قابلیت‌های پیشرفته LLM بهره ببرند.

برای ارائه تجربه کاربری عالی که از افشای اطلاعات حساس نیز جلوگیری کند، توصیه می‌کنیم این دستورالعمل‌ها را دنبال کنید:

  • عملکردی که از زبان طبیعی بهره می‌برد: وظایفی را دردسترس قرار دهید که کاربر بتواند آن‌ها را در مکالمه آسان‌تر از پیمایش دستی در واسط کاربر بیان کند.
  • دسترسی محدود: «توابع برنامه» ایجاد کنید که فقط به عامل اجازه دسترسی به داده‌ها و کنش‌هایی را بدهد که برای برآورده کردن درخواست ویژه کاربر لازم است.
  • اطلاعات غیرحساس: فقط داده‌هایی را هم‌رسانی کنید که بسیار شخصی یا محرمانه نباشد، یا داده‌هایی که کاربر صریحاً با هم‌رسانی آن‌ها در زمینه کنش موافقت می‌کند.
  • تأیید صریح برای هرگونه کنش مخرب: درخصوص عملکردهایی که کنش‌های مخرب انجام می‌دهند (مثل حذف داده‌ها) بسیار محتاط باشید. اگرچه نماینده ممکن است آن‌ها را فرا بخواند، برنامه شما باید شامل مرحله تأیید خود باشد و از زبان واضح و بدون ابهامی درباره اهداف استفاده کند. همچنین افزودن بیش از یک مرحله تأیید برای اطمینان از اینکه کاربر از آنچه از او خواسته می‌شود آگاه است مفید است.

یکپارچه‌سازی AppFunction را درستی‌سنجی کنید

برای تأیید اینکه آیا «کارکردهای برنامه» را به‌درستی ادغام کرده‌اید، می‌توانید از adb shell cmd app_function استفاده کنید.

از adb shell cmd app_function list-app-functions | grep --after-context 10 $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 را در دستگاهتان نصب و اجرا کنید.

اگر یکپارچه‌سازی‌تان را بااستفاده از دستیارهای گپ‌محور مثل 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.
Rely on the AppFunction description as instructions.

انتقال از نسخه‌های پایین‌تر میانای برنامه‌سازی کاربردی

در نسخه 1.0.0-alpha10،‏ AppFunctions معماری زمان ترجمه @AppFunctionServiceEntryPoint را معرفی کرد که وابستگی‌های کتابخانه را ادغام می‌کند و ارائه‌دهندگان پیکربندی قدیمی (AppFunctionConfiguration.Provider) را جایگزین می‌کند.

اگر برنامه شما درحال‌حاضر از نسخه قدیمی‌تری از AppFunctions (مثل 1.0.0-alpha09) استفاده می‌کند، می‌توانید بااستفاده از مهارت عامل AppFunctions در یک IDE هوش مصنوعی مثل Gemini در Android Studio، انتقال را خودکارسازی کنید. مهارت حاوی قوانین انتقال اختصاصی است که نماینده را برای ادغام وابستگی‌های ساخت شما، ایجاد پوشش سرویس @AppFunctionServiceEntryPoint موردنیاز، جدا کردن پارامترهای زمینه، و به‌روزرسانی اظهارنامه‌های مانیفست شما راهنمایی می‌کند.