واجهة 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.
تنفيذ عملية التشغيل الآلي:
  • لا يتطلّب التطبيق إذن الوصول إلى الجهاز الذي يبدأ عملية التشغيل الآلي.
  • يجب أن يكون لدى التطبيق والمستخدِم إذن الوصول إلى الجهاز الذي يتم عليه الإجراء.

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

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

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