Android용 Home API를 사용하려면 먼저 앱
에서 홈을 초기화해야 합니다. 이 단계에서는 로컬 컨텍스트에 대해 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또는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 호스팅 UI 흐름을 특정 언어로 렌더링하려면 권한을 요청하기 전에 HomeClient 인스턴스에서 setLocale()를 호출하세요. 자세한 내용은 앱 언어 구성을 참고하세요.
앱에서 시작하는 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)를 호출하는 대신 Home.getClient(context, userAccount,
homeConfig)를 호출합니다. 여기서 두 번째 매개변수는 Lazy<UserAccount>입니다. 그러면 지정된 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 인스턴스에서 다음 메서드를 호출하여 사용자에게 권한을 요청합니다.
registerActivityResultCallerForPermissions(): 사용하려는 ActivityResultCaller의 참조requestPermissions(). 그러면 사용자가 권한을 부여할 수 있는 GHP 동의 화면이 표시됩니다.
UserAccount를 사용하여 HomeClient를 만든 다음 forcePermissionFlow를 ForcePermissionFlow.FORCE_LAUNCH로 설정하여 requestPermissions()를 호출하면 동의 화면을 다시 실행하여 사용자가 권한 부여를 업데이트하도록 할 수 있습니다.
val client =
Home.getClient(
context = context.applicationContext,
account =
lazy {
UserAccount.GoogleAccount(androidAccount)
},
homeConfig = HomeConfig()
)
client.registerActivityResultCallerForPermissions(this)
client.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH)
동의 화면을 특정 언어로 표시하려면 requestPermissions()를 호출하기 전에 client.setLocale()를 호출하세요. 자세한 내용은 앱 언어 구성을 참고하고, Home API 권한 관리에 관한 자세한 내용은 Permissions API를 참고하세요.
새 HomeClient로 전체 활동 새로고침
새 HomeClient 인스턴스가 있으면 전체 활동을 새로고침하여 다시 구독하고 이 사용자 계정과 연결된 전체 집, 기기, 기타 관련 데이터를 가져와야 합니다.
특성 및 기기 유형 등록
FactoryRegistry 클래스는 개발자가 앱에서 사용하는 특성과 기기 유형을 명시적으로 나타내도록 하여 앱 바이너리 크기를 최적화하는 데 도움이 됩니다.
권한과 팩토리 레지스트리는 분리되어 있습니다. 따라서 권한을 사용하여 앱에서 사용할 수 있지만 팩토리 레지스트리에 포함되지 않은 등록되지 않은 특성 및 유형은 Automation API를 사용하여 액세스할 수 없으며 일괄 traits() 또는 types() 메서드 호출에서 반환되지 않습니다.
DeviceGroup 항목으로 표현되며, 이는 HomeDevice와 다릅니다. 기기 그룹을 쿼리하고 상호작용하려면 FactoryRegistry를 초기화할 때 entityTypes 목록에 DeviceGroup를 Group, GroupManagement, GroupMembership 특성과 함께 포함합니다.
자세한 내용은 기기 그룹을 참고하세요.
앱 언어 구성
HomeClient 인스턴스에서 setLocale() 및 getLocale()를 사용하여 앱의 언어 환경설정을 구성하고 가져옵니다. 언어는 유효한 BCP-47 언어 태그(예: "en-US", "en-GB", "ja")여야 합니다.
HomeClient에서 언어를 설정하면 Home API는 권한 UI, Matter 커미셔닝, 기기 삭제 흐름을 비롯한 Google 호스팅 UI 흐름에 해당 언어를 사용합니다. 언어를 설정하지 않으면 이러한 흐름은 기본적으로 앱 또는 기기 언어로 설정됩니다.
- 사용자가 로그인하고 권한을 부여하기 전에
setLocale()를 호출하면 언어가 메모리에 저장되고 초기 권한 UI 흐름에 적용됩니다. 사용자가 로그인하고 구조를 사용할 수 있게 되면 SDK는 언어를 클라우드와 동기화합니다. 사용자가 이미 클라우드에 앱의 언어를 저장한 경우 초기 동기화 시 클라우드 설정이 우선 적용됩니다. - 로그인한 상태에서
setLocale()를 호출하면 메모리의 언어가 업데이트되고 해당 사용자와 앱의 클라우드에 유지됩니다.
// Set the locale using a BCP-47 language tag
coroutineScope.launch {
homeManager.setLocale("ja")
}
// Retrieve the configured locale, or null if not set
val currentLocale: String? = homeManager.getLocale()
Android 앱별 언어 환경설정과 동기화
앱이 LocaleManager를 사용하여 Android 앱별 언어 설정을 지원하는 경우 LocaleManager.applicationLocales를 업데이트하기 전에 homeManager.setLocale()를 호출합니다. applicationLocales를 업데이트하면 활성 Activity가 다시 생성되며, 이후에 setLocale()를 호출하면 진행 중인 코루틴이 취소될 수 있습니다.
coroutineScope.launch {
val languageTag = "fr-CA"
// 1. Persist the locale to HomeClient first
homeManager.setLocale(languageTag)
// 2. Update Android's per-app locale (recreates the Activity)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.getSystemService(LocaleManager::class.java).applicationLocales =
LocaleList.forLanguageTags(languageTag)
}
}