इस गाइड में बताया गया है कि AppFunctions API को अपने Android ऐप्लिकेशन में कैसे इंटिग्रेट करें, किसी फ़ंक्शन के लिए लॉजिक कैसे लागू करें, और यह कैसे पुष्टि करें कि इंटिग्रेशन सही तरीके से काम कर रहा है.
वर्शन के साथ काम करने की सुविधा
इस सुविधा को लागू करने के लिए, यह ज़रूरी है कि आपका प्रोजेक्ट compileSdk एपीआई लेवल 36 या उसके बाद के लेवल पर सेट हो.
आपके ऐप्लिकेशन को यह पुष्टि करने की ज़रूरत नहीं है कि AppFunctions काम करती हैं या नहीं. यह काम, AppFunctions Jetpack लाइब्रेरी में अपने-आप होता है.
अगर सुविधा काम करती है, तो AppFunctionManager एक इंस्टेंस दिखाता है. अगर सुविधा काम नहीं करती है, तो यह शून्य दिखाता है.
डिपेंडेंसी
अपने मॉड्यूल की build.gradle.kts (या build.gradle) फ़ाइल में, ज़रूरी लाइब्रेरी डिपेंडेंसी जोड़ें. साथ ही, अपने टॉप-लेवल ऐप्लिकेशन मॉड्यूल में KSP प्लगिन को इस तरह कॉन्फ़िगर करें:
# 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")
}
AppFunctions लॉजिक लागू करना
अपने Android ऐप्लिकेशन के लिए AppFunction लागू करने के लिए, एक ऐसी क्लास बनाएं जो AppFunctions के लॉजिक को लागू करती हो. इसमें पैरामीटर और जवाबों के लिए, सीरियलाइज़ किए जा सकने वाले डेटा क्लास बनाना शामिल है. इसके बाद, फ़ंक्शन के तरीके में मुख्य लॉजिक देना शामिल है.
नीचे दिए गए कोड में, TODO ऐप्लिकेशन में टास्क बनाने के लिए, लागू करने का एक उदाहरण दिखाया गया है. इसमें कस्टम पैरामीटर और जवाब के टाइप तय करना और रिपॉज़िटरी का इस्तेमाल करके मुख्य फ़ंक्शन लॉजिक तय करना शामिल है.
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)
}
कोड के बारे में अहम बातें
- डिफ़ॉल्ट रूप से, AppFunction को लागू करने की प्रोसेस, Android यूज़र इंटरफ़ेस (यूआई) थ्रेड में चलती है.
इसलिए, लंबे समय तक चलने वाली कार्रवाई को ये काम करने चाहिए:
- AppFunction को सस्पेंड फ़ंक्शन के तौर पर एलान करें.
- जब ऑपरेशन थ्रेड को ब्लॉक कर सकता है, तब किसी सही कोरूटीन डिस्पैचर पर स्विच करें.
- जब
isDescribedByKDocकोtrueपर सेट किया जाता है, तो फ़ंक्शन के ब्यौरे या सीरियलाइज़ किए जा सकने वाले ब्यौरे कोAppFunctionMetadataके हिस्से के तौर पर कोड में बदला जाता है. इससे एजेंट को यह समझने में मदद मिलती है कि ऐप्लिकेशन के AppFunction का इस्तेमाल कैसे किया जाए.
ज़रूरी नहीं: कस्टम AppFunction फ़ैक्ट्री देने के लिए, Hilt का इस्तेमाल करें
अगर आपकी AppFunction इंप्लीमेंटेशन क्लास को अपने कंस्ट्रक्टर में डिपेंडेंसी की ज़रूरत है (जैसे कि पिछले उदाहरण में TaskRepository), तो आपको एक कस्टम फ़ैक्ट्री देनी होगी, ताकि सिस्टम को पता चल सके कि इसे कैसे इंस्टैंटिएट करना है. यह एक
ज़रूरी नहीं है. यह सिर्फ़ तब ज़रूरी है, जब आपकी फ़ंक्शन क्लास में कंस्ट्रक्टर
पैरामीटर हों. इस उदाहरण में, कस्टम AppFunctionFactory बनाने और उसे अपनी Application क्लास में कॉन्फ़िगर करने का तरीका दिखाया गया है. इसके लिए, डिपेंडेंसी इंजेक्शन के लिए Hilt का इस्तेमाल किया गया है.
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()
}
ज़रूरी नहीं: रनटाइम के दौरान AppFunction की उपलब्धता को टॉगल करें
AppFunctions को गेट करते समय, फ़ंक्शन को साफ़ तौर पर चालू या बंद करने के लिए, AppFunctionManager API का इस्तेमाल करें. गेटिंग की सुविधा तब काम आ सकती है, जब आपके ऐप्लिकेशन की कुछ सुविधाएँ सभी उपयोगकर्ताओं के लिए उपलब्ध न हों. AppFunctions को डाइनैमिक तरीके से चालू या बंद करने पर, इंटेलिजेंस सिस्टम को यह पता चलता है कि आपके उपयोगकर्ता के लिए कौनसी सुविधाएं उपलब्ध हैं.
AppFunctions को सुरक्षित तरीके से गेट करने के लिए, दो चरणों वाली प्रोसेस अपनाएं. इन AppFunctions के लिए, खाते की खास स्थिति की ज़रूरत होती है:
पहला चरण. फ़ंक्शन को डिफ़ॉल्ट रूप से बंद करें
अगर आपको यह फ़ंक्शन, फ़ीचर फ़्लैग की पुष्टि होने से पहले ऐक्सेस होने से रोकना है, तो अपने @AppFunction एनोटेशन के isEnabled पैरामीटर को false पर सेट करें.
@AppFunction(isEnabled = false, isDescribedByKDoc = true)
suspend fun createTask(...) { ... }
दूसरा चरण. डाइनैमिक तौर पर रनटाइम पर फ़ंक्शन चालू करना
हर AppFunction क्लास के लिए, कंपाइलर एक मिलती-जुलती क्लास जनरेट करता है. इसमें फ़ंक्शन आईडी कॉन्स्टेंट होते हैं. ये कॉन्स्टेंट, Ids सफ़िक्स का इस्तेमाल करते हैं. इन जनरेट किए गए आईडी कॉन्स्टेंट का इस्तेमाल, setAppFunctionEnabled से AppFunctionManagerCompat वाले तरीके के साथ किया जा सकता है. इससे, रनटाइम के दौरान किसी फ़ंक्शन की चालू स्थिति को बदला जा सकता है.
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,
)
}
उपलब्ध कराई जाने वाली सुविधाओं के टाइप के बारे में ध्यान रखने वाली बातें
सुरक्षा हमेशा सबसे अहम होती है. अपने ऐप्लिकेशन की किन सुविधाओं को AppFunctions के तौर पर उपलब्ध कराना है, यह चुनते समय ध्यान रखें कि सिस्टम एजेंट, उपयोगकर्ता की क्वेरी को सर्वर पर प्रोसेस कर सकते हैं. ऐसा वे एलएलएम की बेहतर सुविधाओं का फ़ायदा पाने के लिए करते हैं.
लोगों को बेहतरीन अनुभव देने के लिए, हम इन दिशा-निर्देशों का पालन करने का सुझाव देते हैं. इससे संवेदनशील जानकारी को भी सुरक्षित रखा जा सकेगा:
- नैचुरल लैंग्वेज से फ़ायदा पाने वाली सुविधाएं: ऐसे टास्क उपलब्ध कराएं जिन्हें उपयोगकर्ता, मैन्युअल यूज़र इंटरफ़ेस (यूआई) नेविगेशन के बजाय बातचीत में आसानी से पूरा कर सकें.
- सीमित ऐक्सेस: ऐसे AppFunctions बनाएं जो एजेंट को सिर्फ़ उस डेटा और कार्रवाइयों का ऐक्सेस दें जिनकी ज़रूरत उपयोगकर्ता के अनुरोध को पूरा करने के लिए होती है.
- संवेदनशील जानकारी नहीं: सिर्फ़ ऐसा डेटा शेयर करें जो बहुत निजी या गोपनीय न हो. इसके अलावा, ऐसा डेटा शेयर करें जिसे उपयोगकर्ता ने कार्रवाई के संदर्भ में शेयर करने की साफ़ तौर पर सहमति दी हो.
- डेटा मिटाने जैसी कार्रवाइयों के लिए, साफ़ तौर पर पुष्टि करना: डेटा मिटाने जैसी कार्रवाइयां करने वाली सुविधाओं का इस्तेमाल करते समय, बहुत ज़्यादा सावधानी बरतें. हालांकि, एजेंट इन्हें लागू कर सकता है, लेकिन आपके ऐप्लिकेशन में पुष्टि करने का अपना चरण शामिल होना चाहिए. साथ ही, इसमें साफ़ तौर पर बताया जाना चाहिए कि ऐसा क्यों किया जा रहा है. पुष्टि करने के लिए एक से ज़्यादा चरण जोड़ने से भी मदद मिलती है. इससे यह पक्का किया जा सकता है कि उपयोगकर्ता को पता है कि उससे क्या करने के लिए कहा जा रहा है.
AppFunction इंटिग्रेशन की पुष्टि करना
यह पुष्टि करने के लिए कि आपने AppFunctions को सही तरीके से इंटिग्रेट किया है, adb
shell cmd app_function का इस्तेमाल किया जा सकता है.
आपके ऐप्लिकेशन में उपलब्ध AppFunctions की जानकारी देखने के लिए, adb shell cmd app_function list-app-functions | grep --after-context 10
$myPackageName का इस्तेमाल करें.
Android Studio में Gemini या अपनी पसंद के किसी अन्य एजेंट में, इस तरह का कोई प्रॉम्प्ट दें.
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.