Zuhause auf Android-Geräten initialisieren

Bevor du eine der Home APIs für Android verwenden kannst, musst du das Zuhause in deiner App initialisieren. In diesem Schritt erstellst du eine Singleton-Instanz von Home für den lokalen Kontext.

Es sollte jeweils nur eine Instanz von Home aktiv sein.

Dies ist der Einstiegspunkt für die Home APIs. Hier werden auch die Eigenschaften und Gerätetypen deklariert, die du mit den Device & Structure und Automation APIs verwenden möchtest. Wenn du gerade erst mit dem Google Home-Ökosystem beginnst und dir nicht sicher bist, welche Eigenschaften oder Gerätetypen du registrieren sollst, findest du in diesem Leitfaden einige der gängigsten.

Home-Instanz erstellen

Importieren Sie zuerst diese Pakete in Ihre App:

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

So initialisierst du die Home APIs:

  1. Rufen Sie eine Referenz zum Application-Kontext ab. Dieser Kontext ist nicht vom Aktivitätslebenszyklus abhängig und bleibt so lange bestehen, wie Ihre App aktiv ist. Sie können sie abrufen, indem Sie getApplicationContext() innerhalb eines Activity oder Service aufrufen:

    val context = getApplicationContext()
    
  2. Erstelle eine FactoryRegistry-Instanz mit allen Attributen und Gerätetypen, die du in deiner App verwenden möchtest.

    In diesem Leitfaden haben wir einige gängige Gerätetypen (Licht, Steckdose, Sensor, Schalter und Thermostat) sowie Anwesenheits- und Assistant-Eigenschaften für automatisierte Abläufe vorgeschlagen, falls du dir nicht sicher bist, was du brauchst. Weitere Informationen findest du unter Registrierung von Attributen und Gerätetypen.

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

    Für jede hier registrierte Eigenschaft und jeden Gerätetyp sind Importanweisungen erforderlich (Android Studio sollte Sie auffordern, diese hinzuzufügen).

  3. Instanziieren Sie ein HomeConfig mit dem Koroutinenkontext Dispatchers.IO und Ihrer Registry-Instanz.

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. Erstellen Sie schließlich die Singleton-Instanz von Home, die den Einstiegspunkt für die APIs darstellt, indem Sie den Kontext und die HomeConfig verwenden.

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

Um Fehler mit ungültigen Sitzungen zu vermeiden, ist es wichtig, dass nur eine Singleton-Instanz von Home erstellt wird. Dazu wird sie in eine Objektdeklaration eingeschlossen.

In der Beispiel-App wird das so gemacht:

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

Wenn Sie möchten, dass von Google gehostete UI-Abläufe, z. B. der Zustimmungsbildschirm für Berechtigungen, in einer bestimmten Sprache gerendert werden, rufen Sie setLocale() in Ihrer HomeClient-Instanz auf, bevor Sie Berechtigungen anfordern. Weitere Informationen finden Sie unter App-Sprache konfigurieren.

Von der App initiierte Google-Anmeldung

Möglicherweise möchten Sie die Google-Authentifizierungen Ihrer Nutzer in Ihrer App verwalten. So können Sie dasselbe Nutzerkonto für verschiedene Google-Dienste wie Google Home, Drive, Maps usw. verwenden.

Mit der von der App initiierten Google-Anmeldung können Sie eine HomeClient-Instanz abrufen, die explizit an einen bestimmten Nutzer gebunden ist. Dadurch werden die Google-Kontoauswahl und der Zustimmungsbildschirm umgangen, wenn das Konto bereits autorisiert ist.

Außerdem wird so verhindert, dass Nutzer zwei verschiedene Bildschirme zur Kontoauswahl sehen – einen von der Anmeldung in der App und einen von Google Home.

Dazu müssen Sie die Schritte im Artikel Nutzer mit „Über Google anmelden“ authentifizieren ausführen:

OAuth-Webanwendungs-Client-ID erstellen

  1. Öffnen Sie die Google Cloud Console.
    • Rufen Sie in der Google Cloud Console die Seite „Anmeldedaten“ auf.
    • Wählen Sie ein vorhandenes Projekt aus oder erstellen Sie ein neues.
  2. OAuth-Zustimmungsbildschirm konfigurieren (falls noch nicht geschehen)
    • Bevor Sie Anmeldedaten erstellen, muss der OAuth-Zustimmungsbildschirm mit den Details Ihrer App konfiguriert sein, einschließlich der URLs für die Datenschutzerklärung und die Nutzungsbedingungen.
  3. OAuth-Client-ID (Typ „Webanwendung“) erstellen
    • Klicken Sie auf der Seite „Anmeldedaten“ auf + CREATE CREDENTIALS und wählen Sie im Drop-down-Menü die Option OAuth-Client-ID aus.
    • Wählen Sie als Anwendungstyp die Option Webanwendung aus.
    • Geben Sie einen Namen für Ihren Webclient ein (z.B. „My App Web Backend“).
    • Klicken Sie auf „Erstellen“.
  4. Client-ID abrufen
    • Nach der Erstellung wird die neue Client-ID in der Console angezeigt. Diesen Wert verwenden Sie in Ihrer Android-App (z. B. {project number}-.....apps.googleusercontent.com).
    • Es wird empfohlen, die Client-ID extern zu speichern (z. B. in build.gradle), anstatt sie direkt im Code zu hinterlegen.

Google Log-in-Anfrage instanziieren

Verwenden Sie die Web-App-ID, um eine Google-Anmeldeanfrage zu erstellen:

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

Ablauf „Über Google anmelden“ erstellen

Verwenden Sie CredentialManager, um eine Sign in with Google-Anfrage auszuführen, um den Anmeldevorgang zu implementieren. Sobald der Nutzer ein Konto ausgewählt hat, extrahieren Sie seine E-Mail-Adresse aus dem resultierenden Google-ID-Token, um ein android.accounts.Account zu erstellen. Dieses Konto wird dann verwendet, um eine HomeClient-Instanz zu initialisieren, die speziell mit diesem angemeldeten Nutzer verknüpft ist.

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

Neue HomeClient-Instanz abrufen

Folge den Schritten unter Home-Instanz erstellen, aber rufe in Schritt 4 nicht Home.getClient(context, homeConfig), sondern Home.getClient(context, userAccount, homeConfig) auf, wobei der zweite Parameter ein Lazy<UserAccount> ist. Dadurch wird eine Instanz von HomeClientWithProvidedAccount zurückgegeben, einer Unterklasse von HomeClient, die explizit mit dem angegebenen Google-Konto verknüpft ist:

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

Wenn der angegebene Nutzer nicht autorisiert ist, fordern Sie ihn auf, die Berechtigung zu erteilen. Rufen Sie dazu die folgenden Methoden für die HomeClientWithProvidedAccount-Instanz auf:

  1. registerActivityResultCallerForPermissions() mit einem Verweis auf den ActivityResultCaller, den Sie verwenden möchten.
  2. requestPermissions(). Dadurch wird der GHP-Zustimmungsbildschirm aufgerufen, auf dem der Nutzer seine Zustimmung erteilen kann.

Sie können ein HomeClient mit einem UserAccount erstellen und dann requestPermissions() mit forcePermissionFlow auf ForcePermissionFlow.FORCE_LAUNCH aufrufen, um den Zustimmungsbildschirm noch einmal zu starten, damit der Nutzer seine Berechtigungen aktualisieren kann:

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

client.registerActivityResultCallerForPermissions(this)
client.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH)

Wenn Sie den Einwilligungsbildschirm in einer bestimmten Sprache anzeigen möchten, rufen Sie client.setLocale() auf, bevor Sie requestPermissions() aufrufen. Weitere Informationen findest du unter App-Sprache konfigurieren und Permissions API.

Gesamte Aktivität mit dem neuen HomeClient aktualisieren

Sobald du eine neue HomeClient-Instanz hast, musst du die gesamte Aktivität aktualisieren, um das Abo wieder zu aktivieren und die vollständigen Gebäude, Geräte und anderen relevanten Daten abzurufen, die mit diesem Nutzerkonto verknüpft sind.

Registrierung von Eigenschaften und Gerätetypen

Mit der Klasse FactoryRegistry können Entwickler die Größe ihrer App-Binärdatei optimieren, indem sie explizit angeben, welche Eigenschaften und Gerätetypen von ihrer App verwendet werden.

Beachten Sie, dass Berechtigungen und die Factory Registry entkoppelt sind. Nicht registrierte Eigenschaften und Typen, die deiner App über Berechtigungen zur Verfügung stehen, aber nicht in der Factory-Registry enthalten sind, sind daher nicht über die Automation API zugänglich und werden auch nicht in den Bulk-Methodenaufrufen traits() oder types() zurückgegeben.

Gerätegruppen werden durch die Entität DeviceGroup dargestellt, die sich von HomeDevice unterscheidet. Wenn du Gerätegruppen abfragen und mit ihnen interagieren möchtest, füge DeviceGroup in die entityTypes-Liste ein, wenn du deine FactoryRegistry initialisierst, zusammen mit den Attributen Group, GroupManagement und GroupMembership.

Weitere Informationen finden Sie unter Gerätegruppen.

App-Sprache konfigurieren

Verwenden Sie setLocale() und getLocale() auf Ihrer HomeClient-Instanz, um die Spracheinstellung für Ihre App zu konfigurieren und abzurufen. Das Gebietsschema muss ein gültiges BCP-47-Sprach-Tag sein, z. B. "en-US", "en-GB" oder "ja".

Wenn du eine Sprache für HomeClient festlegst, verwenden die Home APIs diese Sprache für von Google gehostete UI-Abläufe, einschließlich der Berechtigungs-UI, der Matter-Inbetriebnahme und der Abläufe zum Entfernen von Geräten. Wenn Sie keine Sprache festlegen, wird für diese Abläufe standardmäßig die Sprache der App oder des Geräts verwendet.

  • Wenn Sie setLocale() aufrufen, bevor sich der Nutzer anmeldet und Berechtigungen gewährt, wird die Sprache im Arbeitsspeicher gespeichert und auf den ersten Berechtigungs-UI-Ablauf angewendet. Sobald sich der Nutzer anmeldet und ein Gebäude verfügbar ist, synchronisiert das SDK die Sprache mit der Cloud. Wenn der Nutzer bereits eine gespeicherte Spracheinstellung in der Cloud für Ihre App hat, hat die Cloud-Einstellung bei der ersten Synchronisierung Vorrang.
  • Wenn setLocale() aufgerufen wird, während der Nutzer angemeldet ist, wird die Sprache im Arbeitsspeicher aktualisiert und für diesen Nutzer und diese App in der Cloud gespeichert.
// Set the locale using a BCP-47 language tag
coroutineScope.launch {
  homeManager.setLocale("ja")
}

// Retrieve the configured locale, or null if not set
val currentLocale: String? = homeManager.getLocale()

Mit der Einstellung der bevorzugten Sprache pro App unter Android synchronisieren

Wenn Ihre App die Einstellung der bevorzugten Sprache pro App unter Android mit LocaleManager unterstützt, rufen Sie homeManager.setLocale() auf, bevor Sie LocaleManager.applicationLocales aktualisieren. Wenn Sie applicationLocales aktualisieren, wird die aktive Activity neu erstellt. Dadurch kann eine laufende Koroutine abgebrochen werden, wenn Sie danach setLocale() aufrufen.

coroutineScope.launch {
  val languageTag = "fr-CA"

  // 1. Persist the locale to HomeClient first
  homeManager.setLocale(languageTag)

  // 2. Update Android's per-app locale (recreates the Activity)
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    context.getSystemService(LocaleManager::class.java).applicationLocales =
      LocaleList.forLanguageTags(languageTag)
  }
}