ก่อนใช้ Home API สำหรับ Android คุณต้องเริ่มต้นบ้านในแอป ในขั้นตอนนี้ คุณจะสร้างอินสแตนซ์ Singleton ของ Home สำหรับบริบทเฉพาะรายการ
ควรมี Home เพียงอินสแตนซ์เดียวที่ทำงานอยู่
นี่คือจุดแรกเข้าของ Home API และยังเกี่ยวข้องกับการประกาศลักษณะและประเภทอุปกรณ์ที่คุณต้องการใช้กับ Device & Structure API และ Automation API ด้วย หากคุณเพิ่งเริ่มต้นใช้งานระบบนิเวศของ Google Home และไม่แน่ใจว่าควรลงทะเบียนลักษณะหรือประเภทอุปกรณ์ใด เราได้แนะนำลักษณะและประเภทอุปกรณ์ที่พบบ่อยที่สุดไว้ในคู่มือนี้
สร้างอินสแตนซ์ Home
เริ่มต้นด้วยการนำเข้าแพ็กเกจเหล่านี้ไปยังแอปของคุณ
import android.content.Context
import com.google.home.FactoryRegistry
import com.google.home.HomeConfig
import com.google.home.Home
วิธีเริ่มต้นใช้งาน Home API
รับข้อมูลอ้างอิงไปยังบริบท
Applicationบริบทนี้ไม่ได้ขึ้นอยู่กับวงจรกิจกรรมใดๆ และจะคงอยู่ตราบเท่าที่แอปของคุณยังทำงานอยู่ คุณสามารถรับรหัสได้โดยเรียกใช้getApplicationContext()ภายในActivityหรือServiceดังนี้val context = getApplicationContext()สร้างอินสแตนซ์
FactoryRegistryที่มีลักษณะและประเภทอุปกรณ์ทั้งหมดที่คุณต้องการใช้ในแอปสำหรับคู่มือนี้ เราได้แนะนำประเภทที่พบบ่อย (ประเภทอุปกรณ์หลอดไฟ ปลั๊ก เซ็นเซอร์ สวิตช์ และตัวควบคุมอุณหภูมิ รวมถึงลักษณะการมีผู้ใช้งานอยู่และ Assistant สำหรับการทำงานอัตโนมัติ) เผื่อว่าคุณไม่แน่ใจว่าต้องการอะไร ดูข้อมูลเพิ่มเติมได้ที่การลงทะเบียนลักษณะและประเภทอุปกรณ์
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 โดยใช้บริบทและHomeConfigval homeManager: HomeClient = Home.getClient(context, homeConfig)
เพื่อหลีกเลี่ยงข้อผิดพลาดเกี่ยวกับเซสชันที่ไม่ถูกต้อง คุณต้องสร้างอินสแตนซ์ Home แบบ Singleton เท่านั้น โดยรวมไว้ในการประกาศออบเจ็กต์
ตัวอย่างเช่น แอปตัวอย่างจะดำเนินการดังนี้
internal object HomeClientModule {
@Provides
@Singleton
fun provideHomeClient(@ApplicationContext context: Context): HomeClient {
return Home.getClient(
context,
HomeConfig(
coroutineContext = IODispatcherModule.provideIoDispatcher(),
factoryRegistry = registry,
),
)
}
}
หากต้องการให้ขั้นตอน UI ที่ Google โฮสต์ เช่น หน้าจอขอความยินยอมสำหรับสิทธิ์ แสดงผลเป็นภาษาที่เฉพาะเจาะจง ให้เรียกใช้ setLocale() ในอินสแตนซ์ HomeClient ก่อนขอสิทธิ์ โปรดดูรายละเอียดที่หัวข้อกำหนดค่าภาษาของแอป
การลงชื่อเข้าใช้ Google ที่เริ่มต้นโดยแอป
คุณอาจต้องการจัดการการตรวจสอบสิทธิ์ Google ของผู้ใช้ภายในแอป ซึ่งจะช่วยให้คุณใช้บัญชีผู้ใช้เดียวกันในบริการต่างๆ ของ Google เช่น Google Home, ไดรฟ์, Maps และอื่นๆ ได้
เมื่อใช้การลงชื่อเข้าใช้ Google ที่เริ่มต้นโดยแอป คุณจะได้รับอินสแตนซ์ HomeClient ที่เชื่อมโยงกับผู้ใช้รายใดรายหนึ่งอย่างชัดเจน ซึ่งจะข้ามเครื่องมือเลือกบัญชี Google และหน้าจอขอความยินยอมเมื่อบัญชีได้รับสิทธิ์แล้ว
นอกจากนี้ วิธีนี้ยังช่วยป้องกันไม่ให้ผู้ใช้เห็นหน้าจอการเลือกบัญชี 2 หน้าจอที่แตกต่างกัน ซึ่งหน้าจอหนึ่งมาจากการลงชื่อเข้าใช้ของแอป และอีกหน้าจอหนึ่งมาจาก Google Home
โดยคุณต้องดูตรวจสอบสิทธิ์ผู้ใช้ด้วยฟีเจอร์ลงชื่อเข้าใช้ด้วย Google และทำตามขั้นตอนต่อไปนี้
สร้างรหัสไคลเอ็นต์ OAuth สำหรับเว็บแอปพลิเคชัน
- เปิดคอนโซล Google Cloud
- ไปที่หน้าข้อมูลเข้าสู่ระบบของคอนโซล Google Cloud
- เลือกโปรเจ็กต์ที่มีอยู่หรือสร้างโปรเจ็กต์ใหม่
- กำหนดค่าหน้าจอขอความยินยอม OAuth (หากยังไม่ได้ดำเนินการ)
- ก่อนสร้างข้อมูลเข้าสู่ระบบ โปรดตรวจสอบว่าได้กำหนดค่าหน้าจอขอความยินยอม OAuth ด้วยรายละเอียดของแอป รวมถึง URL ของนโยบายความเป็นส่วนตัวและข้อกำหนดในการให้บริการแล้ว
- สร้างรหัสไคลเอ็นต์ OAuth (ประเภทเว็บแอปพลิเคชัน)
- ในหน้าข้อมูลเข้าสู่ระบบ ให้คลิก
+ CREATE CREDENTIALSแล้วเลือกรหัสไคลเอ็นต์ OAuth จากเมนูแบบเลื่อนลง - ในส่วนประเภทแอปพลิเคชัน ให้เลือกเว็บแอปพลิเคชัน
- ป้อนชื่อสำหรับไคลเอ็นต์เว็บ (เช่น "แบ็กเอนด์เว็บของแอปฉัน")
- คลิกสร้าง
- ในหน้าข้อมูลเข้าสู่ระบบ ให้คลิก
- ดึงข้อมูลรหัสไคลเอ็นต์
- หลังจากสร้างแล้ว คอนโซลจะแสดงรหัสไคลเอ็นต์ใหม่ ค่านี้คือค่าที่คุณจะใช้ในแอปพลิเคชัน Android (เช่น "{project number}-.....apps.googleusercontent.com")
- ขอแนะนำให้จัดเก็บรหัสไคลเอ็นต์ไว้ภายนอก (เช่น ใน
build.gradle) แทนที่จะฮาร์ดโค้ดโดยตรง
สร้างอินสแตนซ์คำขอ Google Sign-In
ใช้รหัสเว็บแอปเพื่อสร้างคำขอลงชื่อเข้าใช้ 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) โดยที่พารามิเตอร์ที่ 2 คือ 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()ซึ่งจะแสดงหน้าจอขอความยินยอมของ GHP ที่ผู้ใช้สามารถให้สิทธิ์ได้
คุณสามารถสร้าง 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)
หากต้องการแสดงหน้าจอขอความยินยอมในภาษาที่เฉพาะเจาะจง ให้เรียกใช้ client.setLocale() ก่อนเรียกใช้ requestPermissions() ดูรายละเอียดได้ที่กำหนดค่าภาษาของแอป และดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการสิทธิ์ของ Home API ได้ที่ Permissions API
รีเฟรชกิจกรรมทั้งหมดด้วย HomeClient ใหม่
เมื่อมีอินสแตนซ์ HomeClient ใหม่แล้ว คุณต้องรีเฟรชกิจกรรมทั้งหมดเพื่อสมัครอีกครั้งและดึงข้อมูลโครงสร้าง อุปกรณ์ และข้อมูลอื่นๆ ที่เกี่ยวข้องทั้งหมดซึ่งเชื่อมโยงกับบัญชีผู้ใช้นี้
การลงทะเบียนลักษณะและประเภทอุปกรณ์
คลาส FactoryRegistry ช่วยให้นักพัฒนาแอปเพิ่มประสิทธิภาพขนาดไบนารีของแอปได้โดยการระบุลักษณะและประเภทอุปกรณ์ที่แอปใช้ไว้อย่างชัดเจน
โปรดทราบว่าสิทธิ์และรีจิสทรีโรงงานจะแยกออกจากกัน ดังนั้นลักษณะและประเภทที่ไม่ได้ลงทะเบียนซึ่งแอปของคุณใช้ได้โดยใช้สิทธิ์แต่ไม่ได้รวมอยู่ในรีจิสทรีเริ่มต้นจะเข้าถึงไม่ได้โดยใช้ Automation API และจะไม่แสดงผลในการเรียกใช้เมธอด traits() หรือ types() แบบเป็นกลุ่ม
DeviceGroup ซึ่งแตกต่างจาก HomeDevice หากต้องการค้นหาและโต้ตอบกับกลุ่มอุปกรณ์ ให้ใส่ DeviceGroup ไว้ในรายการ entityTypes เมื่อเริ่มต้น FactoryRegistry พร้อมกับลักษณะ Group, GroupManagement และ GroupMembership
ดูข้อมูลเพิ่มเติมได้ที่กลุ่มอุปกรณ์
กำหนดค่าภาษาของแอป
ใช้ setLocale() และ getLocale() ในอินสแตนซ์ HomeClient เพื่อกำหนดค่าและดึงข้อมูลค่ากำหนดภาษาสำหรับแอปของคุณ ภาษาต้องเป็นแท็กภาษา BCP-47 ที่ถูกต้อง เช่น "en-US", "en-GB" หรือ "ja"
เมื่อคุณตั้งค่าภาษาใน HomeClient Home API จะใช้ภาษานั้นสำหรับขั้นตอน UI ที่โฮสต์โดย Google ซึ่งรวมถึง UI สิทธิ์, การจัดสรรคอมมิชชัน Matter และขั้นตอนการนำอุปกรณ์ออก หากคุณไม่ได้ตั้งค่าภาษา ขั้นตอนเหล่านี้จะใช้ภาษาของแอปหรืออุปกรณ์เป็นค่าเริ่มต้น
- การเรียกใช้
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
หากแอปของคุณรองรับค่ากำหนดภาษาที่ใช้ในแอปของ Android โดยใช้ LocaleManager ให้เรียกใช้ homeManager.setLocale() ก่อนอัปเดต LocaleManager.applicationLocales การอัปเดต 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)
}
}