إنشاء تطبيق مصغّر باستخدام ميزة "نظرة سريعة"

توضِّح الأقسام التالية كيفية إنشاء تطبيق مصغّر أساسي باستخدام Glance.

الإعلان عن AppWidget في ملف البيان

بعد إكمال خطوات الإعداد، عليك الإعلان عن AppWidget والبيانات الوصفية الخاصة به في تطبيقك.

  1. عليك توسيع أداة استقبال AppWidget من GlanceAppWidgetReceiver:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
    }

  2. عليك تسجيل موفِّر التطبيق المصغّر في ملف AndroidManifest.xml وملف البيانات الوصفية المرتبطَين:

        <receiver android:name=".glance.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_info" />
    </receiver>
    

إضافة البيانات الوصفية AppWidgetProviderInfo

بعد ذلك، اتّبِع دليل إنشاء تطبيق مصغّر لإنشاء معلومات التطبيق المصغّر وتحديدها في الملف @xml/my_app_widget_info.

الفرق الوحيد في Glance هو أنّه لا يتوفّر ملف XML لـ initialLayout، ولكن عليك تحديد ملف. يمكنك استخدام تنسيق التحميل المحدّد مسبقًا والمتاح في المكتبة:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

الإعلان عن ملف XML لـ AppWidgetProviderInfo

يحدّد العنصر AppWidgetProviderInfo الخصائص الأساسية لتطبيقك المصغّر. عليك تحديد AppWidgetProviderInfo في ملف مصدر البيانات الوصفية بتنسيق XML (res/xml/my_app_widget_info.xml) داخل عنصر <appwidget-provider>

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

سمات تغيير حجم التطبيق المصغّر

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

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

يوضِّح الجدول التالي سمات <appwidget-provider> المتعلّقة بتغيير حجم التطبيق المصغّر:

السمات والوصف
targetCellWidth و targetCellHeight (الإصدار 12 من نظام التشغيل Android)، و minWidth وminHeight
  • بدءًا من الإصدار 12 من نظام التشغيل Android، تحدّد السمتان targetCellWidth وtargetCellHeight الحجم التلقائي للتطبيق المصغّر من حيث خلايا الشبكة. يتم تجاهل هاتَين السمتَين في الإصدار 11 من نظام التشغيل Android والإصدارات الأقدم، و يمكن تجاهلهما إذا كانت الشاشة الرئيسية لا تتيح تنسيقًا مستندًا إلى الشبكة.
  • تحدّد السمتان minWidth و minHeight الحجم التلقائي للتطبيق المصغّر بوحدة dp. إذا لم تتطابق قيمتا الحد الأدنى لعرض التطبيق المصغّر أو ارتفاعه مع أبعاد الخلايا، يتم تقريب القيم إلى أقرب حجم خلية.
ننصحك بتحديد كلتا مجموعتَي السمات، أي targetCellWidth و targetCellHeight، وminWidth و minHeight، حتى يتمكّن تطبيقك من الرجوع إلى استخدام minWidth وminHeight إذا كان جهاز المستخدِم لا يتيح targetCellWidth و targetCellHeight. إذا كانت السمتان targetCellWidth وtargetCellHeight متاحتَين، تكون لهما الأولوية على السمتَين minWidth وminHeight.
minResizeWidth و minResizeHeight تحديد الحد الأدنى المطلق لحجم التطبيق المصغّر تحدّد هاتان القيمتان الـ حجم الذي يصبح التطبيق المصغّر غير مقروء أو غير قابل للاستخدام تحته. باستخدام هاتَين السمتَين، يمكن للمستخدِم تغيير حجم التطبيق المصغّر إلى حجم أصغر من الحجم التلقائي للتطبيق المصغّر. يتم تجاهل السمة minResizeWidth إذا كانت أكبر من minWidth أو إذا لم يكن تغيير الحجم أفقيًا مفعّلاً. راجِع resizeMode. وبالمثل، يتم تجاهل السمة minResizeHeight إذا كانت أكبر من minHeight أو إذا لم يكن تغيير الحجم عموديًا مفعّلاً.
maxResizeWidth و maxResizeHeight تحديد الحد الأقصى المقترَح لحجم التطبيق المصغّر إذا لم تكن القيم مضاعفات لأبعاد خلية الشبكة، يتم تقريبها إلى أقرب حجم خلية. يتم تجاهل السمة maxResizeWidth إذا كانت أصغر من minWidth أو إذا لم يكن تغيير الحجم أفقيًا مفعّلاً. راجِع resizeMode. وبالمثل، يتم تجاهل السمة maxResizeHeight إذا كانت أصغر من minHeight أو إذا لم يكن تغيير الحجم عموديًا مفعّلاً. تم طرح هذه السمة في الإصدار 12 من نظام التشغيل Android.
resizeMode تحديد القواعد التي يمكن بموجبها تغيير حجم التطبيق المصغّر يمكنك استخدام هذه السمة لجعل التطبيقات المصغّرة على الشاشة الرئيسية قابلة لتغيير الحجم أفقيًا أو عموديًا أو على كلا المحورَين. ينقر المستخدِمون مع الاستمرار على تطبيق مصغّر لعرض مقابض تغيير الحجم، ثم يسحبون المقابض الأفقية أو العمودية لتغيير حجمه على شبكة التنسيق. تشمل قيم السمة resizeMode كلاً من horizontal وvertical وnone. للإعلان عن تطبيق مصغّر قابل لتغيير الحجم أفقيًا وعموديًا، استخدِم horizontal|vertical.

مثال

لتوضيح كيفية تأثير السمات في الجدول السابق على تغيير حجم التطبيق المصغّر، لنفترض المواصفات التالية:

  • عرض خلية الشبكة 30 dp وارتفاعها 50 dp.
  • تم تقديم مواصفات السمة التالية:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />

بدءًا من الإصدار 12 من نظام التشغيل Android:

استخدِم السمتَين targetCellWidth وtargetCellHeight كحجم تلقائي للتطبيق المصغّر.

حجم التطبيق المصغّر هو ‎2×2 تلقائيًا. يمكن تغيير حجم التطبيق المصغّر إلى ‎2×1 أو ‎4×3.

الإصدار 11 من نظام التشغيل Android والإصدارات الأقدم:

استخدِم السمتَين minWidth وminHeight لاحتساب الحجم التلقائي للتطبيق المصغّر.

العرض التلقائي = Math.ceil(80 / 30) = 3

الارتفاع التلقائي = Math.ceil(80 / 50) = 2

حجم التطبيق المصغّر هو ‎3×2 تلقائيًا. يمكن تغيير حجم التطبيق المصغّر إلى ‎2×1 أو ملء الشاشة.

سمات التطبيق المصغّر الإضافية

يوضِّح الجدول التالي سمات <appwidget-provider> المتعلّقة بالخصائص الأخرى غير تغيير حجم التطبيق المصغّر.

السمات والوصف
updatePeriodMillis تحديد عدد المرات التي يطلب فيها إطار عمل التطبيق المصغّر تحديثًا من الـ GlanceAppWidgetReceiver من خلال استدعاء طريقة رد الاتصال onUpdate() ننصحك بإجراء التحديث بأقل قدر ممكن من التكرار، أي مرة واحدة في الساعة على الأكثر، للحفاظ على البطارية. لمزيد من التفاصيل، راجِع قسم وقت تحديث التطبيقات المصغّرة في إدارة حالة Glance.
initialLayout يشير إلى مصدر التنسيق الذي يحدّد تنسيق التحميل الخاص بالتطبيق المصغّر قبل عرض تركيبات واجهة مستخدم Glance. يمكنك استخدام تنسيق التحميل المحدّد مسبقًا والمتاح في المكتبة: @layout/glance_default_loading_layout.
configure تحديد نشاط الإعداد الذي يتم تشغيله عندما يضيف المستخدِم التطبيق المصغّر راجِع قسم تنفيذ نشاط إعداد تطبيق مصغّر في هذه الصفحة.
description تحديد الوصف الذي يعرضه منتقي التطبيقات المصغّرة لتطبيقك المصغّر تم طرح هذه السمة في الإصدار 12 من نظام التشغيل Android.
previewLayout (الإصدار 12 من نظام التشغيل Android) وpreviewImage (الإصدار 11 من نظام التشغيل Android والإصدارات الأقدم)
  • بدءًا من الإصدار 12 من نظام التشغيل Android، تحدّد السمة previewLayout معاينة قابلة لتغيير الحجم، والتي تقدّمها كمجموعة تنسيق XML تم ضبطها على الحجم التلقائي للتطبيق المصغّر. من المفترض أن يشير هذا إلى عملية ربط XML ثابتة تطابق تنسيق التصميم.
  • في الإصدار 11 من نظام التشغيل Android أو الإصدارات الأقدم، تحدّد السمة previewImage لقطة شاشة ثابتة لصورة التطبيق المصغّر، والتي تظهر في منتقي التطبيقات المصغّرة.
ننصحك بتحديد كلتيهما حتى يتمكن تطبيقك من الرجوع إلى المنصات القديمة بسلاسة. بالنسبة إلى المنصات الأحدث (الإصدار 15 من نظام التشغيل Android والإصدارات الأحدث)، يمكنك تحديد معاينات تم إنشاؤها مباشرةً في Kotlin باستخدام `GlanceAppWidget.providePreview`. راجِع دليل المعاينات التي تم إنشاؤها.
autoAdvanceViewId تحديد معرّف العرض للعرض الفرعي للتطبيق المصغّر الذي يتم تقدّمه تلقائيًا من قِبل مضيف التطبيق المصغّر
widgetCategory تحديد ما إذا كان يمكن عرض تطبيقك المصغّر على الشاشة الرئيسية (home_screen) أو شاشة القفل (keyguard) أو كلتيهما بالنسبة إلى الإصدار 5.0 من نظام التشغيل Android والإصدارات الأحدث، تكون home_screen فقط صالحة.
widgetFeatures تحديد الميزات التي يتيحها التطبيق المصغّر على سبيل المثال، إذا كان إعداد تطبيقك المصغّر اختياريًا، حدِّد كلاً من configuration_optional وreconfigurable.

تحديد GlanceAppWidget

  1. عليك إنشاء فئة جديدة توسّع من GlanceAppWidget وتتجاوز طريقة provideGlance. هذه هي الطريقة التي يمكنك من خلالها تحميل البيانات اللازمة لعرض تطبيقك المصغّر:

    class MyAppWidget : GlanceAppWidget() {
    
        override suspend fun provideGlance(context: Context, id: GlanceId) {
    
            // In this method, load data needed to render the AppWidget.
            // Use `withContext` to switch to another thread for long running
            // operations.
    
            provideContent {
                // create your AppWidget here
                Text("Hello World")
            }
        }
    }

  2. عليك إنشاء مثيل له في glanceAppWidget على GlanceAppWidgetReceiver:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    
        // Let MyAppWidgetReceiver know which GlanceAppWidget to use
        override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
    }

لقد أعددت الآن AppWidget باستخدام Glance.

استخدِم فئة GlanceAppWidgetReceiver لمعالجة عمليات بث التطبيق المصغّر

تنسّق فئة GlanceAppWidgetReceiver عمليات بث التطبيق المصغّر وتعديلات حالة المنصة من خلال توسيع AppWidgetProvider الأساسي. تتلقّى هذه الفئة أحداث المنصة عند تعديل تطبيقك المصغّر أو حذفه أو تفعيله أو إيقافه، وتحوِّلها إلى طلبات دورة حياة Compose.

الإعلان عن تطبيق مصغّر في ملف البيان

عليك الإعلان عن الفئة الفرعية GlanceAppWidgetReceiver كمستقبِل عمليات بث في ملف AndroidManifest.xml:

<receiver android:name="ExampleAppWidgetReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/my_app_widget_info" />
</receiver>

يتطلّب العنصر <receiver> السمة android:name التي تحدّد فئة المستقبِل. يجب أن يقبل المستقبِل إجراء بث ACTION_APPWIDGET_UPDATE داخل <intent-filter>.

يجب أن يحدّد العنصر <meta-data> اسمه على أنّه android.appwidget.provider، ويجب أن تشير السمة android:resource إلى مصدر البيانات الوصفية بتنسيق XML لـ AppWidgetProviderInfo (@xml/my_app_widget_info).

تنفيذ فئة GlanceAppWidgetReceiver

في Glance، عليك توسيع GlanceAppWidgetReceiver بدلاً من AppWidgetProvider مباشرةً. عليك تنفيذ ذلك من خلال ربط المستقبِل بمثيل GlanceAppWidget. تعمل معاودات الاتصال الأساسية المتاحة في GlanceAppWidgetReceiver على النحو التالي:

  • onUpdate(): يتم تجاوزها تلقائيًا من قِبل Glance لتنفيذ تعديلات التركيب. إذا تجاوزت onUpdate يدويًا، عليك استدعاء super.onUpdate للسماح لـ Glance بتشغيل سلاسل تعليمات التركيب بنجاح.
  • onAppWidgetOptionsChanged(): يتم استدعاؤها عند وضع التطبيق المصغّر لأول مرة أو تغيير حجمه. يقرأ Glance عناصر حزمة الخيارات تحت الغطاء، لذا يتم تعديل التنسيق بسلاسة استنادًا إلى الأبعاد في وقت التشغيل.
  • onDeleted(Context, IntArray): يتم استدعاؤها كلما حذف المستخدِم مثيلاً معيّنًا من التطبيق المصغّر.
  • onEnabled(Context): يتم تشغيلها عند إنشاء أول مثيل من تطبيقك المصغّر بنجاح. هذه الطريقة ممتازة لتشغيل عمليات النقل العامة.
  • onDisabled(Context): يتم استدعاؤها عند إزالة آخر مثيل نشط من الموفِّر.
  • onReceive(Context, Intent): تعترض كل عمليات بث المنصة قبل طرق معاودة الاتصال المحدّدة. عليك التأكّد من أنّ أي منطق استقبال مخصّص تكتبه يستدعي super.onReceive(context, intent) ويجب ألا تستدعي goAsync بنفسك لأنّ Glance توجّه العمل تلقائيًا بشكل غير متزامن.

تلقّي أغراض بث التطبيق المصغّر

تحت الغطاء، تعمل فئة GlanceAppWidgetReceiver على فلترة أغراض بث التطبيق المصغّر الأساسية التالية ومعالجتها:

إنشاء واجهة المستخدم

يوضِّح المقتطف التالي كيفية إنشاء واجهة المستخدم:

/* Import Glance Composables
 In the event there is a name clash with the Compose classes of the same name,
 you may rename the imports per https://kotlinlang.org/docs/packages.html#imports
 using the `as` keyword.

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text
*/
class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // Load data needed to render the AppWidget.
        // Use `withContext` to switch to another thread for long running
        // operations.

        provideContent {
            // create your AppWidget here
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize(),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button(
                    text = "Home",
                    onClick = actionStartActivity<MyActivity>()
                )
                Button(
                    text = "Work",
                    onClick = actionStartActivity<MyActivity>()
                )
            }
        }
    }
}

ينفّذ نموذج الرمز البرمجي السابق ما يلي:

  • في Column على المستوى الأعلى، يتم وضع العناصر عموديًا واحدًا تلو الآخر.
  • يوسّع Column حجمه ليطابق المساحة المتاحة (من خلال الـ GlanceModifier ويضبط محتواه على أعلى (verticalAlignment) ومركزه أفقيًا (horizontalAlignment).
  • يتم تحديد محتوى Column باستخدام تعبير لامدا. الترتيب مهم.
    • العنصر الأول في Column هو مكوّن Text مع مساحة ترك مسافة داخلية تبلغ 12.dp.
    • العنصر الثاني هو Row، حيث يتم وضع العناصر أفقيًا واحدًا تلو الآخر، مع Buttons مركّزَين أفقيًا (horizontalAlignment). يعتمد العرض النهائي على المساحة المتاحة. تعرض الصورة التالية مثالاً على الشكل الذي قد يبدو عليه:
destination_widget
الشكل 1. مثال على واجهة مستخدم

يمكنك تغيير قيم المحاذاة أو تطبيق قيم معدِّل مختلفة (مثل مساحة الترك) لتغيير موضع المكوّنات وحجمها. راجِع المستندات المرجعية للحصول على قائمة كاملة بالمكوّنات والمعلّمات والمعدِّلات المتاحة لكل فئة.

تنفيذ الزوايا المستديرة

يطرح الإصدار 12 من نظام التشغيل Android معلّمات نظام لتخصيص أنصاف أقطار زوايا التطبيقات المصغّرة ديناميكيًا:

  • system_app_widget_background_radius: تحديد نصف قطر زاوية حاوية خلفية التطبيق المصغّر (لا يكون أكبر من 28 dp أبدًا)
  • نصف القطر الداخلي: لمنع اقتصاص المحتوى، عليك احتساب نصف قطر متناسب للمحتوى الداخلي استنادًا إلى المخطط التفصيلي لخلفية النظام: systemRadiusValue - widgetPadding

في Glance، يمكنك تطبيق خصائص تغيير حجم نصف القطر ديناميكيًا في التركيب باستخدام GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius).

لضمان التوافق مع الأنظمة القديمة على الأجهزة التي تعمل بالإصدار 11 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 30) أو الإصدارات الأقدم، عليك تنفيذ سمات مخصّصة وعمليات رجوع مخصّصة لموارد المظهر:

  • /values/attrs.xml

    <resources>
    <attr name="backgroundRadius" format="dimension" />
    </resources>
    
  • /values/styles.xml

    <resources>
    <style name="MyWidgetTheme">
      <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
    </style>
    </resources>
    
  • /values-31/styles.xml

    <resources>
    <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
      <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
    </style>
    </resources>
    
  • /drawable/my_widget_background.xml

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="?attr/backgroundRadius" />
    </shape>