Inicializar a casa no Android

Antes de usar qualquer uma das APIs Home para Android, é necessário inicializar a casa no app. Nesta etapa, você vai criar uma instância singleton de Home para o contexto local.

Apenas uma instância de Home pode estar ativa por vez.

Esse é o ponto de entrada para as APIs Home e também envolve declarar quais características e tipos de dispositivos você pretende usar com as APIs Device & Structure e Automation. Se você está começando a usar o ecossistema do Google Home e não sabe quais características ou tipos de dispositivos registrar, sugerimos alguns dos mais comuns neste guia.

Criar uma instância de casa

Para começar, importe estes pacotes para seu app:

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

Para inicializar as APIs Home:

  1. Receba uma referência ao contexto Application. Esse contexto não depende de nenhum ciclo de vida de atividade e vai existir enquanto o app estiver ativo. Para isso, chame getApplicationContext() em um Activity ou Service:

    val context = getApplicationContext()
    
  2. Crie uma instância FactoryRegistry com todas as características e tipos de dispositivos que você pretende usar no app.

    Neste guia, sugerimos alguns comuns (tipos de dispositivos de luz, plugue, sensor, interruptor e termostato, além de traços de presença e do Google Assistente para automações), caso você não saiba o que precisa. Para saber mais, consulte Registro de características e tipos de dispositivos.

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

    São necessárias instruções de importação para cada característica individual e tipo de dispositivo registrado aqui. O Android Studio vai pedir que você adicione essas informações.

  3. Instancie um HomeConfig usando o contexto de corrotina Dispatchers.IO e sua instância de registro.

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. Por fim, crie a instância singleton de Home, que é o ponto de entrada para as APIs, usando o contexto e o HomeConfig.

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

Para evitar erros com sessões inválidas, é importante que apenas uma instância singleton de Home seja criada, envolvendo-a em uma declaração de objeto.

Por exemplo, o app de amostra faz isso desta forma:

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

Login do Google iniciado pelo app

Talvez você queira gerenciar as autenticações do Google do usuário no seu app. Isso permite usar a mesma conta de usuário em vários serviços do Google, como Google Home, Drive, Maps e outros.

Com o login do Google iniciado pelo app, você pode receber uma instância HomeClient explicitamente vinculada a um usuário específico, ignorando o seletor de Conta do Google e a tela de consentimento quando a conta já está autorizada.

Além disso, essa abordagem impede que os usuários vejam duas telas diferentes de seleção de conta: uma do login do app e outra do Google Home.

Para isso, consulte Autenticar usuários com o recurso Fazer login com o Google e siga estas etapas:

Criar um ID do cliente do aplicativo da Web OAuth

  1. Abra o console do Google Cloud
    • Acesse a página "Credenciais" do Console do Google Cloud.
    • Selecione um projeto atual ou crie um novo.
  2. Configure a tela de permissão OAuth (se ainda não tiver feito isso)
    • Antes de criar credenciais, verifique se a tela de permissão OAuth está configurada com os detalhes do app, incluindo URLs da Política de Privacidade e dos Termos de Serviço.
  3. Crie um ID do cliente OAuth (tipo "Aplicativo da Web")
    • Na página "Credenciais", clique em + CREATE CREDENTIALS e selecione ID do cliente OAuth no menu suspenso.
    • Em Tipo de aplicativo, selecione Aplicativo da Web.
    • Insira um nome para seu cliente da Web (por exemplo, "My App Web Backend").
    • Clique em "Criar".
  4. Recuperar o ID do cliente
    • Depois da criação, o console vai mostrar seu novo ID do cliente. Esse é o valor que você vai usar no seu aplicativo Android (por exemplo, "{project number}-.....apps.googleusercontent.com")
    • Recomendamos que você armazene o Client-ID externamente (por exemplo, em build.gradle) em vez de codificá-lo diretamente.

Instanciar uma solicitação de Login do Google

Use o ID do app da Web para criar uma solicitação de login do 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()

Criar o fluxo "Fazer login com o Google"

Para implementar o fluxo de login, use CredentialManager para executar uma solicitação Sign in with Google. Depois que o usuário selecionar uma conta, extraia o e-mail dele do token de ID do Google resultante para criar um android.accounts.Account. Essa conta é usada para inicializar uma instância HomeClient especificamente vinculada a esse usuário conectado.

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

Receber uma nova instância do HomeClient

Siga as mesmas etapas descritas em Criar uma instância de casa, mas em vez de chamar Home.getClient(context, homeConfig) na etapa 4, chame Home.getClient(context, userAccount, homeConfig), em que o segundo parâmetro é um Lazy<UserAccount>. Isso retorna uma instância de HomeClientWithProvidedAccount, uma subclasse de HomeClient, que está explicitamente vinculada à Conta do Google especificada:

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

Se o usuário especificado não estiver autorizado, peça permissão chamando os seguintes métodos na instância HomeClientWithProvidedAccount:

  1. registerActivityResultCallerForPermissions() com uma referência ao ActivityResultCaller que você quer usar.
  2. requestPermissions(). Isso abre a tela de consentimento do GHP, em que o usuário pode conceder a permissão.

É possível criar um HomeClient com um UserAccount e chamar requestPermissions() com forceLaunch==true para iniciar a tela de consentimento de novo e permitir que o usuário atualize a concessão de permissões:

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

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

Consulte a API Permissions para mais informações sobre como gerenciar permissões das APIs Home.

Atualize toda a atividade com o novo HomeClient

Depois de ter uma nova instância HomeClient, atualize toda a atividade para se inscrever novamente e buscar as estruturas, os dispositivos e outros dados pertinentes completos associados a essa conta de usuário.

Registro de características e tipos de dispositivos

A classe FactoryRegistry ajuda os desenvolvedores a otimizar o tamanho binário do app, permitindo que eles indiquem explicitamente quais características e tipos de dispositivos são usados pelo app.

As permissões e o registro de fábrica são separados. Portanto, características e tipos não registrados que estão disponíveis para seu app usando permissões, mas não incluídos no registro de fábrica, não podem ser acessados usando a API Automation nem são retornados nas chamadas de método em massa traits() ou types().