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 a declaração de 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 o 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. Acesse uma referência ao Application contexto. Esse contexto não depende de nenhum ciclo de vida da atividade e vai existir enquanto o app estiver ativo. Você pode acessá-lo chamando getApplicationContext() em uma Activity ou Service:

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

    Para este guia, sugerimos alguns comuns (tipos de dispositivos de iluminação, plugue, sensor, interruptor e termostato, características 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))
    

    As instruções de importação para cada característica e tipo de dispositivo registrado aqui são obrigatórias (Android Studio vai pedir que você as adicione).

  3. Instancie um HomeConfig usando o Dispatchers.IO contexto de corrotina e a instância do 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 assim por diante.

Com o login do Google iniciado pelo app, é possível receber uma instância HomeClient explicitamente vinculada a um usuário específico, ignorando o seletor de contas do Google e a tela de permissão quando a conta já está autorizada.

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

Para fazer isso, consulte Autenticar usuários com o recurso "Fazer login com o Google" e conclua as etapas a seguir:

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 os URLs da política de privacidade e dos Termos de Serviço.
  3. Criar um ID do cliente OAuth (tipo de 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 o cliente da Web (por exemplo, "Back-end da Web do meu app").
    • Clique em "Criar".
  4. Recuperar o ID do cliente
    • Após a criação, o console vai mostrar o novo ID do cliente. Este é o valor que você vai usar no app Android (por exemplo, "{project number}-.....apps.googleusercontent.com")
    • Recomendamos que você armazene o ID do cliente 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 do token de ID do Google resultante para criar uma android.accounts.Account. Essa conta é usada para inicializar uma instância HomeClient especificamente vinculada ao 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 de 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 HomeClientWithProvidedAccount instância:

  1. registerActivityResultCallerForPermissions() com uma referência ao ActivityResultCaller que você quer usar.
  2. requestPermissions(). Isso abre a tela de permissão 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 permissão novamente 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 as permissões das APIs Home.

Atualizar toda a atividade com o novo HomeClient

Depois de ter uma nova instância HomeClient, é necessário atualizar toda a atividade para se inscrever novamente e buscar as estruturas, os dispositivos e outros dados relevantes 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 do 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, as características e os tipos não registrados que estão disponíveis para o 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().