Инициализировать дом на Android

Прежде чем использовать какие-либо API Home для Android, необходимо инициализировать Home в вашем приложении. На этом шаге вы создадите единственный экземпляр Home для локального контекста.

В любой момент времени должен быть активен только один экземпляр Home .

Это точка входа в API Home, а также указание характеристик и типов устройств, которые вы планируете использовать с API Device & Structure и Automation. Если вы только начинаете работать с экосистемой Google Home и не уверены, какие характеристики или типы устройств нужно зарегистрировать, в этом руководстве мы предложили несколько наиболее распространенных вариантов.

Создайте экземпляр Home.

Для начала импортируйте следующие пакеты в ваше приложение:

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

Для инициализации API Home:

  1. Получите ссылку на контекст Application . Этот контекст не зависит от жизненного цикла какой-либо активности и будет существовать до тех пор, пока ваше приложение работает. Вы можете получить его, вызвав getApplicationContext() внутри Activity или Service :

    val context = getApplicationContext()
    
  2. Создайте экземпляр FactoryRegistry со всеми характеристиками и типами устройств, которые вы планируете использовать в своем приложении.

    В этом руководстве мы предложили несколько распространенных типов устройств (светильник, розетка, датчик, выключатель и термостат, а также характеристики присутствия и данные голосового помощника для автоматизации), на случай, если вы не уверены, что именно вам нужно. Для получения дополнительной информации см. раздел «Регистрация характеристик и типов устройств» .

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

    Для каждого отдельного признака и типа устройства, зарегистрированных здесь, необходимы операторы импорта ( Android Studio предложит вам добавить их).

  3. Создайте экземпляр HomeConfig , используя контекст сопрограммы Dispatchers.IO и ваш экземпляр реестра.

    val homeConfig = HomeConfig(
            coroutineContext = Dispatchers.IO,
            factoryRegistry = registry)
    
  4. Наконец, создайте единственный экземпляр класса Home , который является точкой входа в API, используя контекст и HomeConfig .

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

Во избежание ошибок, связанных с недействительными сессиями, важно, чтобы создавался только единственный экземпляр класса Home , заключенный в объявление объекта .

Например, в демонстрационном приложении это делается следующим образом:

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

Вход в систему Google, инициированный приложением.

Возможно, вам потребуется управлять аутентификацией пользователей Google внутри вашего приложения. Это позволит использовать одну и ту же учетную запись пользователя в различных сервисах Google, таких как Google Home, Google Drive, Google Maps и так далее.

При использовании входа в систему Google, инициируемого приложением, вы можете получить экземпляр HomeClient явно привязанный к конкретному пользователю, тем самым минуя выбор учетной записи Google и экран подтверждения согласия, когда учетная запись уже авторизована.

Кроме того, такой подход предотвращает отображение пользователями двух разных экранов выбора учетной записи — одного при входе в приложение и другого на Google Home.

Для этого необходимо перейти к разделу «Аутентификация пользователей с помощью входа через Google» и выполнить следующие шаги:

Создайте идентификатор клиента веб-приложения OAuth.

  1. Откройте консоль Google Cloud.
    • Перейдите на страницу «Учетные данные консоли Google Cloud».
    • Выберите существующий проект или создайте новый.
  2. Настройте экран согласия OAuth (если вы этого еще не сделали).
    • Перед созданием учетных данных убедитесь, что экран согласия OAuth настроен с указанием данных вашего приложения, включая URL-адреса политики конфиденциальности и условий использования.
  3. Создайте идентификатор клиента OAuth (тип веб-приложения).
    • На странице «Учетные данные» нажмите кнопку + CREATE CREDENTIALS и выберите «Идентификатор клиента OAuth» из выпадающего меню.
    • В поле «Тип приложения» выберите «Веб-приложение» .
    • Введите имя для вашего веб-клиента (например, "My App Web Backend").
    • Нажмите «Создать».
  4. Получите идентификатор клиента.
    • После создания в консоли отобразится ваш новый идентификатор клиента (Client ID). Это значение вы будете использовать в своем Android-приложении (например, " {номер проекта}-.....apps.googleusercontent.com ")
    • Рекомендуется хранить идентификатор клиента во внешнем хранилище (например, в build.gradle ), а не прописывать его напрямую в коде.

Инициировать запрос на вход через Google.

Используйте идентификатор веб-приложения для создания запроса на вход через 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()

Создайте процесс авторизации через Google.

Для реализации процесса авторизации используйте CredentialManager для выполнения запроса Sign in with Google . После того, как пользователь выберет учетную запись, извлеките его адрес электронной почты из полученного токена Google ID, чтобы создать объект android.accounts.Account . Затем эта учетная запись используется для инициализации экземпляра HomeClient специально привязанного к авторизованному пользователю.

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

Получить новый экземпляр HomeClient

Выполните те же шаги, что и в разделе «Создание экземпляра Home» , но вместо вызова Home.getClient(context, homeConfig) на шаге 4 вызовите Home.getClient(context, userAccount, homeConfig) , где вторым параметром является Lazy<UserAccount> . Это вернет экземпляр HomeClientWithProvidedAccount , подкласса HomeClient , явно привязанного к указанной учетной записи 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()
     )

Если указанный пользователь не авторизован, запросите у него разрешение, вызвав следующие методы экземпляра HomeClientWithProvidedAccount :

  1. При вызове registerActivityResultCallerForPermissions() укажите ссылку на ActivityResultCaller , который вы хотите использовать.
  2. Вызов requestPermissions() открывает экран согласия GHP, где пользователь может предоставить свои разрешения.

Вы можете создать HomeClient с UserAccount , а затем вызвать requestPermissions() с forceLaunch==true чтобы снова запустить экран согласия и позволить пользователю обновить предоставленные ему разрешения:

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

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

Дополнительную информацию об управлении разрешениями API Home см. в разделе «API разрешений» .

Обновите всю активность с помощью нового HomeClient.

После создания нового экземпляра HomeClient необходимо обновить всю активность, чтобы повторно подписаться и получить все структуры, устройства и другие соответствующие данные, связанные с этой учетной записью пользователя.

Регистрация характеристик и типов устройств

Класс FactoryRegistry помогает разработчикам оптимизировать размер исполняемого файла приложения, позволяя им явно указывать, какие характеристики и типы устройств используются их приложением.

Обратите внимание, что разрешения и реестр фабрик не связаны между собой. Поэтому незарегистрированные трейты и типы, доступные вашему приложению с помощью разрешений, но не включенные в реестр фабрик, недоступны с помощью API автоматизации и не возвращаются в вызовах методов bulk traits() или types() .