راه‌اندازی خانه در Android

قبل‌از استفاده از هرکدام از Home API برای Android، باید خانه را در برنامه‌تان مقداردهی اولیه کنید. در این مرحله، یک نمونه تک‌قلو از Home برای بافت محلی ایجاد خواهید کرد.

هربار فقط یک نمونه از Home باید فعال باشد.

این نقطه ورود به Home APIs است و همچنین شامل اعلام این است که قصد دارید از کدام ویژگی‌ها و انواع دستگاه‌ها با Device & Structure و Automation APIs استفاده کنید. اگر تازه کار با بوم‌سازگان Google Home را شروع کرده‌اید و مطمئن نیستید چه ویژگی‌ها یا انواع دستگاهی را ثبت کنید، برخی‌از رایج‌ترین آن‌ها را در این راهنما پیشنهاد کرده‌ایم.

ایجاد نمونه Home

برای شروع، این بسته‌ها را به برنامه‌تان وارد کنید:

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

برای مقداردهی اولیه Home APIs:

  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 را که نقطه ورودی به میاناهای برنامه‌سازی کاربردی است بااستفاده از بافت و 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، مثل صفحه رضایت «اجازه‌ها»، به زبان خاصی ارائه شود، پیش‌از درخواست اجازه‌ها، setLocale() را در نمونه HomeClient خود فراخوانی کنید. برای جزئیات بیشتر، پیکربندی منطقه زبانی برنامه را ببینید.

ورود به سیستم Google آغازشده توسط برنامه

ممکن است بخواهید اصالت‌سنجی‌های Google کاربرتان را در برنامه‌تان مدیریت کنید. با انجام این کار می‌توانید از همان حساب کاربری در سرویس‌های مختلف Google مانند Google Home،‏ Drive،‏ Maps، و غیره استفاده کنید.

با ورود به سیستم Google با شروع برنامه، می‌توانید نمونه HomeClient را به‌طور صریح به کاربر خاصی گره بزنید و درنتیجه، وقتی حساب ازقبل مجاز شده باشد، انتخابگر «حساب Google» و صفحه رضایت را دور بزنید.

علاوه‌براین، این رویکرد مانع از این می‌شود که کاربران دو صفحه انتخاب حساب متفاوت را ببینند - یکی از ورود به سیستم برنامه و دیگری از Google Home.

برای انجام این کار، باید به اصالت‌سنجی کاربران با «ورود به سیستم با Google» مراجعه کنید و مراحل زیر را تکمیل کنید:

ایجاد کردن شناسه کارخواه برنامه وب OAuth

  1. باز کردن «کنسول Google Cloud»
    • به صفحه «اطلاعات کاربری کنسول Google Cloud» بروید.
    • پروژه موجودی را انتخاب کنید یا پروژه جدیدی ایجاد کنید.
  2. پیکربندی «صفحه کسب رضایت OAuth» (اگر قبلاً انجام نداده‌اید)
    • پیش‌از ایجاد اطلاعات کاربری، مطمئن شوید صفحه رضایت OAuth با جزئیات برنامه‌تان، ازجمله نشانی‌های وب خط‌مشی رازداری و شرایط خدمات، پیکربندی شده باشد.
  3. ایجاد شناسه کارخواه OAuth (نوع برنامه وب)
    • در صفحه «اعتبارنامه‌ها»، روی + CREATE CREDENTIALS کلیک کنید و شناسه کارخواه OAuth را از منوِ کرکره‌ای انتخاب کنید.
    • برای نوع برنامه، برنامه وب را انتخاب کنید.
    • نامی برای مشتری وب خود وارد کنید (مثلاً «My App Web Backend»).
    • روی «ایجاد کردن» کلیک کنید.
  4. بازیابی شناسه کارخواه
    • پس‌از ایجاد، کنسول «شناسه کارخواه» جدیدتان را نمایش خواهد داد. این مقداری است که در برنامه 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) در مرحله ۴، 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() را با 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، Permissions API را ببینید.

بازآوری کل فعالیت با HomeClient جدید

وقتی نمونه HomeClient جدیدی دارید، باید کل فعالیت را بازآوری کنید تا دوباره مشترک شوید و ساختارها، دستگاه‌ها، و دیگر داده‌های مربوطه مرتبط با این حساب کاربری را واکشی کنید.

ثبت ویژگی‌ها و انواع دستگاه

کلاس FactoryRegistry به توسعه‌دهندگان کمک می‌کند اندازه دودویی برنامه‌شان را با اجازه دادن به آن‌ها برای نشان دادن صریح اینکه کدام ویژگی‌ها و انواع دستگاه توسط برنامه‌شان استفاده می‌شود بهینه‌سازی کنند.

توجه داشته باشید که اجازه‌ها و ثبت کارخانه از هم جدا هستند. بنابراین، ویژگی‌ها و انواع ثبت‌نشده‌ای که بااستفاده از اجازه‌ها برای برنامه‌تان دردسترس هستند اما در ثبت کارخانه گنجانده نشده‌اند، بااستفاده از Automation API دردسترس نیستند و در فراخوانی‌های روش انبوه traits() یا types() برگردانده نمی‌شوند.

گروه‌های دستگاه با موجودیت DeviceGroup نشان داده می‌شوند که با HomeDevice متفاوت است. برای جستجو و تعامل با گروه‌های دستگاه، هنگام مقداردهی اولیه FactoryRegistry، DeviceGroup را در فهرست entityTypes به‌همراه ویژگی‌های Group، GroupManagement، و GroupMembership اضافه کنید.

برای اطلاعات بیشتر، به گروه‌های دستگاه مراجعه کنید.

پیکربندی زبان برنامه

از setLocale() و getLocale() در نمونه HomeClient خود برای پیکربندی و بازیابی اولویت زبان برای برنامه‌تان استفاده کنید. منطقه زبانی باید برچسب زبان BCP-47 معتبری باشد، مانند "en-US"، "en-GB"، یا "ja".

وقتی منطقه‌ای را در HomeClient تنظیم می‌کنید، Home APIs از آن زبان برای جریان‌های میانای کاربر میزبانی‌شده در Google، ازجمله میانای کاربر «اجازه‌ها»، Matter راه‌اندازی، و جریان‌های برداشتن دستگاه استفاده می‌کند. اگر منطقه زبانی تنظیم نکنید، این جریان‌ها به‌طور پیش‌فرض از منطقه زبانی برنامه یا دستگاه استفاده می‌کنند.

  • فراخوانی setLocale() قبل‌از اینکه کاربر به سیستم وارد شود و اجازه‌ها را اعطا کند، منطقه زبانی را در حافظه ذخیره می‌کند و آن را در جریان واسط کاربر اجازه‌های اولیه اعمال می‌کند. وقتی کاربر به سیستم وارد می‌شود و ساختاری دردسترس است، کیت توسعه نرم‌افزار منطقه زبانی را با فضای ابری همگام‌سازی می‌کند. اگر کاربر ازقبل منطقه زبانی ذخیره‌شده‌ای در فضای ابری برای برنامه شما داشته باشد، تنظیمات ابری در همگام‌سازی اولیه اولویت دارد.
  • فراخوانی 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 پشتیبانی می‌کند، پیش‌از به‌روزرسانی 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)
  }
}