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

توضِّح الأقسام التالية كيفية إنشاء تطبيق مصغّر أساسي باستخدام 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>

الإعلان عن AppWidgetProviderInfo XML

يحدّد العنصر 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="MyReceiver"
          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>