Inicjowanie domu na urządzeniu z Androidem

Zanim zaczniesz używać interfejsów Home API na Androidzie, musisz zainicjować dom w aplikacji. W tym kroku utworzysz instancję singleton klasy Home dla kontekstu lokalnego.

W danym momencie aktywna może być tylko jedna instancja Home.

Jest to punkt wejścia do interfejsów Home API. Wymaga też zadeklarowania, których cech i typów urządzeń zamierzasz używać w interfejsach Device & Structure API i Automation API. Jeśli dopiero zaczynasz korzystać z ekosystemu Google Home i nie wiesz, jakie cechy lub typy urządzeń zarejestrować, w tym przewodniku znajdziesz kilka najpopularniejszych propozycji.

Tworzenie instancji Home

Aby zacząć, zaimportuj te pakiety do aplikacji:

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

Aby zainicjować interfejsy Home API:

  1. Uzyskaj odniesienie do Application kontekstu. Ten kontekst nie zależy od cyklu życia żadnej aktywności i będzie istniał tak długo, jak długo działa aplikacja. Możesz go uzyskać, dzwoniąc pod numer getApplicationContext()Activity lub Service:

    val context = getApplicationContext()
    
  2. Utwórz instancję FactoryRegistry ze wszystkimi cechami i typami urządzeń, których chcesz używać w aplikacji.

    W tym przewodniku proponujemy kilka typowych (typy urządzeń: światło, gniazdko, czujnik, przełącznik i termostat; cechy obecności i Asystenta w przypadku automatyzacji), jeśli nie masz pewności, czego potrzebujesz. Więcej informacji znajdziesz w artykule Rejestracja cech i typów urządzeń.

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

    Wymagane są instrukcje importu dla każdego zarejestrowanego tutaj pojedynczego atrybutu i typu urządzenia (Android Studio powinien wyświetlić prośbę o ich dodanie).

  3. Utwórz instancję HomeConfig za pomocą kontekstu korutyny Dispatchers.IO i instancji rejestru.

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. Na koniec utwórz instancję singletonu Home, która jest punktem wejścia do interfejsów API, używając kontekstu i HomeConfig.

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

Aby uniknąć błędów związanych z nieprawidłowymi sesjami, ważne jest, aby utworzyć tylko jedną instancję Home, umieszczając ją w deklaracji obiektu.

Na przykład aplikacja przykładowa robi to w ten sposób:

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

Logowanie przez Google inicjowane przez aplikację

Możesz zarządzać uwierzytelnianiem użytkowników w Google w ramach swojej aplikacji. Dzięki temu użytkownicy mogą korzystać z tego samego konta w różnych usługach Google, takich jak Google Home, Dysk, Mapy itp.

Dzięki logowaniu przez Google inicjowanemu przez aplikację możesz uzyskać instancję HomeClient wyraźnie powiązaną z określonym użytkownikiem, co pozwala pominąć selektor kont Google i ekran zgody, gdy konto jest już autoryzowane.

Dodatkowo to podejście zapobiega wyświetlaniu użytkownikom dwóch różnych ekranów wyboru konta – jednego z logowania w aplikacji i jednego z Google Home.

Aby to zrobić, zapoznaj się z artykułem Uwierzytelnianie użytkowników za pomocą logowania przez Google i wykonaj te czynności:

Tworzenie identyfikatora klienta aplikacji internetowej OAuth

  1. Otwórz konsolę Google Cloud.
    • Otwórz stronę Dane logowania w konsoli Google Cloud.
    • Wybierz istniejący projekt lub utwórz nowy.
  2. Skonfiguruj ekran zgody OAuth (jeśli jeszcze tego nie zrobiono).
    • Zanim utworzysz dane logowania, upewnij się, że ekran akceptacji OAuth jest skonfigurowany z danymi aplikacji, w tym adresami URL polityki prywatności i warunków korzystania z usługi.
  3. Utwórz identyfikator klienta OAuth (typ aplikacji internetowej).
    • Na stronie Dane logowania kliknij + CREATE CREDENTIALS i z menu wybierz Identyfikator klienta OAuth.
    • Jako Typ aplikacji wybierz Aplikacja internetowa.
    • Wpisz nazwę klienta internetowego (np. „My App Web Backend”).
    • Kliknij Utwórz.
  4. Pobieranie identyfikatora klienta
    • Po utworzeniu identyfikator klienta pojawi się w konsoli. Jest to wartość, której będziesz używać w aplikacji na Androida (np. „{project number}-.....apps.googleusercontent.com”).
    • Zalecamy przechowywanie identyfikatora klienta na zewnątrz (np.w build.gradle) zamiast bezpośredniego kodowania go na stałe.

Utwórz instancję żądania logowania się przez Google

Użyj identyfikatora aplikacji internetowej, aby utworzyć żądanie logowania przez 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()

Tworzenie procedury logowania się przez Google

Aby wdrożyć proces logowania, użyj CredentialManager do wykonania żądania Sign in with Google. Gdy użytkownik wybierze konto, wyodrębnij jego adres e-mail z otrzymanego tokena identyfikatora Google, aby utworzyć android.accounts.Account. To konto jest następnie używane do inicjowania instancji HomeClient powiązanej z tym zalogowanym użytkownikiem.

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

Uzyskiwanie nowej instancji HomeClient

Wykonaj te same czynności, które opisano w sekcji Tworzenie instancji Home, ale zamiast wywoływać Home.getClient(context, homeConfig) w kroku 4, wywołaj Home.getClient(context, userAccount, homeConfig), gdzie drugi parametr to Lazy<UserAccount>. Zwraca to instancję klasy HomeClientWithProvidedAccount, podklasy klasy HomeClient, która jest wyraźnie powiązana z określonym kontem 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()
     )

Jeśli określony użytkownik nie jest autoryzowany, poproś go o zezwolenie, wywołując te metody w instancji HomeClientWithProvidedAccount:

  1. registerActivityResultCallerForPermissions() z odwołaniem do interfejsu ActivityResultCaller, którego chcesz użyć.
  2. requestPermissions() Wyświetli się ekran zgody platformy GHP, na którym użytkownik może wyrazić zgodę.

Możesz utworzyć HomeClient za pomocą UserAccount, a następnie wywołać requestPermissions()forceLaunch==true, aby ponownie wyświetlić ekran zgody i umożliwić użytkownikowi zaktualizowanie przyznanych uprawnień:

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

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

Więcej informacji o zarządzaniu uprawnieniami interfejsów API Home znajdziesz w artykule Interfejs API uprawnień.

Odśwież całą aktywność za pomocą nowego HomeClient

Gdy uzyskasz nową instancję HomeClient, musisz odświeżyć całą aktywność, aby ponownie zasubskrybować i pobrać pełne struktury, urządzenia i inne istotne dane powiązane z tym kontem użytkownika.

Rejestracja cech i typów urządzeń

Klasa FactoryRegistry pomaga deweloperom optymalizować rozmiar pliku binarnego aplikacji, umożliwiając im wyraźne wskazanie, które cechy i typy urządzeń są używane przez aplikację.

Pamiętaj, że uprawnienia i rejestr fabryczny są od siebie niezależne. Dlatego niezarejestrowane cechy i typy, które są dostępne dla aplikacji za pomocą uprawnień, ale nie są uwzględnione w rejestrze fabrycznym, są niedostępne za pomocą interfejsu Automation API ani nie są zwracane w wywołaniach metod zbiorczych traits() ani types().