Initialiser la maison sur Android

Avant d'utiliser l'une des API Home pour Android, vous devez initialiser la maison dans votre application. Dans cette étape, vous allez créer une instance singleton de Home pour le contexte local.

Une seule instance de Home doit être active à la fois.

Il s'agit du point d'entrée des API Home. Il s'agit également de déclarer les traits et les types d'appareils que vous comptez utiliser avec les API Device & Structure et Automation. Si vous débutez avec l'écosystème Google Home et que vous ne savez pas quels traits ou types d'appareils enregistrer, nous vous en avons suggéré quelques-uns des plus courants dans ce guide.

Créer une instance Home

Pour commencer, importez ces packages dans votre application :

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

Pour initialiser les API Home :

  1. Obtenez une référence au contexte Application. Ce contexte ne dépend d'aucun cycle de vie d'activité et restera actif tant que votre application le sera. Vous pouvez l'obtenir en appelant getApplicationContext() dans un Activity ou un Service :

    val context = getApplicationContext()
    
  2. Créez une instance FactoryRegistry avec tous les traits et types d'appareils que vous prévoyez d'utiliser dans votre application.

    Pour ce guide, nous avons suggéré quelques types d'appareils courants (types d'appareils Light, Plug, Sensor, Switch et Thermostat, traits Presence et Assistant pour les automatisations), au cas où vous ne sauriez pas ce dont vous avez besoin. Pour en savoir plus, consultez Enregistrement des traits et des types d'appareils.

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

    Les instructions d'importation pour chaque trait et type d'appareil enregistrés ici sont obligatoires (Android Studio devrait vous inviter à les ajouter).

  3. Instanciez un HomeConfig à l'aide du contexte de coroutine Dispatchers.IO et de votre instance de registre.

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. Enfin, créez l'instance singleton de Home, qui est le point d'entrée des API, à l'aide du contexte et de HomeConfig.

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

Pour éviter les erreurs liées à des sessions non valides, il est important de ne créer qu'une instance singleton de Home en l'encapsulant dans une déclaration d'objet.

Par exemple, l'application exemple procède comme suit :

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

Connexion à Google initiée par l'application

Vous pouvez gérer les authentifications Google de vos utilisateurs dans votre application. Cela vous permet d'utiliser le même compte utilisateur dans différents services Google tels que Google Home, Drive, Maps, etc.

Avec la connexion Google initiée par l'application, vous pouvez obtenir une instance HomeClient explicitement liée à un utilisateur spécifique, en contournant ainsi le sélecteur de compte Google et l'écran de consentement lorsque le compte est déjà autorisé.

Cette approche empêche également les utilisateurs de voir deux écrans de sélection de compte différents : l'un provenant de la connexion à l'application et l'autre de Google Home.

Pour ce faire, vous devez vous reporter à Authentifier les utilisateurs avec Se connecter avec Google et suivre les étapes suivantes :

Créer un ID client d'application Web OAuth

  1. Ouvrez la console Google Cloud.
    • Accédez à la page "Identifiants" de la console Google Cloud.
    • Sélectionnez un projet existant ou créez-en un.
  2. Configurer l'écran de consentement OAuth (si ce n'est pas déjà fait)
    • Avant de créer des identifiants, assurez-vous que l'écran de consentement OAuth est configuré avec les informations de votre application, y compris les URL des règles de confidentialité et des conditions d'utilisation.
  3. Créer un ID client OAuth (type "Application Web")
    • Sur la page "Identifiants", cliquez sur + CREATE CREDENTIALS, puis sélectionnez ID client OAuth dans le menu déroulant.
    • Dans le champ Type d'application, sélectionnez Application Web.
    • Saisissez un nom pour votre client Web (par exemple, "My App Web Backend").
    • Cliquez sur Créer.
  4. Récupérer l'ID client
    • Une fois l'ID client créé, la console l'affiche. Il s'agit de la valeur que vous utiliserez dans votre application Android (par exemple, {project number}-.....apps.googleusercontent.com).
    • Nous vous recommandons de stocker l'ID client en externe (par exemple, dans build.gradle) plutôt que de le coder en dur directement.

Instancier une requête Google Sign-In

Utilisez l'ID de l'application Web pour créer une demande de connexion 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()

Créer le flux Se connecter avec Google

Pour implémenter le flux de connexion, utilisez CredentialManager pour exécuter une requête Sign in with Google. Une fois que l'utilisateur a sélectionné un compte, extrayez son adresse e-mail du jeton d'identité Google obtenu pour créer un android.accounts.Account. Ce compte est ensuite utilisé pour initialiser une instance HomeClient spécifiquement liée à cet utilisateur connecté.

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

Obtenir une nouvelle instance HomeClient

Suivez les mêmes étapes que celles décrites dans Créer une instance Home, mais au lieu d'appeler Home.getClient(context, homeConfig) à l'étape 4, appelez Home.getClient(context, userAccount, homeConfig), où le deuxième paramètre est un Lazy<UserAccount>. Cela renvoie une instance de HomeClientWithProvidedAccount, une sous-classe de HomeClient, qui est explicitement liée au compte Google spécifié :

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

Si l'utilisateur spécifié n'est pas autorisé, demandez-lui son autorisation en appelant les méthodes suivantes sur l'instance HomeClientWithProvidedAccount :

  1. registerActivityResultCallerForPermissions() avec une référence à l'ActivityResultCaller que vous souhaitez utiliser.
  2. requestPermissions(). L'écran de consentement GHP s'affiche, permettant à l'utilisateur d'accorder son autorisation.

Vous pouvez créer un HomeClient avec un UserAccount, puis appeler requestPermissions() avec forceLaunch==true pour relancer l'écran d'autorisation et permettre à l'utilisateur de mettre à jour les autorisations qu'il a accordées :

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

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

Pour en savoir plus sur la gestion des autorisations des API Home, consultez la section API Permissions.

Actualiser l'ensemble de l'activité avec le nouveau HomeClient

Une fois que vous disposez d'une nouvelle instance HomeClient, vous devez actualiser l'intégralité de l'activité pour vous réabonner et récupérer les structures, les appareils et les autres données pertinentes associés à ce compte utilisateur.

Enregistrement des caractéristiques et des types d'appareils

La classe FactoryRegistry aide les développeurs à optimiser la taille du binaire de leur application en leur permettant d'indiquer explicitement les caractéristiques et les types d'appareils utilisés par leur application.

Notez que les autorisations et le registre d'usine sont dissociés. Par conséquent, les traits et types non enregistrés qui sont disponibles pour votre application à l'aide d'autorisations, mais qui ne sont pas inclus dans le registre d'usine, sont inaccessibles à l'aide de l'API Automation. Ils ne sont pas non plus renvoyés dans les appels de méthode traits() ou types() groupés.