Android의 Permissions API

Android용 Home API를 사용하기 전에 앱에 API에서 구조 라고 하는 사용자 홈의 기기에 액세스할 수 있는 권한이 있어야 합니다. 사용자는 Permissions API를 사용하여 Google 계정으로 Home API 앱에 홈의 기기에 대한 액세스 권한을 부여할 수 있습니다.

권한 흐름을 사용하면 사용자가 Google Home app (GHA)을 사용하지 않고도 아직 설정되지 않은 경우 구조를 만들 수 있습니다.

Permissions API 통합

계속하기 전에 Android에서 홈 초기화를 따랐는지 확인하세요. 이 단계의 homeManager 인스턴스는 여기에 있는 모든 권한 예시에서 사용됩니다.

먼저 SDK에 ActivityResultCaller 를 등록합니다. 예를 들어 샘플 앱에서 이 작업을 처리하는 방법은 다음과 같습니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    homeManager.registerActivityResultCallerForPermissions(this)
  }

권한 확인

권한을 요청하기 전에 앱 사용자가 이미 구조에 액세스하는 데 동의했는지 확인하는 것이 좋습니다. 이렇게 하려면 Home 인스턴스의 hasPermissions() 메서드를 호출하여 Flow PermissionsState 값의 를 가져옵니다.

val permissionsReadyState =
homeManager.hasPermissions().collect { state ->
    when (state) {
      PermissionsState.GRANTED -> println("Permissions granted, no need to request permissions")
      PermissionsState.PERMISSIONS_STATE_UNAVAILABLE ->
          println("Permissions state unavailable, request permissions")

      PermissionsState.NOT_GRANTED ->
          println("OAuth permission is enabled but not granted yet, request permissions")

      PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> println(
          "Permissions state is not initialized yet. Clients should wait for another status update"
      )
      else ->
          throw IllegalStateException("""
            HomeClient.hasPermissions state should be PermissionsState.GRANTED,
            PermissionState.PERMISSIONS_STATE_UNINITIALIZED, or
            PermissionsState.PERMISSIONS_STATE_UNAVAILABLE. Actual state: $state
          """.trimIndent())
    }
}

확인에서 PermissionsStateNOT_GRANTED 또는 PERMISSIONS_STATE_UNAVAILABLE로 반환되면 사용자 또는 애플리케이션에 구조에 대한 액세스 권한이 없는 것입니다. 확인에서 PermissionsStateGRANTED로 반환되지만 후속 structures() 호출에서 구조가 반환되지 않으면 사용자가 GHA 설정 페이지를 통해 앱에 대한 액세스 권한을 취소했거나 사용자에게 필요한 액세스 권한이 없는 것입니다.

권한 요청

특정 구조 내의 구조 및 기기에 액세스하려면 앱에 권한이 부여되어야 합니다.

사용자가 아직 권한을 부여하지 않은 경우 Home 인스턴스의 requestPermissions() 메서드를 사용하여 권한 UI를 실행하고 결과를 처리합니다.

fun requestPermissions(scope: CoroutineScope, onShowSnackbar: (String) -> Unit) {
  scope.launch {
    val result =
      try {
        homeManager.requestPermissions()
      } catch (e: HomeException) {
        PermissionsResult(
          PermissionsResultStatus.ERROR,
          "Got HomeException with error: ${e.message}",
        )
      }
    when (result.status) {
      PermissionsResultStatus.SUCCESS -> {
        Log.i(TAG, "Permissions successfully granted.")
      }
      PermissionsResultStatus.CANCELLED -> {
        Log.i(TAG, "User cancelled Permissions flow.")
        onShowSnackbar("User cancelled Permissions flow")
      }
      else -> {
        Log.e(
          TAG,
          "Failed to grant permissions with error: ${result.status}, ${result.errorMessage}",
        )
        onShowSnackbar("Failed to grant permissions with error: ${result.errorMessage}")
      }
    }
  }
}
PermissionsManager

권한 UI가 제대로 실행되려면 앱에 OAuth를 이미 설정해야 합니다.

권한 부여

이제 앱을 실행하고 사용자에게 권한을 부여할 수 있습니다. 권한을 부여할 수 있는 사용자 유형과 권한을 부여할 수 있는 기기 유형은 Google Home Developer Console에 앱을 등록했는지 여부에 따라 다릅니다.

Developer Console 등록이 필요합니다. Home API를 사용하여 앱을 게시하려면 Home API를 테스트하고 사용하는 데는 필요하지 않습니다.

앱이 Developer Console에 등록되지 않은 경우 확인되지 않음 상태가 됩니다. Home API의 테스트 사용에 권장되는 사항은 다음과 같습니다.

앱이 개발자 콘솔에 등록되어 있고Developer Console 하나 이상의 기기 유형에 대한 액세스가 승인되었으며 OAuth에 대한 브랜드 인증이 완료된 경우, 확인됨 상태가 됩니다. 이 상태는 앱을 프로덕션에 출시하는 데 필요합니다.

  • 테스트 사용자 한도가 더 이상 적용되지 않습니다. 모든 사용자가 앱에 권한을 부여할 수 있습니다.
  • 사용자는 개발자 콘솔에서 승인된 기기 유형에만 권한을 부여할 수 있습니다.Developer Console

이제 OAuth가 설정되었으므로 앱의 requestPermissions() 호출이 다음 대화상자를 트리거합니다.

  1. 사용하려는 Google 계정을 선택하라는 메시지가 사용자에게 표시됩니다.
  2. 앱 액세스 권한을 부여할 구조를 선택하라는 메시지가 사용자에게 표시됩니다.
    1. 확인되지 않은 앱의 경우 Home API에서 지원하는 모든 기기 유형을 앱에서 사용할 수 있습니다.
    2. 확인된 앱의 경우 사용자는 개발자 콘솔에서 승인된 기기 유형에만 권한을 부여할 수 있습니다.Developer Console
    3. 앱에서 관리할 수 있는 민감한 기기 유형의 경우 사용자는 기기별로 액세스를 제한할 수 있습니다. 예를 들어 사용자에게 잠금장치가 3개 있는 경우 이러한 잠금장치 중 하나에만 액세스 권한을 부여할 수 있습니다.
  • OAuth 동의 - 계정 선택
  • OAuth 동의 - 기기 연결 01
  • OAuth 동의 - 기기 연결 02
그림 1: OAuth 동의 흐름 예시

권한이 부여되면 앱은 Home API를 사용하여 구조의 기기 상태를 읽고 제어할 수 있습니다. 사용자가 특정 기기 유형 또는 민감한 기기에 대한 권한을 앱에 부여하지 않으면 앱은 Home API를 사용하여 액세스, 제어 또는 자동화할 수 없습니다.

권한 변경

다른 구조의 기기에 액세스할 수 있는 권한을 부여하려면 계정 선택 도구를 실행하여 사용자가 전환할 Google 계정 및 구조를 선택할 수 있도록 합니다. 이 과정에서 이전에 동의가 부여되었더라도 사용자에게 동의 화면이 다시 표시됩니다.

이는 forceLaunch 플래그를 true로 설정하여 requestPermissions()를 다시 호출하면 됩니다.

homeManager.requestPermissions(forceLaunch=true)

구조 힌트를 사용하여 권한 변경

구조 힌트를 사용하면 앱에서 사용자의 Home API 권한에 대한 증분 변경을 요청할 때 특정 구조를 미리 선택하거나 사용 가능한 구조 목록을 제한할 수 있습니다. 구조 매개변수를 승인 요청에 전달하면 권한 대화상자가 선택한 구조에 자동으로 포커스를 맞춰 사용자 불편을 줄이고 구성 오류를 방지합니다.

구조 힌트는 ConsentScreenOptions 데이터 클래스를 사용하여 관리됩니다. ConsentScreenOptions 클래스는 다음 구성 매개변수를 허용합니다.

  • structureId — 권한 대화상자에서 미리 선택할 특정 구조 ID입니다. 업데이트되는 구조의 구조 속성을 확인하여 가져옵니다.
  • allowedStructureIds — 구조 ID 목록입니다. 제공된 경우 권한 대화상자는 사용 가능한 구조를 필터링하여 이 목록에 있는 구조만 표시합니다. 사용자가 이미 부여된 구조 목록 내에 있도록 하려는 경우가 아니라면 대부분의 경우 지정하지 않아도 됩니다.
  • allowStructureChange — 사용자가 미리 선택된 구조를 변경할 수 있는지 결정합니다. 대부분의 경우 allowedStructureIdsstructureId 중 하나 이상이 지정된 경우 이를 true로 설정하여 사용자의 자연스러운 동작을 지원합니다.

forceLaunch 플래그가 true로 설정된 상태에서 이 객체를 requestPermissions() 호출의 선택적 매개변수로 전달합니다.

import com.google.home.ConsentScreenOptions

// Create the ConsentScreenOptions class, allowing structure changes while
// ensuring the permissions dialog pre-selects the target structure on launch
val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowStructureChange = true
)

homeManager.requestPermissions(forceLaunch=true, consentOptions)

사용자에게 ConsentScreenOptions 객체에 언급된 구조로 이미 필터링된 동의 화면이 표시됩니다.

사용자가 구조 힌트를 사용하여 구조를 전환하도록 허용

사용자가 앱에 여러 구조를 보유하고 있으며 사용자가 사용 가능한 구조 간에 전환할 수 있도록 하면서도 하나의 구조를 미리 선택하려는 경우 allowStructureChange 플래그로 구조 변경을 사용 설정하고 allowedStructureIds에 구조 목록을 제공합니다.

val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowedStructureIds = listOf(target-structure-id, another-structure-id),
    allowStructureChange = true
)

권한 취소

사용자는 이전에 부여된 액세스 권한을 취소할 수 있습니다.

  1. Google 내 계정 페이지 > 데이터 및 개인 정보 보호 > 서드 파티 앱 및 서비스를 통해. 이렇게 하면 초기 동의가 부여될 때 발급된 OAuth 토큰이 취소되고 사용자가 모든 화면 (휴대전화)과 구조에서 사용 중인 앱의 모든 인스턴스에 대한 액세스 권한이 취소됩니다.

    사용자는 다음 URL 스키마를 사용하여 딥 링크로 서드 파티 앱 및 서비스 하위 페이지로 이동할 수 있습니다.

    https://myaccount.google.com/connections/link?project_number=Cloud project_number
    
  2. GHA > 설정 > 연결된 앱 페이지를 통해. GHA에서 을 클릭하면 설정 페이지로 이동합니다. 여기에서 동의 화면과 유사한 페이지로 이동하는 연결된 앱 타일을 클릭합니다. 이 페이지에서 사용자는 앱에 대한 액세스 권한을 삭제할 수 있습니다. 사용자는 이 동일한 페이지를 사용하여 앱에서 액세스할 수 있는 기기 유형 또는 특정 민감한 기기를 변경할 수 있습니다.

Google Home 생태계에서 대부분의 기기 유형의 경우 사용자는 해당 유형의 모든 기기에 대한 권한을 한 번에 부여할 수 있습니다. 잠금장치, 카메라, 초인종과 같은 민감하거나 제한된 기기 유형의 경우 사용자는 이러한 기기에 개별적으로 권한을 부여해야 합니다.

사용자가 민감하거나 제한된 기기 유형에 액세스할 수 있는 권한을 부여했는지 확인하려면 구조 수준 consentedDeviceTypes() 함수를 사용합니다.

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

OkGoogle 권한

okGoogle 명령어는 기기 수준 명령어이며 구조의 모든 기기를 자동화하는 데 사용할 수 있습니다. 하지만 Home API 앱은 모든 기기에 액세스하지 못할 수 있습니다. 다음 표에서는 이러한 경우 권한이 적용되는 방법을 설명합니다.

자동화 트레이트 권한 적용
오후 10시에 침실 스피커에서 '취침 시간'을 브로드캐스트합니다. AssistantBroadcastTrait 기기에서. 자동화 생성:
  • 브로드캐스트 기기는 어시스턴트 기기여야 합니다.
  • 앱과 사용자는 브로드캐스트가 발생하는 기기에 액세스할 수 있어야 합니다.
자동화 실행:
  • 앱과 사용자는 브로드캐스트가 발생하는 기기에 액세스할 수 있어야 합니다.
오후 10시에 모든 기기에서 '취침 시간'을 브로드캐스트합니다. AssistantBroadcastTrait 구조에. 자동화 생성:
  • 앱과 사용자가 액세스할 수 있는 구조에 어시스턴트 기기가 하나 이상 있어야 합니다.
  • 앱과 사용자는 구조에 액세스할 수 있어야 합니다.
자동화 실행:
  • 앱과 사용자는 구조에 액세스할 수 있어야 합니다.
오후 10시에 '음악 틀어 줘' AssistantFulfillmentTrait.OkGoogleCommand 자동화 생성:
  • 앱과 사용자는 자동화에서 명령어를 실행하는 기기에 액세스할 수 있어야 합니다.
자동화 실행:
  • 앱과 사용자는 자동화에서 명령어를 실행하는 기기에 액세스할 수 있어야 합니다.
누군가가 '음악 틀어 줘'라고 말할 때마다 VoiceStarterTrait.OkGoogleEvent 자동화 생성:
  • 앱과 사용자는 구조에 액세스할 수 있어야 합니다. 구조에 액세스할 수 있는 모든 사용자가 동일한 Google 계정을 사용하여 휴대전화를 통해 어시스턴트와 상호작용하고 VoiceStarter를 트리거할 수 있으므로 자동화 에는 유효성 검사를 통과하거나 실행하기 위한 어시스턴트 기기가 필요하지 않습니다.
자동화 실행:
  • 앱에는 자동화를 시작하는 기기에 액세스할 수 있는 권한이 필요하지 않습니다.
  • 앱과 사용자에게는 작업이 발생하는 기기에 액세스할 수 있는 권한이 있어야 합니다.

사용자가 모든 권한을 취소하는 경우 안내

사용자가 모든 권한을 취소하면 기존의 모든 자동화가 작동을 멈춥니다. 또한 사용자가 특정 기기에 대한 액세스 권한을 취소하면 이러한 기기와 연결된 시작 조건, 조건, 작업이 작동을 멈춥니다.

앱이 시작될 때마다 권한이 여전히 유효한지 확인하세요. 권한이 취소된 경우 애플리케이션에 캐시된 데이터를 포함하여 이전의 모든 데이터가 삭제되었는지 확인하세요.