إضافة واجهة برمجة التطبيقات AppFunctions إلى تطبيقك

يوضّح هذا الدليل كيفية دمج AppFunctions API في تطبيق Android، وتنفيذ منطق إحدى الدوال، والتأكّد من أنّ عملية الدمج تعمل بشكل صحيح.

التوافق مع الإصدارات

يتطلّب هذا التنفيذ ضبط مشروعك compileSdk على مستوى واجهة برمجة التطبيقات 36 أو مستوى أحدث.

ليس مطلوبًا من تطبيقك التحقّق مما إذا كانت AppFunctions متوافقة، إذ يتم التعامل مع ذلك تلقائيًا ضمن مكتبة AppFunctions Jetpack. تعرض الدالة AppFunctionManager مثيلاً إذا كانت الميزة متاحة، وتعرض قيمة فارغة إذا لم تكن متاحة.

الطلبات التابعة

أضِف الاعتمادات المطلوبة للمكتبة إلى ملف 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 لتفعيل الوظائف أو إيقافها بشكل صريح عند حظر AppFunctions. يمكن أن يكون حظر الوصول مفيدًا عندما لا تتوفّر ميزات معيّنة في تطبيقك لجميع المستخدمين. من خلال تفعيل AppFunctions أو إيقافها بشكل ديناميكي، يعرف نظام الذكاء الاصطناعي الميزات المتاحة للمستخدم في أي وقت.

لإجراء عملية التحقّق من حالة الحساب بشكل آمن في AppFunctions التي تتطلّب حالة حساب معيّنة، اتّبِع الخطوتَين التاليتَين:

الخطوة 1: إيقاف الوظيفة تلقائيًا

لمنع إمكانية الوصول إلى الدالة قبل إثبات صحة علامة الميزة، اضبط المَعلمة isEnabled في التعليق التوضيحي @AppFunction على false.

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

الخطوة 2: تفعيل الدالة ديناميكيًا في وقت التشغيل

بالنسبة إلى كل فئة 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
    }
}

اعتبارات أنواع الوظائف التي يجب إتاحتها

الأمان هو الأهم دائمًا. عند اختيار إمكانات تطبيقك التي تريد إتاحتها كوظائف AppFunctions، من المهم تذكُّر أنّ وكلاء النظام قد يعالجون طلبات المستخدمين على الخادم للاستفادة من إمكانات نماذج اللغات الكبيرة المتقدّمة.

لتقديم تجربة مستخدم رائعة وتجنُّب الكشف عن معلومات حساسة، ننصحك باتّباع الإرشادات التالية:

  • الوظائف التي تستفيد من اللغة الطبيعية: يمكنك إتاحة المهام التي يسهل على المستخدم التعبير عنها في المحادثة أكثر من التنقّل اليدوي في واجهة المستخدم.
  • الوصول المحدود: أنشئ AppFunctions تمنح الوكيل إذن الوصول فقط إلى البيانات والإجراءات المطلوبة لتنفيذ طلب المستخدم المحدّد.
  • المعلومات غير الحسّاسة: يجب مشاركة البيانات التي لا تتضمّن معلومات شخصية أو سرية للغاية، أو البيانات التي يوافق المستخدم صراحةً على مشاركتها في سياق الإجراء.
  • تأكيد واضح لأي إجراء مدمِّر: يجب توخّي الحذر الشديد عند استخدام الوظائف التي تنفّذ إجراءات مدمِّرة (مثل حذف البيانات). وعلى الرغم من أنّ الوكيل قد يستدعي هذه الميزات، يجب أن يتضمّن تطبيقك خطوة تأكيد خاصة به وأن يستخدم لغة واضحة لا لبس فيها بشأن النوايا. من المفيد أيضًا إضافة أكثر من خطوة تأكيد واحدة لضمان أن يكون المستخدم على دراية بما يُطلب منه فعله.

التحقّق من عملية دمج AppFunction

للتأكّد من أنّك قد دمجت AppFunctions بشكل صحيح، يمكنك استخدام adb shell cmd app_function.

استخدِم adb shell cmd app_function list-app-functions | grep --after-context 10 $myPackageName للاطّلاع على تفاصيل AppFunctions التي يوفّرها تطبيقك.

يمكنك أيضًا تنفيذ 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\"}}'"

لتجربة ميزة &quot;التحكّم في الأجهزة الجوّالة من Android&quot; والتحقّق من سير العمل المتكامل بدون الحاجة إلى أي طلبات، ثبِّت تطبيق وكيل اختبار AppFunctions على جهاز Android وشغِّله.

إذا كنت بصدد إثبات صحة عملية الدمج باستخدام مساعدين مستندين إلى المحادثة، مثل &quot;Gemini في استوديو Android&quot;، استخدِم مهارة تطوير 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". تتضمّن الأداة قواعد نقل بيانات مخصّصة ترشد الوكيل إلى دمج تبعيات الإصدار وإنشاء برنامج تضمين خدمة @AppFunctionServiceEntryPoint المطلوب وفصل مَعلمات السياق وتعديل بيانات ملف البيان.

لبدء عملية نقل بيانات مبرمَجة باستخدام وكيل الذكاء الاصطناعي، استخدِم طلبًا مثل ما يلي:

Use the AppFunctions migration skill to upgrade my app's AppFunctions implementation from 1.0.0-alpha09 to the 1.0.0-alpha10 @AppFunctionServiceEntryPoint architecture.