在 Android 上初始化主畫面

使用任何 Android 適用的 Home API 前,您必須在應用程式中初始化住家。在這個步驟中,您將為本機環境建立 singleton Home 執行個體。

一次只能啟用一個 Home 例項。

這是 Home API 的進入點,也涉及宣告您打算搭配 Device & Structure 和 Automation API 使用的特徵和裝置類型。如果您剛開始使用 Google Home 生態系統,不確定要註冊哪些特徵或裝置類型,我們已在本指南中建議一些最常見的特徵或裝置類型。

建立住家執行個體

首先,請將下列套件匯入應用程式:

import android.content.Context
import com.google.home.FactoryRegistry
import com.google.home.HomeConfig
import com.google.home.Home

如要初始化 Home API,請按照下列步驟操作:

  1. 取得 Application 內容的參照。這個內容不依附於任何活動生命週期,只要應用程式保持運作,這個內容就會存在。您可以在 ActivityService 中呼叫 getApplicationContext() 來取得:

    val context = getApplicationContext()
    
  2. 建立具有所有特徵和裝置類型的FactoryRegistry 執行個體,以便在應用程式中使用。

    在本指南中,我們建議使用一些常見的裝置類型 (燈具、插座、感應器、開關和溫度控制器裝置類型,以及自動化作業的在場狀態和 Google 助理特徵),以防您不確定需要哪些裝置。詳情請參閱「註冊特徵和裝置類型」。

    val registry = FactoryRegistry(
      traits = listOf(
                AirQuality,
                AreaAttendanceState,
                AreaPresenceState,
                AssistantBroadcast,
                AssistantFulfillment,
                BooleanState,
                ColorControl,
                ExtendedColorControl,
                FlowMeasurement,
                IlluminanceMeasurement,
                LevelControl,
                Notification,
                OccupancySensing,
                OnOff,
                RelativeHumidityMeasurement,
                Switch,
                TemperatureMeasurement,
                Thermostat),
      types = listOf(
                AirQualitySensorDevice,
                ColorDimmerSwitchDevice,
                ColorTemperatureLightDevice,
                ContactSensorDevice,
                DimmableLightDevice,
                DimmablePlugInUnitDevice,
                DimmerSwitchDevice,
                ExtendedColorLightDevice,
                FlowSensorDevice,
                GenericSwitchDevice,
                HumiditySensorDevice,
                LightSensorDevice,
                OccupancySensorDevice,
                OnOffLightDevice,
                OnOffLightSwitchDevice,
                OnOffPluginUnitDevice,
                OnOffSensorDevice,
                SpeakerDevice,
                TemperatureSensorDevice,
                ThermostatDevice))
    

    您必須匯入在此註冊的各個特徵和裝置類型專用的陳述式 (Android Studio 應會提示您新增這些陳述式)。

  3. 使用 Dispatchers.IO 協同程式內容和登錄例項,例項化 HomeConfig

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. 最後,請使用內容和 HomeConfig,建立 Homesingleton 執行個體,這是 API 的進入點。

    val homeManager: HomeClient = Home.getClient(context, homeConfig)
    

為避免無效工作階段發生錯誤,請務必只建立 singleton Home 執行個體,方法是將其包裝在 object 宣告中。

以「範例應用程式」為例,做法如下:

internal object HomeClientModule {
  @Provides
  @Singleton
  fun provideHomeClient(@ApplicationContext context: Context): HomeClient {
    return Home.getClient(
      context,
      HomeConfig(
        coroutineContext = IODispatcherModule.provideIoDispatcher(),
        factoryRegistry = registry,
      ),
    )
  }
}

應用程式發起的 Google 登入

您可能想在應用程式中管理使用者的 Google 驗證。 這樣一來,使用者就能在各種 Google 服務 (例如 Google Home、雲端硬碟、地圖等) 中使用同一個帳戶。

透過應用程式啟動的 Google 登入功能,您可以取得與特定使用者明確連結的 HomeClient 執行個體,因此當帳戶已獲得授權時,系統會略過 Google 帳戶挑選器和同意畫面。

此外,這個方法可避免使用者看到兩個不同的帳戶選取畫面,一個來自應用程式的登入畫面,另一個來自 Google Home。

如要這麼做,請參閱「使用 Google 登入功能驗證使用者身分」,並完成下列步驟:

建立 OAuth 網頁應用程式用戶端 ID

  1. 開啟 Google Cloud 控制台
    • 前往 Google Cloud 控制台的「憑證」頁面。
    • 選取現有專案或建立新專案。
  2. 設定 OAuth 同意畫面 (如尚未設定)
    • 建立憑證前,請務必先設定 OAuth 同意畫面,並填入應用程式詳細資料,包括隱私權政策和服務條款網址。
  3. 建立 OAuth 用戶端 ID (網頁應用程式類型)
    • 在「憑證」頁面中,按一下 + CREATE CREDENTIALS,然後從下拉式選單中選取「OAuth 用戶端 ID」
    • 在「Application type」部分,選取「Web application」
    • 輸入網頁用戶端的名稱 (例如 「My App Web Backend」)。
    • 按一下「建立」。
  4. 擷取用戶端 ID
    • 建立完成後,控制台會顯示新的用戶端 ID。這是您在 Android 應用程式中使用的值 (例如「{project number}-.....apps.googleusercontent.com」)
    • 建議您將 Client ID 儲存在外部 (例如 build.gradle),而不是直接以硬式編碼方式儲存

將 Google 登入要求例項化

使用網頁應用程式 ID 建立 Google 登入要求:

// Your Google Cloud console Web Client ID for Google Sign-In
val serverClientId = BuildConfig.DEFAULT_WEB_CLIENT_ID

// Build the request for Google ID token
val googleIdOption = GetGoogleIdOption.Builder()
    .setFilterByAuthorizedAccounts(false) // Show all Google Accounts on the device
    .setServerClientId(serverClientId) // embed WebClientID in token
    .build()

// Build the GetCredentialRequest
val request = GetCredentialRequest.Builder().addCredentialOption(googleIdOption).build()

建立「使用 Google 帳戶登入」流程

如要實作登入流程,請使用 CredentialManager 執行 Sign in with Google 要求。使用者選取帳戶後,請從產生的 Google ID 權杖中擷取電子郵件地址,然後建立 android.accounts.Account。這個帳戶隨後會用於初始化與該登入使用者相關聯的 HomeClient 執行個體。

  try {
    // CredentialManager is responsible for interacting with various credential providers on the device
    val credentialManager = CredentialManager.create(context)
    // Credential returns when user has selected an account and the getCredential call completes
    val result = credentialManager.getCredential(context = context, request = request)
    val credential = result.credential

    if (
      credential is CustomCredential &&
      credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL
    ) {
      try {
        val googleCredential = GoogleIdTokenCredential.createFrom(credential.data)
        googleCredential.id.let { userEmail ->
          Log.i(TAG, "Email found in Google ID Token: $email")
          /*
           Why "com.google"?
           The string "com.google" is a standard identifier used in Android's android.accounts.
           Account system to represent accounts managed by Google. This is often used when
           interacting with Android's Account Manager or when using Google-specific APIs. So,
           even if the email ends in "@gmail.com", the underlying account type or provider is
           still considered "com.google" within the Android system.
          */
          val account = Account(userEmail, "com.google")
          Log.d(TAG,"Switched account to : $userEmail")
          // Get the new Home Client Instance with the userEmail
        }
        Log.i(TAG, "Account switch complete. Emitting navigation event.")
      } catch (e: Exception) {
        Log.e(TAG,"Could not convert CustomCredential to Google ID Token", e)
      }
    }
  } catch (e: Exception) {
    Log.e(TAG, "Google Sign-In failed with unexpected error", e)
  }

取得新的 HomeClient 執行個體

請按照「建立 Home 執行個體」一文中的步驟操作,但請在步驟 4 中呼叫 Home.getClient(context, userAccount, homeConfig),而非 Home.getClient(context, homeConfig),其中第二個參數是 Lazy<UserAccount>。這會傳回 HomeClientWithProvidedAccount 的執行個體,這是 HomeClient 的子類別,明確繫結至指定的 Google 帳戶:

val client =
     Home.getClient(
       context = context.applicationContext,
       account =
         lazy {
         // 1. Create the Account object.
           val androidAccount = Account(userEmail,
                                        GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE)
         // 2. Wrap it in UserAccount.GoogleAccount.
           UserAccount.GoogleAccount(androidAccount)
         },
       homeConfig = HomeConfig()
     )

如果指定使用者未獲得授權,請在 HomeClientWithProvidedAccount 執行個體上呼叫下列方法,提示使用者授予權限:

  1. registerActivityResultCallerForPermissions(),並參照您要使用的 ActivityResultCaller
  2. requestPermissions()。 系統會顯示 GHP 同意畫面,使用者可以在這裡授予權限。

您可以建立具有 UserAccountHomeClient,然後呼叫 requestPermissions() (使用 forceLaunch==true) 再次啟動同意畫面,讓使用者更新授予的權限:

val client =
     Home.getClient(
       context = context.applicationContext,
       account =
         lazy {
              UserAccount.GoogleAccount(androidAccount)
         },
       homeConfig = HomeConfig()
     )

client.registerActivityResultCallerForPermissions(this)
client.requestPermissions(forceLaunch= true)

如要進一步瞭解如何管理 Home API 權限,請參閱 Permissions API

使用新的 HomeClient 重新整理整個活動

取得新的 HomeClient 執行個體後,您必須重新整理整個活動,才能重新訂閱及擷取與這個使用者帳戶相關聯的完整結構、裝置和其他相關資料。

註冊特徵和裝置類型

開發人員可以透過 FactoryRegistry 類別,明確指出應用程式使用的特徵和裝置類型,藉此最佳化應用程式二進位檔大小。

請注意,權限和工廠登錄程序是分開的。因此,應用程式可透過權限存取但未納入工廠登錄的未註冊特徵和型別,無法透過 Automation API 存取,也不會傳回大量 traits()types() 方法呼叫。