واجهة Permissions API على Android

قبل استخدام أي من واجهات برمجة التطبيقات لمنزل Google على Android، يجب أن يكون لدى التطبيق إذن بالوصول إلى الأجهزة في منزل المستخدم، ويُشار إليها في واجهة برمجة التطبيقات باسم البنية. باستخدام Permissions API، يمكن للمستخدم، باستخدام حسابه على Google، منح تطبيقات Home APIs إذن الوصول إلى الأجهزة في منزله.

يسمح مسار الأذونات للمستخدم بإنشاء بنية إذا لم يتم إعدادها من قبل، بدون الحاجة إلى استخدام Google Home app (GHA).

دمج Permissions API

قبل المتابعة، تأكَّد من اتّباع الخطوات الواردة في مقالة تهيئة المنزل على Android. يتم استخدام مثيل homeManager من تلك الخطوة في جميع أمثلة الأذونات الواردة هنا.

أولاً، سجِّل ActivityResultCaller باستخدام حزمة تطوير البرامج (SDK). على سبيل المثال، إليك كيفية معالجة التطبيق النموذجي لذلك:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    homeManager.registerActivityResultCallerForPermissions(this)
  }

التحقّق من الأذونات

قبل طلب الأذونات، ننصحك بالتحقّق مما إذا كان مستخدم التطبيق قد منح الموافقة على الوصول إلى البنية من قبل. لإجراء ذلك، استخدِم طريقة hasPermissions() لمثيل Home للحصول على Flow من PermissionsState قيم:

val permissionsReadyState =
homeManager.hasPermissions().collect { state ->
    when (state) {
      PermissionsState.GRANTED -> println("Permissions granted, no need to request permissions")
      PermissionsState.PERMISSIONS_STATE_UNAVAILABLE ->
          println("Permissions state unavailable, request permissions")

      PermissionsState.NOT_GRANTED ->
          println("OAuth permission is enabled but not granted yet, request permissions")

      PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> println(
          "Permissions state is not initialized yet. Clients should wait for another status update"
      )
      else ->
          throw IllegalStateException("""
            HomeClient.hasPermissions state should be PermissionsState.GRANTED,
            PermissionState.PERMISSIONS_STATE_UNINITIALIZED, or
            PermissionsState.PERMISSIONS_STATE_UNAVAILABLE. Actual state: $state
          """.trimIndent())
    }
}

إذا أرجعت عملية التحقّق PermissionsState بقيمة NOT_GRANTED أو PERMISSIONS_STATE_UNAVAILABLE، يعني ذلك أنّ المستخدم أو التطبيق لا يمكنه الوصول إلى البنية. إذا أرجعت عملية التحقّق PermissionsState بقيمة GRANTED ولكنّ طلبًا لاحقًا لـ structures() لم يُرجع أي بنى، يعني ذلك أنّ المستخدم قد ألغى إذن الوصول إلى التطبيق من خلال صفحة إعدادات GHA، أو أنّ المستخدم لا يملك إذن الوصول المطلوب.

طلب الحصول على الأذونات

يجب منح الإذن لتطبيقك للوصول إلى البنى والأجهزة ضِمن بنية معيّنة.

إذا لم يسبق للمستخدم منح الأذونات، استخدِم الـ requestPermissions() لمثيل Home لتشغيل واجهة مستخدم الأذونات ومعالجة النتيجة:

fun requestPermissions(scope: CoroutineScope, onShowSnackbar: (String) -> Unit) {
  scope.launch {
    val result =
      try {
        homeManager.requestPermissions()
      } catch (e: HomeException) {
        PermissionsResult(
          PermissionsResultStatus.ERROR,
          "Got HomeException with error: ${e.message}",
        )
      }
    when (result.status) {
      PermissionsResultStatus.SUCCESS -> {
        Log.i(TAG, "Permissions successfully granted.")
      }
      PermissionsResultStatus.CANCELLED -> {
        Log.i(TAG, "User cancelled Permissions flow.")
        onShowSnackbar("User cancelled Permissions flow")
      }
      else -> {
        Log.e(
          TAG,
          "Failed to grant permissions with error: ${result.status}, ${result.errorMessage}",
        )
        onShowSnackbar("Failed to grant permissions with error: ${result.errorMessage}")
      }
    }
  }
}

لكي يتم تشغيل واجهة مستخدم الأذونات بشكلٍ صحيح، يجب أن تكون قد أعددت بروتوكول OAuth لتطبيقك.

منح الأذونات

يجب أن تتمكّن الآن من تشغيل تطبيقك ومنح المستخدم الأذونات. سيختلف نوع المستخدمين الذين يمكنهم منح الإذن وأنواع الأجهزة التي يمكن منح الأذونات لها، وذلك حسب ما إذا كنت قد سجّلت تطبيقك في Google Home Developer Console.

يلزم التسجيل في Developer Console لنشر تطبيق باستخدام Home APIs. ولكن لا يجب التسجيل لاختبار Home APIs واستخدامها.

إذا لم يتم تسجيل تطبيق في Developer Console، سيظهر في في حالة لم يتم التحقّق منه. ننصح بذلك لاختبار استخدام Home APIs:

  • يمكن للمستخدمين المسجّلين كمستخدمين اختباريين في وحدة تحكّم OAuth فقط منح الأذونات للتطبيق. ويبلغ الحد الأقصى لعدد المستخدمين الاختباريين لتطبيق لم يتم التحقّق منه 100 مستخدم.

  • سيتمكّن التطبيق الذي لم يتم التحقّق منه من الوصول إلى الأجهزة من أي أنواع أجهزة متوافقة مع OAuth لـ Home APIs (قائمة أنواع الأجهزة في Developer Console). وسيتم منح الإذن لجميع الأجهزة في البنية.

إذا تم تسجيل تطبيق في Developer Console و تمت الموافقة على وصوله إلى نوع جهاز واحد أو أكثر، وتم التحقّق من العلامة التجارية لبروتوكول OAuth، سيظهر في حالة تم التحقّق منه. هذه الحالة مطلوبة لإطلاق تطبيق في مرحلة الإنتاج:

  • لم تعُد تنطبق الحدود القصوى لعدد المستخدمين الاختباريين. يمكن لأي مستخدم منح الإذن للتطبيق.
  • لا يمكن للمستخدم منح الإذن إلا لأنواع الأجهزة التي تمت الموافقة عليها في Developer Console.

بعد إعداد OAuth، يؤدي طلب التطبيق لـ requestPermissions() إلى ظهور مربّعات الحوار التالية:

  1. يُطلب من المستخدم اختيار حساب Google الذي يريد استخدامه.
  2. يُطلب من المستخدم اختيار البنية التي يريد منح التطبيق إذن الوصول إليها.
    1. بالنسبة إلى تطبيق لم يتم التحقّق منه، تتوفّر للتطبيق جميع أنواع الأجهزة المتوافقة مع Home APIs.
    2. بالنسبة إلى تطبيق تم التحقّق منه، لا يمكن للمستخدم منح الإذن إلا لأنواع الأجهزة التي تمت الموافقة عليها في Developer Console.
    3. بالنسبة إلى أنواع الأجهزة الحسّاسة التي يمكن للتطبيق إدارتها، يمكن للمستخدم حصر إذن الوصول على أساس كل جهاز على حدة. على سبيل المثال، إذا كان لدى المستخدم ثلاثة أقفال، يمكنه منح إذن الوصول إلى قفل واحد فقط من هذه الأقفال.
  • موافقة OAuth - اختيار حساب
  • OAuth consent - link devices 01
  • الموافقة على OAuth - ربط الجهاز 02
الشكل 1: مثال على مسار طلب الموافقة على OAuth

بعد منح الإذن، يمكن للتطبيق استخدام Home APIs لقراءة حالة الأجهزة في البنية والتحكّم فيها. إذا لم يمنح المستخدم الإذن للتطبيق لنوع جهاز معيّن أو جهاز حسّاس، لن يتمكّن التطبيق من استخدام Home APIs للوصول إليه أو التحكّم فيه أو تشغيله تلقائيًا.

تغيير الأذونات

لمنح الإذن بالوصول إلى الأجهزة في بنية مختلفة، يمكن تشغيل أداة اختيار الحساب للسماح للمستخدم باختيار حساب Google والبنية التي يريد التبديل إليها. أثناء هذه العملية، ستظهر للمستخدم شاشة طلب الموافقة مرة أخرى، حتى إذا تم منح الموافقة سابقًا.

يمكن إجراء ذلك من خلال استدعاء requestPermissions() مرة أخرى مع ضبط العلامة forceLaunch على true:

homeManager.requestPermissions(forceLaunch=true)

تغيير الأذونات باستخدام تلميحات البنية

تسمح تلميحات البنية للتطبيق باختيار بنية معيّنة مسبقًا، أو حصر قائمة البنى المتاحة، عند طلب تغيير تدريجي في أذونات Home APIs للمستخدم. من خلال تمرير مَعلمات البنية إلى طلب التفويض، سيركّز مربّع حوار الأذونات تلقائيًا على البنية المختارة، ما يقلّل من إزعاج المستخدم ويمنع أخطاء الإعداد.

تتم إدارة تلميحات البنية باستخدام الـ ConsentScreenOptions فئة البيانات. تقبل فئة ConsentScreenOptions مَعلمات الإعداد التالية:

  • structureId : رقم تعريف البنية المحدّد الذي سيتم اختياره مسبقًا في مربّع حوار الأذونات. يمكنك الحصول على هذا الرقم من خلال التحقّق من خصائص البنية التي يتم تعديلها.
  • allowedStructureIds: قائمة بأرقام تعريف البنى. إذا تم تقديمها، سيُفلتر مربّع حوار الأذونات البنى المتاحة لعرض تلك البنى فقط في هذه القائمة. يمكن ترك هذه المَعلمة غير محدّدة في معظم الحالات، إلا إذا كنت تريد التأكّد من بقاء المستخدم ضِمن قائمة البنى التي تم منح الإذن لها سابقًا.
  • allowStructureChange : تحدّد ما إذا كان يُسمح للمستخدم بتغيير البنية التي تم اختيارها مسبقًا. اضبط هذه المَعلمة على true إذا تم تحديد allowedStructureIds أو structureId أو كلتيهما في معظم الحالات لدعم السلوك الطبيعي للمستخدم.

مرِّر هذا العنصر كمَعلمة اختيارية في طلب requestPermissions()، مع ضبط العلامة forceLaunch على true:

import com.google.home.ConsentScreenOptions

// Create the ConsentScreenOptions class, allowing structure changes while
// ensuring the permissions dialog pre-selects the target structure on launch
val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowStructureChange = true
)

homeManager.requestPermissions(forceLaunch=true, consentOptions)

ستظهر للمستخدم شاشة طلب الموافقة التي تم فلترتها مسبقًا لتشمل البنية الموضّحة في عنصر ConsentScreenOptions.

السماح للمستخدم بتبديل البنى باستخدام تلميحات البنية

إذا كان لدى المستخدم بنى متعدّدة في أحد التطبيقات وأردت اختيار بنية مسبقًا مع السماح له في الوقت نفسه بالتبديل بين البنى المتاحة، فعِّل تغييرات البنية باستخدام العلامة allowStructureChange وقدِّم قائمة بالبنى في allowedStructureIds:

val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowedStructureIds = listOf(target-structure-id, another-structure-id),
    allowStructureChange = true
)

إبطال الأذونات

يمكن للمستخدمين إبطال إذن الوصول الذي تم منحه سابقًا:

  1. من خلال صفحة حسابي على Google > البيانات والخصوصية > التطبيقات والخدمات الخارجية. سيؤدي ذلك إلى إبطال رمز OAuth المميّز الذي تم إصداره عند منح الموافقة الأولية، وسيؤدي إلى إبطال إذن الوصول إلى أي مثيل من التطبيق كان يستخدمه المستخدم على جميع الأسطح (الهواتف) والبنى.

    يمكن توجيه المستخدم باستخدام رابط انتقال سريع إلى الصفحة الفرعية التطبيقات والخدمات الخارجية باستخدام نظام عناوين URL التالي:

    https://myaccount.google.com/connections/link?project_number=Cloud project_number
    
  2. من خلال صفحة GHA > الإعدادات > التطبيقات المرتبطة. سيؤدي النقر على في GHA إلى نقلك إلى صفحة الإعدادات. من هناك، انقر على مربّع التطبيقات المرتبطة الذي ينقلك إلى صفحة تبدو مشابهة لشاشة طلب الموافقة. من هذه الصفحة، يمكن للمستخدم إزالة إذن الوصول إلى التطبيق. ويمكن للمستخدم استخدام هذه الصفحة نفسها لتغيير أنواع الأجهزة أو الأجهزة الحسّاسة المحدّدة التي يمكن للتطبيق الوصول إليها.

في نظام Google Home، يمكن للمستخدمين منح الأذونات لجميع الأجهزة من نوع معيّن في آنٍ واحد، وذلك لمعظم أنواع الأجهزة. بالنسبة إلى أنواع الأجهزة الحسّاسة أو المحظورة، مثل الأقفال أو الكاميرات أو أجراس الأبواب، يجب أن يمنح المستخدمون الإذن لها بشكلٍ فردي.

لتحديد ما إذا كان المستخدم قد منح الإذن بالوصول إلى نوع جهاز حسّاس أو محظور، استخدِم الدالة consentedDeviceTypes() على مستوى البنية:

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

أذونات "مساعد Google"

الأمر okGoogle هو أمر على مستوى الجهاز ويمكن استخدامه لتشغيل أي جهاز تلقائيًا في البنية. ومع ذلك، قد لا يتمكّن تطبيق Home APIs من الوصول إلى كل جهاز. يوضّح الجدول التالي كيفية فرض الأذونات في مثل هذه الحالات.

أتمتة السمة فرض الأذونات
في الساعة 10:00 مساءً، أريد أن يتم بث رسالة مضمونها "حان وقت النوم" على مكبّر صوت غرفة النوم. AssistantBroadcastTrait على الجهاز. إنشاء الأتمتة:
  • يجب أن يكون جهاز البث جهازًا من أجهزة "مساعد Google".
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى الجهاز الذي يتم عليه الـ بث.
تنفيذ الأتمتة:
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى الجهاز الذي يتم عليه الـ بث.
في الساعة 10:00 مساءً، أريد أن يتم بث رسالة مضمونها "حان وقت النوم" على جميع الأجهزة AssistantBroadcastTrait على البنية. إنشاء الأتمتة:
  • يجب أن يكون هناك جهاز واحد على الأقل من أجهزة "مساعد Google" في البنية يمكن للتطبيق والمستخدم الوصول إليه.
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى البنية.
تنفيذ الأتمتة:
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى البنية.
في الساعة 10:00 مساءً، أريد "تشغيل بعض الموسيقى" AssistantFulfillmentTrait.OkGoogleCommand إنشاء الأتمتة:
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى الأجهزة التي تُرسِل إليها الأتمتة الأوامر.
تنفيذ الأتمتة:
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى الأجهزة التي تُرسِل إليها الأتمتة الأوامر.
عندما يقول أحد المستخدمين "تشغيل بعض الموسيقى" VoiceStarterTrait.OkGoogleEvent إنشاء الأتمتة:
  • يجب أن يتمكّن التطبيق والمستخدم من الوصول إلى البنية. لا تتطلّب الأتمتة جهازًا من أجهزة "مساعد Google" لاجتياز عملية التحقّق أو التشغيل، لأنّه يمكن لأي مستخدم لديه إذن الوصول إلى البنية استخدام هاتفه (باستخدام حساب Google نفسه) للتفاعل مع "مساعد Google" وتشغيل VoiceStarter.
تنفيذ الأتمتة:
  • لا يتطلّب التطبيق إذن الوصول إلى الجهاز الذي يبدأ الأتمتة.
  • يجب أن يكون لدى التطبيق والمستخدم إذن الوصول إلى الجهاز الذي يتم عليه الإجراء.

إرشادات في حال إبطال المستخدم الأذونات الكاملة

إذا أبطَل المستخدم الأذونات الكاملة، ستتوقف جميع عمليات التشغيل الآلي الحالية عن العمل. أيضًا، إذا ألغى المستخدم إذن الوصول إلى أجهزة معيّنة، ستتوقف عن العمل أدوات البدء والشروط والإجراءات المرتبطة بهذه الأجهزة.

في كل مرة يبدأ فيها التطبيق، احرص على التحقّق من أنّ الأذونات لا تزال سارية. إذا تم إبطالها، تأكَّد من إزالة جميع البيانات السابقة، بما في ذلك أي بيانات مخزّنة مؤقتًا في التطبيق.