আপনার অ্যাপে AppFunctions API যোগ করুন

এই নির্দেশিকায় ব্যাখ্যা করা হয়েছে কীভাবে আপনার অ্যান্ড্রয়েড অ্যাপে AppFunctions API একীভূত করবেন, একটি ফাংশনের লজিক প্রয়োগ করবেন এবং একীকরণটি সঠিকভাবে কাজ করছে কিনা তা যাচাই করবেন।

সংস্করণ সামঞ্জস্যতা

এই বাস্তবায়নের জন্য আপনার প্রজেক্টের compileSdk অবশ্যই এপিআই লেভেল ৩৬ বা তার বেশিতে সেট করতে হবে।

আপনার অ্যাপে AppFunctions সমর্থিত কিনা তা যাচাই করার প্রয়োজন নেই; এটি 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")
}

অ্যাপফাংশন লজিক বাস্তবায়ন করুন

আপনার অ্যান্ড্রয়েড অ্যাপের জন্য একটি AppFunction প্রয়োগ করতে, এমন একটি ক্লাস তৈরি করুন যা নির্দিষ্ট AppFunction-এর লজিক বাস্তবায়ন করে। এর জন্য প্যারামিটার এবং রেসপন্সের জন্য সিরিয়ালাইজেবল ডেটা ক্লাস তৈরি করতে হয় এবং তারপর ফাংশন মেথডের মধ্যে মূল লজিকটি প্রদান করতে হয়।

নিম্নলিখিত কোডটিতে 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.
     */
    @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 ইমপ্লিমেন্টেশন অ্যান্ড্রয়েড UI থ্রেডে চলে। তাই, একটি দীর্ঘ সময় ধরে চলা অপারেশনের নিম্নলিখিত কাজগুলো করা উচিত:
    • AppFunction-টিকে একটি সাসপেন্ড ফাংশন হিসেবে ঘোষণা করুন।
    • যখন অপারেশনটি থ্রেডকে ব্লক করতে পারে, তখন একটি উপযুক্ত কো-রুটিন ডিসপ্যাচারে স্যুইচ করুন।
  • যখন isDescribedByKDoc মান true সেট করা থাকে, তখন ফাংশনের বিবরণ অথবা সিরিয়ালাইজেবল বিবরণটি AppFunctionMetadata এর অংশ হিসেবে এনকোড করা হয়, যা এজেন্টকে অ্যাপের AppFunction-টি কীভাবে ব্যবহার করতে হবে তা বুঝতে সাহায্য করে।

আপনার ম্যানিফেস্টে AppFunction সার্ভিসটি ঘোষণা করুন।

আপনার মডিউল ম্যানিফেস্টের মধ্যে, উদাহরণস্বরূপ, src/main/AndroidManifest.xml এ KSP দ্বারা তৈরি সার্ভিস ডিক্লারেশন এবং app_metadata প্রপার্টিটি রেজিস্টার করুন। KSP কম্পাইলার আপনার assets/ ডিরেক্টরিতে সংশ্লিষ্ট XML স্কিমাসহ আপনার অ্যাবস্ট্রাক্ট এন্ট্রি পয়েন্ট ক্লাসকে এক্সটেন্ড করে কনক্রিট সার্ভিস ক্লাস ( TaskAppFunctionService ) তৈরি করে।

<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 ব্যবহার করুন। যখন আপনার অ্যাপের নির্দিষ্ট কিছু ফিচার সকল ব্যবহারকারীর জন্য উপলব্ধ থাকে না, তখন গেটিং কার্যকর হতে পারে। AppFunction-গুলোকে ডায়নামিকভাবে সক্রিয় বা নিষ্ক্রিয় করার মাধ্যমে, ইন্টেলিজেন্স সিস্টেমটি যেকোনো নির্দিষ্ট সময়ে আপনার ব্যবহারকারীর জন্য ঠিক কোন ফিচারগুলো উপলব্ধ আছে তা জানতে পারে।

যেসব অ্যাপফাংশনের জন্য একটি নির্দিষ্ট অ্যাকাউন্ট স্টেট প্রয়োজন, সেগুলোকে নিরাপদে গেট করার জন্য দুটি ধাপের একটি প্রক্রিয়া অনুসরণ করুন:

ধাপ ১. ফাংশনটি ডিফল্টরূপে নিষ্ক্রিয় করুন।

আপনার ফিচার ফ্ল্যাগ যাচাই হওয়ার আগে ফাংশনটি যাতে অ্যাক্সেসযোগ্য না হয়, সেজন্য আপনার @AppFunction অ্যানোটেশনের isEnabled প্যারামিটারটি false এ সেট করুন।

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

ধাপ ২. রানটাইমে ফাংশনটি ডায়নামিকভাবে সক্রিয় করুন।

প্রতিটি AppFunction ক্লাসের জন্য, কম্পাইলার একটি সংশ্লিষ্ট ক্লাস তৈরি করে যাতে ফাংশন আইডি কনস্ট্যান্ট ( Ids সাফিক্স ব্যবহার করে) থাকে। রানটাইমে কোনো ফাংশনের এনাবলড অবস্থা পরিবর্তন করার জন্য আপনি AppFunctionManagerCompat এর setAppFunctionEnabled মেথডের পাশাপাশি এই তৈরি হওয়া আইডি কনস্ট্যান্টগুলো ব্যবহার করতে পারেন।

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

উপলব্ধ করার জন্য কার্যকারিতার প্রকারভেদ বিবেচনা

নিরাপত্তাই সর্বাগ্রে। আপনার অ্যাপের কোন সক্ষমতাগুলোকে AppFunction হিসেবে উপলব্ধ করবেন তা নির্বাচন করার সময়, এটা মনে রাখা গুরুত্বপূর্ণ যে সিস্টেম এজেন্টরা উন্নত LLM সক্ষমতা কাজে লাগানোর জন্য সার্ভারে ব্যবহারকারীর কোয়েরিগুলো প্রসেস করতে পারে।

সংবেদনশীল তথ্য প্রকাশ এড়ানোর পাশাপাশি একটি চমৎকার ব্যবহারকারী অভিজ্ঞতা প্রদানের জন্য, আমরা নিম্নলিখিত নির্দেশিকাগুলো অনুসরণ করার পরামর্শ দিই:

  • স্বাভাবিক ভাষা ব্যবহার করে সুবিধা নেওয়া যায় এমন কার্যকারিতা : এমন সব কাজ উপলব্ধ করুন যা ব্যবহারকারী ম্যানুয়াল UI নেভিগেশনের চেয়ে কথোপকথনের মাধ্যমে সহজে প্রকাশ করতে পারে।
  • অ্যাক্সেস সীমিত করুন : এমন অ্যাপফাংশন তৈরি করুন যা এজেন্টকে শুধুমাত্র ব্যবহারকারীর নির্দিষ্ট অনুরোধ পূরণের জন্য প্রয়োজনীয় ডেটা এবং অ্যাকশনগুলিতে অ্যাক্সেস দেবে।
  • অসংবেদনশীল তথ্য : শুধুমাত্র সেই ডেটা শেয়ার করুন যা অত্যন্ত ব্যক্তিগত বা গোপনীয় নয়, অথবা এমন ডেটা যা ব্যবহারকারী নির্দিষ্ট কাজের প্রেক্ষাপটে শেয়ার করার জন্য স্পষ্টভাবে সম্মতি দেন।
  • যেকোনো ধ্বংসাত্মক কাজের জন্য সুস্পষ্ট নিশ্চিতকরণ : যেসব ফাংশন ধ্বংসাত্মক কাজ করে (যেমন ডেটা মুছে ফেলা), সেগুলোর ব্যাপারে অত্যন্ত সতর্ক থাকুন। যদিও এজেন্ট সেগুলোকে কল করতে পারে, আপনার অ্যাপে নিজস্ব একটি নিশ্চিতকরণ ধাপ থাকা উচিত এবং এর উদ্দেশ্য সম্পর্কে স্পষ্ট ও দ্ব্যর্থহীন ভাষা ব্যবহার করা উচিত। ব্যবহারকারীকে কী করতে বলা হচ্ছে সে সম্পর্কে তিনি পুরোপুরি সচেতন কি না, তা নিশ্চিত করার জন্য একাধিক নিশ্চিতকরণ ধাপ যোগ করাও সহায়ক।

অ্যাপফাংশন ইন্টিগ্রেশন যাচাই করুন

আপনি AppFunctions সঠিকভাবে সংহত করেছেন কিনা তা যাচাই করতে, আপনি adb shell cmd app_function ব্যবহার করতে পারেন।

আপনার অ্যাপের দেওয়া AppFunction-গুলোর বিস্তারিত দেখতে adb shell cmd app_function list-app-functions | grep --after-context 10 $myPackageName ব্যবহার করুন।

আপনি এর সুস্পষ্ট শনাক্তকারী ( "$enclosingClassName#$methodName" ) ব্যবহার করে সরাসরি কমান্ড লাইন থেকেও একটি AppFunction চালাতে পারেন:

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\"}}'"

অ্যান্ড্রয়েড এমসিপি-এর কার্যকারিতা সরাসরি অভিজ্ঞতা করতে এবং কোনো প্রম্পট ছাড়াই এন্ড-টু-এন্ড ওয়ার্কফ্লো যাচাই করতে, আপনার ডিভাইসে অ্যাপফাংশনস টেস্টিং এজেন্ট অ্যান্ড্রয়েড অ্যাপটি ইনস্টল ও রান করুন।

আপনি যদি অ্যান্ড্রয়েড স্টুডিওতে জেমিনির মতো চ্যাট-ভিত্তিক অ্যাসিস্ট্যান্ট ব্যবহার করে আপনার ইন্টিগ্রেশন যাচাই করেন, তাহলে 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.

নিম্নতর API সংস্করণ থেকে মাইগ্রেট করুন

সংস্করণ 1.0.0-alpha10-এ, AppFunctions একটি কম্পাইল-টাইম @AppFunctionServiceEntryPoint আর্কিটেকচার চালু করেছে যা লাইব্রেরি নির্ভরতা একত্রিত করে এবং পুরোনো কনফিগারেশন প্রোভাইডার ( AppFunctionConfiguration.Provider ) প্রতিস্থাপন করে।

আপনার অ্যাপ যদি বর্তমানে AppFunctions-এর কোনো পুরোনো সংস্করণ (যেমন 1.0.0-alpha09) ব্যবহার করে থাকে, তাহলে আপনি Android Studio-তে Gemini-র মতো কোনো AI IDE-তে AppFunctions এজেন্ট স্কিল ব্যবহার করে আপনার মাইগ্রেশন স্বয়ংক্রিয় করতে পারেন। এই স্কিলটিতে বিশেষ মাইগ্রেশন নিয়ম রয়েছে যা একটি এজেন্টকে আপনার বিল্ড ডিপেন্ডেন্সি একত্রিত করতে, প্রয়োজনীয় @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.