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

توضّح الأقسام التالية كيفية إنشاء أداة تطبيق أساسية باستخدام 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 هو أنّه لا يتضمّن ملف initialLayout XML، ولكن عليك تحديد ملف. يمكنك استخدام تصميم التحميل المحدّد مسبقًا والمضمّن في المكتبة:

<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 أو إذا لم يتم تفعيل تغيير الحجم عموديًا. تم طرح هذه الميزة في Android 12.
resizeMode تحدّد هذه السمة القواعد التي يمكن بموجبها تغيير حجم التطبيق المصغّر. يمكنك استخدام هذه السمة لتغيير حجم التطبيقات المصغّرة على الشاشة الرئيسية أفقيًا أو عموديًا أو على كلا المحورين. ينقر المستخدمون مع الاستمرار على تطبيق مصغّر لعرض مقابض تغيير الحجم، ثم يسحبون المقابض الأفقية أو العمودية لتغيير حجمه على شبكة التصميم. تتضمّن قيم السمة resizeMode ما يلي: horizontal وvertical وnone. لتحديد أنّ التطبيق المصغّر قابل لتغيير الحجم أفقيًا وعموديًا، استخدِم horizontal|vertical.

مثال

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

  • يبلغ عرض خلية الشبكة 30 بكسل غير مرتبط بالكثافة وطولها 50 بكسل غير مرتبط بالكثافة.
  • يتم توفير مواصفات السمة التالية:
<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" />

بدءًا من Android 12:

استخدِم السمتَين targetCellWidth وtargetCellHeight لتحديد المقاس التلقائي للأداة.

يبلغ حجم التطبيق المصغّر 2x2 تلقائيًا. يمكن تغيير حجم التطبيق المصغّر إلى 2x1 أو 4x3.

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

استخدِم السمتَين minWidth وminHeight لاحتساب الحجم التلقائي للأداة.

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

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

يكون حجم التطبيق المصغّر 3x2 تلقائيًا. يمكن تغيير حجم التطبيق المصغّر إلى 2x1 أو أكبر إلى وضع ملء الشاشة.

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

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

السمات والوصف
updatePeriodMillis تحدّد هذه السمة عدد المرات التي يطلب فيها إطار عمل التطبيق المصغّر إجراء تعديل من GlanceAppWidgetReceiver من خلال استدعاء طريقة رد الاتصال onUpdate(). ننصحك بتحديثها بأقل قدر ممكن من التكرار، أي مرة واحدة كل ساعة كحد أقصى، للحفاظ على عمر البطارية. لمزيد من التفاصيل، يُرجى الاطّلاع على القسم الحالات التي يجب فيها تعديل التطبيقات المصغّرة في مقالة "إدارة حالة Glance".
initialLayout يشير إلى مورد التصميم الذي يحدّد تصميم التحميل للأداة قبل عرض تركيبات واجهة مستخدم Glance. يمكنك استخدام تنسيق التحميل المحدّد مسبقًا والمضمّن في المكتبة: @layout/glance_default_loading_layout.
configure تحدّد هذه السمة نشاط الإعداد الذي يتم تشغيله عندما يضيف المستخدم الأداة. راجِع دليل تنفيذ نشاط الإعداد.
description تحدّد هذه السمة الوصف الذي ستعرضه أداة اختيار التطبيقات المصغّرة للتطبيق المصغّر. تم طرح هذه الميزة في Android 12.
previewLayout (الإصدار 12 من نظام التشغيل Android) وpreviewImage (الإصدار 11 من نظام التشغيل Android والإصدارات الأقدم)
  • بدءًا من الإصدار 12 من نظام التشغيل Android، تحدّد السمة previewLayout معاينة قابلة للتوسيع، وتوفّرها كمجموعة تنسيق XML مضبوطة على الحجم التلقائي للأداة. من المفترض أن يشير ذلك إلى عملية تعيين ثابتة بتنسيق XML تتطابق مع تخطيط تصميمك.
  • في نظام التشغيل Android 11 أو الإصدارات الأقدم، تحدّد السمة 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(): يتم استدعاؤها عند وضع التطبيق المصغّر للمرة الأولى أو عند تغيير حجمه. تجمع خيارات القراءة السريعة العناصر في الخلفية، ما يتيح تعديل التصميم بسلاسة استنادًا إلى أبعاد وقت التشغيل.
  • onDeleted(Context, IntArray): يتم استدعاؤه عندما يحذف المستخدم مثيلاً معيّنًا من أداة.
  • onEnabled(Context): يتم تفعيل هذا الحدث عند إنشاء أول مثيل للأداة بنجاح. وهي ممتازة لتنفيذ عمليات نقل البيانات على مستوى العالم.
  • onDisabled(Context): يتم استدعاؤه عند إزالة آخر مثيل نشط للموفّر.
  • onReceive(Context, Intent): يعترض كل عملية بث على المنصة قبل تنفيذ طرق معاودة الاتصال المحدّدة. يجب التأكّد من أنّ أي منطق مخصّص لجهاز الاستقبال تكتبه يستدعي super.onReceive(context, intent)، ويجب ألا يستدعي goAsync بنفسك لأنّ Glance يوجّه العمل تلقائيًا بشكل غير متزامن.

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

في الخلفية، تعمل GlanceAppWidgetReceiver على فلترة ومعالجة ما يلي من أغراض البث الأساسية الخاصة بأداة المنصة:

Create UI

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

/* 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 باستخدام تعبير lambda. الترتيب مهم.
    • العنصر الأول في Column هو مكوّن Text يتضمّن مساحة متروكة تبلغ 12.dp.
    • العنصر الثاني هو Row، حيث يتم وضع العناصر أفقيًا واحدًا تلو الآخر، مع وضع Buttons في المنتصف أفقيًا (horizontalAlignment). يعتمد العرض النهائي على المساحة المتاحة. تعرض الصورة التالية مثالاً على الشكل الذي قد تبدو عليه:
destination_widget
الشكل 1. مثال على واجهة المستخدم

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

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

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

  • system_app_widget_background_radius: تحدّد هذه السمة نصف قطر زاوية حاوية خلفية التطبيق المصغّر (يجب ألا يتجاوز 28 وحدة بكسل مستقلة الكثافة).
  • نصف القطر الداخلي: لمنع قص المحتوى، احسب نصف قطر متناسبًا للمحتوى الداخلي استنادًا إلى المخطط التفصيلي لخلفية النظام: 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>