Android용 Home API를 사용하기 전에 앱에서 홈을 초기화해야 합니다. 이 단계에서는 로컬 컨텍스트에 싱글톤 인스턴스인 Home를 만듭니다.
한 번에 하나의 Home 인스턴스만 활성화해야 합니다.
이는 Home API의 진입점이며, 기기 및 구조와 자동화 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또는Service내에서getApplicationContext()를 호출하여 가져올 수 있습니다.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에서 이를 추가하라는 메시지를 표시해야 함).
Dispatchers.IO코루틴 컨텍스트와 레지스트리 인스턴스를 사용하여HomeConfig를 인스턴스화합니다.val homeConfig = HomeConfig( coroutineContext = Dispatchers.IO, factoryRegistry = registry)마지막으로 컨텍스트와
HomeConfig를 사용하여 API의 진입점인Home의 싱글톤 인스턴스를 만듭니다.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 Home, Drive, 지도 등 다양한 Google 서비스에서 동일한 사용자 계정을 사용할 수 있습니다.
앱 시작 Google 로그인을 사용하면 특정 사용자에게 명시적으로 연결된 HomeClient 인스턴스를 획득하여 계정이 이미 승인된 경우 Google 계정 선택기와 동의 화면을 우회할 수 있습니다.
또한 이 접근 방식을 사용하면 사용자가 두 개의 서로 다른 계정 선택 화면(앱의 로그인 화면과 Google Home의 화면)을 보지 않아도 됩니다.
이렇게 하려면 Google 로그인을 사용하여 사용자 인증을 참고하고 다음 단계를 완료해야 합니다.
OAuth 웹 애플리케이션 클라이언트 ID 만들기
- Google Cloud 콘솔을 엽니다.
- Google Cloud 콘솔 사용자 인증 정보 페이지로 이동합니다.
- 기존 프로젝트를 선택하거나 새 프로젝트를 만듭니다.
- OAuth 동의 화면 구성 (아직 구성하지 않은 경우)
- 사용자 인증 정보를 만들기 전에 개인정보처리방침 및 서비스 약관 URL을 비롯한 앱 세부정보로 OAuth 동의 화면이 구성되어 있는지 확인하세요.
- OAuth 클라이언트 ID (웹 애플리케이션 유형) 만들기
- 사용자 인증 정보 페이지에서
+ CREATE CREDENTIALS를 클릭하고 드롭다운 메뉴에서 OAuth 클라이언트 ID를 선택합니다. - 애플리케이션 유형으로 웹 애플리케이션을 선택합니다.
- 웹 클라이언트의 이름을 입력합니다 (예: '내 앱 웹 백엔드')을 사용합니다.
- '만들기'를 클릭합니다.
- 사용자 인증 정보 페이지에서
- 클라이언트 ID 가져오기
- 생성 후 콘솔에 새 클라이언트 ID가 표시됩니다. Android 애플리케이션에서 사용할 값입니다 (예: '{project number}-.....apps.googleusercontent.com').
- 클라이언트 ID는 직접 하드코딩하는 대신 외부(예:
build.gradle)에 저장하는 것이 좋습니다.
Google 로그인 요청 인스턴스화
웹 앱 ID를 사용하여 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 인스턴스 가져오기
홈 인스턴스 만들기에 설명된 것과 동일한 단계를 따르되 4단계에서 Home.getClient(context, homeConfig)를 호출하는 대신 두 번째 매개변수가 Lazy<UserAccount>인 Home.getClient(context, userAccount,
homeConfig)를 호출합니다. 그러면 지정된 Google 계정에 명시적으로 연결된 HomeClient의 하위 클래스인 HomeClientWithProvidedAccount의 인스턴스가 반환됩니다.
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 인스턴스에서 다음 메서드를 호출하여 사용자에게 권한을 요청합니다.
- 사용하려는 ActivityResultCaller를 참조하는
registerActivityResultCallerForPermissions() requestPermissions()을 호출합니다. 그러면 사용자가 권한을 부여할 수 있는 GHP 동의 화면이 표시됩니다.
UserAccount로 HomeClient를 만든 다음 forceLaunch==true로 requestPermissions()를 호출하여 동의 화면을 다시 실행하면 사용자가 권한 부여를 업데이트할 수 있습니다.
val client =
Home.getClient(
context = context.applicationContext,
account =
lazy {
UserAccount.GoogleAccount(androidAccount)
},
homeConfig = HomeConfig()
)
client.registerActivityResultCallerForPermissions(this)
client.requestPermissions(forceLaunch= true)
Home API 권한 관리에 관한 자세한 내용은 Permissions API를 참고하세요.
새 HomeClient로 전체 활동 새로고침
새 HomeClient 인스턴스가 있으면 전체 활동을 새로고침하여 이 사용자 계정과 연결된 전체 구조, 기기, 기타 관련 데이터를 다시 구독하고 가져와야 합니다.
특성 및 기기 유형 등록
FactoryRegistry 클래스를 사용하면 개발자가 앱에서 사용하는 특성과 기기 유형을 명시적으로 표시하여 앱 바이너리 크기를 최적화할 수 있습니다.
권한과 팩토리 레지스트리는 분리되어 있습니다. 따라서 권한을 사용하여 앱에서 사용할 수 있지만 팩토리 레지스트리에 포함되지 않은 등록되지 않은 특성과 유형은 자동화 API를 사용하여 액세스할 수 없으며 대량 traits() 또는 types() 메서드 호출에서 반환되지도 않습니다.