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() 方法,以获取FlowPermissionsState 值:

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

如果检查返回 NOT_GRANTEDPERMISSIONS_STATE_UNAVAILABLEPermissionsState,则表示用户或应用无权访问该结构。 如果检查返回 PermissionsStateGRANTED,但随后对 structures() 的调用未返回任何结构, 则表示用户已通过 GHA 设置页面撤消了对应用的访问权限,或者用户 缺少所需的访问权限。

请求权限

必须向应用授予权限,才能访问给定结构中的结构和设备。

如果用户尚未授予权限,请使用 requestPermissions() 方法启动权限界面并处理结果:

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

如需正确启动权限界面,您必须已为应用 设置 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. 对于应用有权管理的敏感设备类型,用户可以按设备限制访问权限。例如,如果用户有三把锁,则只能授予对其中一把锁的访问权限。
  • OAuth 权限请求 - 选择账号
  • OAuth 权限请求 - 关联设备 01
  • OAuth 权限请求 - 关联设备 02
图 1:OAuth 权限请求流程示例

授予权限后,应用可以使用 Home API 读取结构中设备的状态并控制这些设备。如果用户未向应用授予对特定设备类型或敏感设备的权限,则应用将无法使用 Home API 访问、控制或自动控制该设备。

更改权限

如需授予访问不同结构中设备的权限,可以启动账号选择器,让用户选择要切换到的 Google 账号和结构。在此过程中,系统会再次向用户显示权限请求页面,即使之前已授予权限也是如此。

为此,请再次调用 requestPermissions(),并将 forceLaunch 标志设置为 true

homeManager.requestPermissions(forceLaunch=true)

撤消权限

用户可以撤消之前授予的访问权限:

  1. 通过 Google 我的账号页面 > 数据和隐私设置 > 第三方应用和服务。这将撤消在首次授予权限时颁发的 OAuth 令牌,并撤消用户在所有界面(手机)和结构中使用的任何应用实例的访问权限。

    用户可能会通过深层链接被定向到第三方应用和服务 子页面,网址协议如下:

    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 点,在卧室扬声器上广播“Bedtime”。 AssistantBroadcastTrait 设备上。 自动化操作创建:
  • 广播设备必须是支持 Google 助理的设备。
  • 应用和用户必须有权访问广播发生的设备。
自动化执行:
  • 应用和用户必须有权访问广播发生的设备。
晚上 10 点,在所有设备上广播“Bedtime”。 AssistantBroadcastTrait 结构上。 自动化操作创建:
  • 结构中必须至少有一个支持 Google 助理的设备,应用和用户有权访问该设备。
  • 应用和用户必须有权访问该结构。
自动化执行:
  • 应用和用户必须有权访问该结构。
晚上 10 点,“播放一些音乐” AssistantFulfillmentTrait.OkGoogleCommand 自动化操作创建:
  • 应用和用户必须有权访问自动化向其发出命令的设备。
自动化执行:
  • 应用和用户必须有权访问自动化向其发出命令的设备。
每当有人说“播放一些音乐”时 VoiceStarterTrait.OkGoogleEvent 自动化操作创建:
  • 应用和用户必须有权访问该结构。自动化操作 不需要支持 Google 助理的设备即可通过验证或运行, 因为任何有权访问该结构的用户都可以使用自己的手机 (使用同一 Google 账号)与 Google 助理互动并触发 VoiceStarter。
自动化执行:
  • 应用不需要访问启动自动化的设备的权限。
  • 应用和用户必须有权访问执行操作的设备。

用户撤消所有权限时的指南

如果用户撤消所有权限,所有现有自动化都将停止运行。此外,如果用户撤消对特定设备的访问权限,则与这些设备关联的启动器、条件和操作都将停止运行。

每次启动应用时,请务必检查权限是否仍然有效。如果权限已被撤消,请务必移除所有先前的数据,包括应用中缓存的所有数据。