Прежде чем использовать Home API для Android, необходимо инициализировать дом в приложении. На этом шаге вы создадите одиночный экземпляр Home для локального контекста.
Одновременно может быть активен только один экземпляр Home.
Это точка входа в Home API. Здесь также нужно указать, какие функции и типы устройств вы планируете использовать с Device & Structure API и Automation API. Если вы только начинаете работать с экосистемой Google Home и не знаете, какие типы устройств и функции нужно зарегистрировать, в этом руководстве вы найдете несколько наиболее распространенных вариантов.
Как создать дом
Для начала импортируйте в приложение следующие пакеты:
import android.content.Context
import com.google.home.FactoryRegistry
import com.google.home.HomeConfig
import com.google.home.Home
Чтобы инициализировать Home API:
Получите ссылку на контекст
Application. Этот контекст не зависит от жизненного цикла объекта activity и будет существовать, пока работает приложение. Его можно получить, вызвав методgetApplicationContext()вActivityилиService:val context = getApplicationContext()Создайте экземпляр
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 предложит вам добавить их).
Создайте экземпляр
HomeConfig, используя контекст сопрограммыDispatchers.IOи экземпляр реестра.val homeConfig = HomeConfig( coroutineContext = Dispatchers.IO, factoryRegistry = registry)Наконец, создайте экземпляр singleton для
Home, который является точкой входа в API, используя контекст иHomeConfig.val homeManager: HomeClient = Home.getClient(context, homeConfig)
Чтобы избежать ошибок, связанных с недействительными сеансами, важно создать только один экземпляр singleton 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, инициированном приложением, вы можете получить экземпляр HomeClient, явно связанный с определенным пользователем. Это позволяет обойти окно выбора аккаунта Google и окно запроса доступа, если аккаунт уже авторизован.
Кроме того, пользователям не придется выбирать аккаунт дважды – в приложении и в Google Home.
Для этого ознакомьтесь с разделом Аутентификация пользователей с помощью функции "Войти с аккаунтом Google" и выполните следующие действия:
Как создать идентификатор клиента веб-приложения OAuth
- Откройте консоль Google Cloud.
- Перейдите на страницу учетных данных в консоли Google Cloud.
- Выберите существующий проект или создайте новый.
- Настройте окно запроса доступа OAuth (если вы ещё этого не сделали).
- Прежде чем создавать учетные данные, убедитесь, что в окне запроса доступа OAuth указаны сведения о вашем приложении, включая URL политики конфиденциальности и условий использования.
- Создайте идентификатор клиента OAuth (тип "Веб-приложение").
- На странице "Учетные данные" нажмите
+ CREATE CREDENTIALSи в раскрывающемся меню выберите Идентификатор клиента OAuth. - Для параметра Application type (Тип приложения) выберите Web application (Веб-приложение).
- Введите название веб-клиента, например "Бэкенд моего приложения".
- Нажмите Create (Создать).
- На странице "Учетные данные" нажмите
- Получите идентификатор клиента.
- После создания в консоли появится новый идентификатор клиента. Это значение вы будете использовать в своем приложении для Android (например, {project number}-.....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, чтобы создать 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:
registerActivityResultCallerForPermissions()со ссылкой на нужный объект ActivityResultCaller.requestPermissions(). Откроется окно запроса доступа к Google Health Platform, в котором пользователь может предоставить разрешение.
Вы можете создать HomeClient с помощью UserAccount, а затем вызвать requestPermissions(), задав для forcePermissionFlow значение ForcePermissionFlow.FORCE_LAUNCH, чтобы снова запустить окно запроса доступа и позволить пользователю изменить разрешения.
val client =
Home.getClient(
context = context.applicationContext,
account =
lazy {
UserAccount.GoogleAccount(androidAccount)
},
homeConfig = HomeConfig()
)
client.registerActivityResultCallerForPermissions(this)
client.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH)
Подробнее о том, как управлять разрешениями Home API, рассказывается в статье Permissions API.
Обновите все действия с помощью нового HomeClient
После создания нового экземпляра HomeClient необходимо обновить все действия, чтобы возобновить подписку и получить полные структуры, устройства и другие соответствующие данные, связанные с этим аккаунтом пользователя.
Регистрация характеристик и типов устройств
Класс FactoryRegistry помогает разработчикам оптимизировать размер двоичного файла приложения, позволяя им явно указывать, какие характеристики и типы устройств используются в их приложении.
Обратите внимание, что разрешения и реестр фабрики не связаны. Поэтому незарегистрированные типажи и типы, доступные вашему приложению через разрешения, но не включенные в реестр фабрики, недоступны через Automation API и не возвращаются при массовых вызовах методов traits() или types().