앱에 AppFunctions API 추가

이 가이드에서는 AppFunctions API를 Android 앱에 통합하고, 함수의 로직을 구현하고, 통합이 올바르게 작동하는지 확인하는 방법을 설명합니다.

버전 호환성

이 구현에서는 프로젝트 compileSdk를 API 수준 36 이상으로 설정해야 합니다.

앱에서 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")
}

AppFunctions 로직 구현

Android 앱의 AppFunction을 구현하려면 특정 AppFunctions 로직을 구현하는 클래스를 만듭니다. 여기에는 매개변수 및 응답을 위한 직렬화 가능한 데이터 클래스를 만든 다음 함수 메서드 내에서 핵심 로직을 제공하는 작업이 포함됩니다.

다음 코드는 리포지토리를 사용하여 맞춤 매개변수 및 응답 유형과 기본 함수 로직을 정의하는 등 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 구현은 Android UI 스레드에서 실행됩니다. 따라서 장기 실행 작업은 다음을 실행해야 합니다.
    • AppFunction을 정지 함수로 선언합니다.
    • 작업이 스레드를 차단할 수 있는 경우 적절한 코루틴 디스패처로 전환합니다.
  • isDescribedByKDoctrue로 설정되면 함수 설명 또는 직렬화 가능한 설명이 AppFunctionMetadata의 일부로 인코딩되어 에이전트가 앱의 AppFunction을 사용하는 방법을 이해하는 데 도움이 됩니다.

매니페스트에서 AppFunction 서비스 선언

모듈 매니페스트(예: src/main/AndroidManifest.xml) 내에서 KSP 생성 서비스 선언 및 app_metadata 속성을 등록합니다. KSP 컴파일러는 추상 진입점 클래스를 확장하는 구체적인 서비스 클래스 (TaskAppFunctionService)를 assets/ 디렉터리의 상응하는 XML 스키마와 함께 생성합니다.

<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를 동적으로 사용 설정하거나 사용 중지하면 인텔리전스 시스템은 언제든지 사용자가 사용할 수 있는 기능을 정확히 파악합니다.

특정 계정 상태가 필요한 AppFunctions를 안전하게 게이트하려면 2단계 프로세스를 따르세요.

1단계: 기본적으로 함수 사용 중지

기능 플래그가 확인되기 전에 함수에 액세스할 수 없도록 하려면 @AppFunction 주석의 isEnabled 매개변수를 false로 설정합니다.

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

2단계: 런타임 시 함수를 동적으로 사용 설정

컴파일러는 각 AppFunction 클래스에 대해 함수 ID 상수 (Ids 접미사 사용)가 포함된 상응하는 클래스를 생성합니다. 생성된 ID 상수를 AppFunctionManagerCompatsetAppFunctionEnabled 메서드와 함께 사용하여 런타임 시 함수의 사용 설정 상태를 변경할 수 있습니다.

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 기능을 활용하기 위해 서버에서 사용자 쿼리를 처리할 수 있다는 점을 기억하는 것이 중요합니다.

민감한 정보를 노출하지 않으면서도 우수한 사용자 환경을 제공하려면 다음 가이드라인을 따르는 것이 좋습니다.

  • 자연어의 이점을 누리는 기능: 사용자가 수동 UI 탐색을 통해 표현하는 것보다 대화에서 더 쉽게 표현할 수 있는 작업을 제공합니다.
  • 액세스 제한: 에이전트가 사용자의 특정 요청을 처리하는 데 필요한 데이터 및 작업에만 액세스할 수 있는 AppFunctions를 만듭니다.
  • 민감하지 않은 정보: 매우 개인적이거나 기밀이 아닌 데이터 또는 사용자가 작업의 맥락에서 공유하는 데 명시적으로 동의한 데이터만 공유합니다.
  • 파괴적인 작업에 관한 명확한 확인: 데이터를 삭제하는 것과 같은 파괴적인 작업을 실행하는 함수는 매우 신중하게 사용합니다. 에이전트가 이러한 함수를 호출할 수 있지만 앱에는 자체 확인 단계가 포함되어야 하며 의도에 관한 명확하고 모호하지 않은 표현을 사용해야 합니다. 사용자가 요청받은 작업을 인식하도록 하려면 확인 단계를 두 개 이상 추가하는 것이 좋습니다.

AppFunction 통합 확인

AppFunctions를 올바르게 통합했는지 확인하려면 adb shell cmd app_function을 사용하면 됩니다.

adb shell cmd app_function list-app-functions | grep --after-context 10 $myPackageName을 사용하여 앱에서 제공하는 AppFunctions의 세부정보를 확인합니다.

명시적 식별자 ("$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\"}}'"

프롬프트 없이 Android MCP를 직접 경험하고 엔드 투 엔드 워크플로를 확인하려면 기기에 AppFunctions testing agent Android 앱을 설치하고 실행하세요.

Android 스튜디오의 Gemini와 같은 채팅 기반 어시스턴트를 사용하여 통합을 확인하는 경우 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는 라이브러리 종속 항목을 통합하고 기존 구성 제공업체(AppFunctionConfiguration.Provider)를 대체하는 컴파일 시간 @AppFunctionServiceEntryPoint 아키텍처를 도입했습니다.

앱에서 현재 이전 버전의 AppFunctions (예: 1.0.0-alpha09)를 사용하는 경우 Android 스튜디오의 Gemini와 같은 AI IDE에서 AppFunctions 에이전트 스킬을 사용하여 이전을 자동화할 수 있습니다. 이 스킬에는 에이전트가 빌드 종속 항목을 통합하고, 필요한 @AppFunctionServiceEntryPoint 서비스 래퍼를 만들고, 컨텍스트 매개변수를 분리하고, 매니페스트 선언을 업데이트하도록 안내하는 전용 마이그레이션 규칙이 포함되어 있습니다.