إنشاء تطبيق مصغّر بسيط

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

مثال على تطبيق مصغّر للموسيقى
الشكل 1. مثال على تطبيق مصغّر للموسيقى

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

للحصول على معلومات عن كيفية تصميم التطبيق المصغّر، اطّلِع على نظرة عامة على التطبيقات المصغّرة.

مكونات التطبيقات المصغّرة

لإنشاء تطبيق مصغّر، تحتاج إلى المكوّنات الأساسية التالية:

عنصر AppWidgetProviderInfo
يصف البيانات الوصفية لأداة مصغّرة، مثل تنسيق الأداة المصغّرة ومعدّل التعديل وAppWidgetProvider. يتم تعريف AppWidgetProviderInfo في ملف XML، كما هو описан في هذا المستند.
صف واحد (AppWidgetProvider)
يحدِّد هذه الواجهة الطرق الأساسية التي تتيح لك التفاعل مع القطعة المكوّنة من البرنامج. من خلال هذا البث، تتلقّى إشعارات عند تعديل التطبيق المصغّر أو تفعيله أو إيقافه أو حذفه. أنت تعلن عن AppWidgetProvider في البيان ثم تنفّذها على النحو الموضّح في هذا المستند.
تنسيق العرض
تحدِّد التنسيق الأولي للأداة. يتم تحديد التنسيق بتنسيق XML، كما هو موضّح في هذا المستند.

يوضّح الشكل 2 كيفية ملاءمة هذه المكوّنات في مسار معالجة التطبيقات المصغرة بشكل عام.

مسار معالجة التطبيقات المصغّرة
الشكل 2. عملية معالجة التطبيق المصغّر

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

ننصحك أيضًا بإجراء التحسينات التالية: تنسيقات مرنة للأدوات وتحسينات متنوعة وأدوات متقدّمة وأدوات مجموعات وإنشاء مضيف أدوات.

إدراج ملف XML الخاص بـ AppWidgetProviderInfo

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

يظهر ذلك في المثال التالي:

<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/example_loading_appwidget"
    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 (Android 12)، minWidth وminHeight
  • بدءًا من الإصدار 12 من Android، تحدِّد السمتَان targetCellWidth وtargetCellHeight المقاس التلقائي للأداة من حيث خلايا الشبكة. يتم تجاهل هذه السمات في الإصدار 11 من Android والإصدارات الأقدم، ويمكن تجاهلها إذا كانت الشاشة الرئيسية لا تسمح بعرض المحتوى بتنسيق شبكي.
  • تحدّد السمتَان minWidth minHeight المقاس التلقائي للتطبيق المصغّر بالنقاط. في حال كانت قيم الحد الأدنى للعرض أو الارتفاع الخاص بالتطبيق المصغّر لا تتطابق مع أبعاد الخلايا، يتم تقريب القيم إلى أقرب حجم للخلية.
ننصح بتحديد مجموعتَي السمات، 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 كحجم تلقائي للتطبيق المصغّر.

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

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

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

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

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

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

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

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

السمات والوصف
updatePeriodMillis تحدّد هذه السياسة عدد المرات التي يطلب فيها إطار العمل المصغّر تعديلاً من AppWidgetProvider من خلال استدعاء طريقة استدعاء onUpdate(). لا يمكن ضمان أن يتم إجراء التحديث الفعلي في الوقت المحدَّد بالضبط باستخدام هذه القيمة، وننصح بإجراء التحديث بقدرٍ متعافٍ من الإمكان، أي مرة واحدة في الساعة كحد أقصى، للحفاظ على شحن البطارية. للحصول على القائمة الكاملة للعوامل التي يجب مراعاتها لاختيار فترة تعديل مناسبة، يُرجى الاطّلاع على التحسينات لتعديل محتوى التطبيقات المصغّرة.
initialLayout تشير إلى مورد التنسيق الذي يحدِّد تنسيق التطبيق المصغّر.
configure تحدد هذه السمة النشاط الذي يبدأ عندما يضيف المستخدم الأداة، وتسمح له بضبط خصائص الأداة. اطّلِع على السماح للمستخدمين بضبط التطبيقات المصغّرة. بدءًا من الإصدار 12 من Android، يمكن لتطبيقك تخطّي الإعدادات الأولية. اطّلِع على استخدام الإعدادات التلقائية للتطبيق المصغّر لمعرفة التفاصيل.
description لتحديد وصف لأداة اختيار التطبيقات المصغّرة لعرضه في تطبيقك المصغّر. تم طرحها في Android 12.
previewLayout (Android 12) وpreviewImage (Android 11 والإصدارات الأقدم)
  • بدءًا من الإصدار 12 من نظام التشغيل Android، تحدّد السمة previewLayout معاينة قابلة للتوسّع تقدّمها كتنسيق XML تم ضبطه على الحجم التلقائي للأداة. من الأفضل أن يكون ملف XML الخاص بالتنسيق الذي تم تحديده لهذه السمة هو ملف XML الخاص بالتنسيق نفسه في العنصر المكوّن الفعلي مع قيم تلقائية واقعية.
  • في الإصدار 11 من نظام التشغيل Android أو الإصدارات الأقدم، تحدِّد السمة previewImage معاينة لشكل التطبيق المصغّر بعد ضبطه، ويظهر ذلك للمستخدِم عند اختيار التطبيق المصغّر. وإذا لم يتم تقديمه، سيظهر للمستخدم رمز مشغّل تطبيقك بدلاً من ذلك. يتطابق هذا الحقل مع سمة android:previewImage في عنصر <receiver> فيملف AndroidManifest.xml.
ملاحظة: نقترح عليك تحديد السمتَين previewImage وpreviewLayout ليتمكّن تطبيقك من استخدام previewImage مرة أخرى إذا كان جهاز المستخدم لا يتوافق مع previewLayout. لمزيد من التفاصيل، راجِع التوافق مع الإصدارات القديمة مع معاينات التطبيقات المصغّرة القابلة للتطوير.
autoAdvanceViewId يحدِّد رقم تعريف العرض لعرض التطبيق المصغّر الفرعي الذي يتم تقديمه تلقائيًا من قِبل مضيف التطبيق المصغّر.
widgetCategory يُستخدَم هذا السمة للإشارة إلى ما إذا كان يمكن عرض التطبيق المصغّر على الشاشة الرئيسية (home_screen) أو شاشة القفل (keyguard) أو كليهما. بالنسبة إلى الإصدار 5.0 من Android والإصدارات الأحدث، يكون الخيار home_screen صالحًا فقط.
widgetFeatures يُستخدَم لتعريف الميزات المتوافقة مع التطبيق المصغّر. على سبيل المثال، إذا كنت تريد أن يستخدم التطبيق المصغّر الإعدادات التلقائية عند إضافته من قِبل المستخدم، حدِّد كلاً من علامتَي configuration_optional و reconfigurable. يؤدي ذلك إلى تجاوز عملية إطلاق نشاط الضبط بعد أن يُضيف المستخدم التطبيق المصغّر. وسيظل بإمكان المستخدم إعادة ضبط التطبيق المصغّر بعد ذلك.

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

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

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

أولاً، عليك تعريف فئة AppWidgetProvider في ملف AndroidManifest.xml لتطبيقك، كما هو موضّح في المثال التالي:

<receiver android:name="ExampleAppWidgetProvider"
                 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/example_appwidget_info" />
</receiver>

يتطلّب عنصر <receiver> السمة android:name التي تحدّد AppWidgetProvider المستخدَم في التطبيق المصغّر. يجب عدم تصدير المكوّن ما لم تكن هناك عملية منفصلة تحتاج إلى البث إلى AppWidgetProvider، وهو ما لا يحدث عادةً.

يجب أن يشتمل العنصر <intent-filter> على عنصر <action> مع السمة android:name. تحدد هذه السمة أنّ السمة AppWidgetProvider تقبل البث ACTION_APPWIDGET_UPDATE. وهذا هو البث الوحيد الذي يجب الإفصاح عنه صراحةً. ترسل AppWidgetManager تلقائيًا جميع عمليات بث التطبيقات المصغّرة الأخرى إلى AppWidgetProvider حسب الضرورة.

يحدِّد عنصر <meta-data> المورد AppWidgetProviderInfo ويتطلب السمات التالية:

  • android:name: لتحديد اسم البيانات الوصفية استخدِم android.appwidget.provider لتحديد البيانات على أنّها وصف AppWidgetProviderInfo.
  • android:resource: لتحديد مكان موارد AppWidgetProviderInfo

تنفيذ فئة AppWidgetProvider

تزيد الفئة AppWidgetProvider من BroadcastReceiver كفئة ملائمة للتعامل مع عمليات بث التطبيقات المصغّرة. ولا يتلقّى سوى أحداث البث ذات الصلة بالتطبيق المصغّر، مثل عند تعديل التطبيق المصغّر أو حذفه أو تفعيله أو إيقافه. عند حدوث أحداث البث هذه، يتمّ استدعاء مثيلَي AppWidgetProvider التاليَين:

onUpdate()
يسمى ذلك بتحديث الأداة على الفواصل الزمنية التي تحدّدها السمة updatePeriodMillis في AppWidgetProviderInfo. اطّلِع على الجدول الذي يصف سمات التطبيقات المصغّرة الإضافية في هذه الصفحة للحصول على مزيد من المعلومات.
يتم أيضًا استدعاء هذه الطريقة عندما يضيف المستخدم التطبيق المصغّر، لذلك تُجري الإعدادات الأساسية، مثل تحديد عناصر معالجة الأحداث لعناصر View أو بدء مهام لتحميل البيانات بهدف عرضها في التطبيق المصغّر. ومع ذلك، إذا أوضحت عن نشاط ضبط بدون العلامة configuration_optional، لن يتم استدعاء هذه الطريقة عند إضافة المستخدم للأداة، ولكن يتم طلبها لإجراء التحديثات اللاحقة. تقع على عاتق نشاط الضبط مسؤولية إجراء التعديل الأول عند اكتمال الضبط. اطّلِع على السماح للمستخدمين بضبط التطبيقات المصغّرة للحصول على مزيد من المعلومات.
أهم معاودة الاتصال هي onUpdate(). اطّلِع على معالجة الأحداث باستخدام فئة onUpdate() في هذه الصفحة للحصول على مزيد من المعلومات.
onAppWidgetOptionsChanged()

يتمّ استدعاء هذا الإجراء عند وضع التطبيق المصغّر لأول مرّة وفي أيّ وقت يتم فيه تغيير حجم التطبيق المصغّر. يمكنك استخدام رد الاتصال هذا لإظهار المحتوى أو إخفائه استنادًا إلى نطاقات حجم الأداة. احصل على نطاقات الأحجام، وبدءًا من نظام التشغيل Android 12، قائمة بالأحجام المحتملة التي يمكن أن يتخذها مثيل الأداة، عن طريق طلب البيانات getAppWidgetOptions()، التي تعرض الرمز Bundle الذي يتضمّن ما يلي:

  • OPTION_APPWIDGET_MIN_WIDTH: يحتوي على الحد الأدنى لعرض التطبيق المصغّر، بوحدات البكسل التدريجي.
  • OPTION_APPWIDGET_MIN_HEIGHT: تحتوي على الحد الأدنى على ارتفاع مثيل التطبيق المصغّر، بوحدات البكسل التدريجي.
  • OPTION_APPWIDGET_MAX_WIDTH: يحتوي على الحد الأقصى لعرض مثيل التطبيق المصغّر، بوحدات dp.
  • OPTION_APPWIDGET_MAX_HEIGHT: يحتوي على الحد الأقصى للارتفاع، بوحدات dp، لمثيل التطبيق المصغّر.
  • OPTION_APPWIDGET_SIZES: تحتوي على قائمة بالأحجام المحتملة (List<SizeF>) التي يمكن أن تأخذها نسخة التطبيق المصغّر، وذلك بوحدات dp. تم طرحها في Android 12.
onDeleted(Context, int[])

ويسمى ذلك في كل مرة يتم فيها حذف تطبيق مصغّر من مضيف الأداة.

onEnabled(Context)

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

onDisabled(Context)

يتمّ استدعاء هذا الإجراء عند حذف آخر نسخة من تطبيقك المصغّر من مضيف تطبيقك المصغّر. يمكنك هنا تنظيف أي عمل تم إجراؤه في onEnabled(Context)، مثل حذف قاعدة بيانات مؤقتة.

onReceive(Context, Intent)

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

يجب الإفصاح عن تنفيذ فئة AppWidgetProvider كمستقبل إعلام باستخدام عنصر <receiver> في AndroidManifest. اطّلِع على تعريف ملف تعريف تطبيق مصغّر في البيان في هذه الصفحة للحصول على مزيد من المعلومات.

التعامل مع الأحداث باستخدام فئة onUpdate()

وأهم استدعاء لـ AppWidgetProvider هو onUpdate()، لأنّه يتم استدعاؤه عند إضافة كل تطبيق مصغّر إلى مضيف ما لم تستخدم نشاط ضبط بدون علامة configuration_optional. إذا كانت الأداة تقبل أي أحداث تفاعل مع المستخدم، سجِّل معالِجات الأحداث في هذه الوظيفة المُعاد الاتصال بها. إذا كانت التطبيقات المصغّرة لا تنشئ ملفات أو قواعد بيانات مؤقتة أو لا تُجري عملاً آخر يتطلّب التنظيف، قد تكون onUpdate() هي طريقة الاستدعاء الوحيدة التي تحتاج إلى تحديدها.

على سبيل المثال، إذا كنت تريد تطبيقًا مصغّرًا يحتوي على زر يؤدي إلى بدء نشاط عند النقر عليه، يمكنك استخدام التنفيذ التالي لعنصر AppWidgetProvider:

Kotlin

class ExampleAppWidgetProvider : AppWidgetProvider() {

    override fun onUpdate(
            context: Context,
            appWidgetManager: AppWidgetManager,
            appWidgetIds: IntArray
    ) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        appWidgetIds.forEach { appWidgetId ->
            // Create an Intent to launch ExampleActivity.
            val pendingIntent: PendingIntent = PendingIntent.getActivity(
                    /* context = */ context,
                    /* requestCode = */  0,
                    /* intent = */ Intent(context, ExampleActivity::class.java),
                    /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            val views: RemoteViews = RemoteViews(
                    context.packageName,
                    R.layout.appwidget_provider_layout
            ).apply {
                setOnClickPendingIntent(R.id.button, pendingIntent)
            }

            // Tell the AppWidgetManager to perform an update on the current
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }
}

Java

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Perform this loop procedure for each widget that belongs to this
        // provider.
        for (int i=0; i < appWidgetIds.length; i++) {
            int appWidgetId = appWidgetIds[i];
            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                /* context = */ context,
                /* requestCode = */ 0,
                /* intent = */ intent,
                /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
            );

            // Get the layout for the widget and attach an onClick listener to
            // the button.
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app
            // widget.
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

لا يحدِّد هذا العنصر AppWidgetProvider سوى طريقة onUpdate()، ويستخدمها لإنشاء PendingIntent لتشغيل Activity وإرفاقه بالزر المخصّص للتطبيق المصغّر باستخدام setOnClickPendingIntent(int, PendingIntent). يتضمّن حلقة تتكرّر في كل إدخال في appWidgetIds، وهي صفيف من المعرّفات التي تحدّد كل تطبيق مصغّر أنشأه هذا الموفّر. إذا أنشأ المستخدم أكثر من مثيل واحد من التطبيق المصغّر، تتم تعديلها كلها في الوقت نفسه. ومع ذلك، يتمّ إدارة جدول زمني واحد فقطupdatePeriodMillis لجميع نُسخ التطبيق المصغّر. على سبيل المثال، إذا تم تحديد جدول التحديث ليكون كل ساعتَين، وتمّت إضافة مثيل ثانٍ من التطبيق المصغّر بعد ساعة من المثيل الأول، سيتم تعديل كليهما خلال الفترة المحدّدة بالمثيل الأول، ويتم تجاهل فترة التعديل الثانية. يتم تحديث كلتا الخدمتَين كل ساعتين، وليس كل ساعة.

اطّلِع على مزيد من التفاصيل في ملف نموذج الصف التالي: ExampleAppWidgetProvider.java.

تلقّي أهداف بث التطبيق المصغّر

AppWidgetProvider هي فئة مناسبة. إذا كنت تريد تلقّي بث التطبيقات المصغّرة مباشرةً، يمكنك تنفيذ BroadcastReceiver أو إلغاء onReceive(Context,Intent) المرجع المخصّص للاتصال. النوايا التي يجب الاهتمام بها هي ما يلي:

إنشاء تنسيق التطبيق المصغّر

يجب تحديد تنسيق أولي لأداة التطبيقات المصغّرة بتنسيق XML وحفظه في دليل res/layout/ المشروع. يُرجى الرجوع إلى إرشادات التصميم للاطّلاع على التفاصيل.

إنّ إنشاء تنسيق الأداة أمر سهل إذا كنت على دراية بالتنسيقات. يُرجى العِلم أنّ تصاميم التطبيقات المصغّرة تستند إلى RemoteViews، التي لا تتوافق مع كل أنواع تصاميم التطبيقات المصغّرة أو طرق عرضها. لا يمكنك استخدام طرق عرض مخصّصة أو فئات فرعية لطرق العرض المتوافقة مع "RemoteViews".

يتوافق RemoteViews أيضًا مع ViewStub، وهو رمز View غير مرئي وبحجم صفري ويمكنك استخدامه لتضخيم موارد التنسيق عند وقت التشغيل.

إتاحة السلوك الذي يعتمد على الحالة

يضيف نظام التشغيل Android 12 إمكانية استخدام السلوك المستند إلى الحالة باستخدام المكونات التالية الحالية:

لا تزال الأداة بلا حالة. يجب أن يخزِّن تطبيقك الحالة وأن يسجِّل أحداث تغيير الحالة.

مثال على تطبيق مصغّر لقائمة التسوّق يعرض سلوكًا يعتمد على الحالة
الشكل 3. مثال على السلوك القائم على الحالة

يوضّح مثال الرمز التالي كيفية تنفيذ هذه المكوّنات.

Kotlin

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
        R.id.my_checkbox,
        RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)

Java

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true);

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2);

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
    R.id.my_checkbox,
    RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));

قدِّم تنسيقَين: أحدهما يستهدف الأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android أو إصدارًا أحدث في res/layout-v31، والآخر يستهدف الإصدار السابق 11 من نظام التشغيل Android أو إصدارًا أقدم في مجلد res/layout التلقائي.

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

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

  • system_app_widget_background_radius: نصف قطر الزاوية لخلفية التطبيق المصغّر، والذي لا يتجاوز أبدًا 28 dp

  • system_app_widget_inner_radius: نصف قطر الزاوية لأي عرض داخل التطبيق المصغّر وهذا أقل بـ 8 dp بالضبط من نصف قطر الخلفية، وذلك لمحاذاة العناصر بشكل جيد عند استخدام مسافة بادئة بحجم 8 dp.

يعرض المثال التالي تطبيقًا مصغّرًا يستخدم system_app_widget_background_radius لزاوية التطبيق المصغّر و system_app_widget_inner_radius للعروض داخل التطبيق المصغّر.

تطبيق مصغّر يعرض أقطار خلفية التطبيق المصغّر وطرق العرض داخل التطبيق المصغّر
الشكل 4. زوايا دائرية

1 زاوية التطبيق المصغّر

2 زاوية عرض داخل التطبيق المصغّر

اعتبارات مهمة للزوايا المستديرة

  • يمكن لمطوّري مشغّلات التطبيقات الخارجية وشركات تصنيع الأجهزة إلغاء المَعلمة system_app_widget_background_radius لتكون أصغر من 28 dp. تكون المَعلمة system_app_widget_inner_radius دائمًا أصغر من قيمة system_app_widget_background_radius بمقدار 8 dp.
  • إذا لم يستخدم التطبيق المصغّر @android:id/background أو لم يحدِّد خلفية تقتطع محتواه استنادًا إلى المخطط، مع ضبط android:clipToOutline على true، سيحدِّد مشغّل التطبيقات الخلفية تلقائيًا ويقصّ التطبيق المصغّر باستخدام مستطيل بزوايا مُدوَّرة يصل قطرها إلى 16 dp. اطَّلِع على التأكد من توافق التطبيق المصغّر مع Android 12.

لضمان توافق التطبيقات المصغّرة مع الإصدارات السابقة من Android، ننصحك بتحديد سمات مخصّصة واستخدام مظهر مخصّص لاستبدالها في الإصدار 12 من Android، كما هو موضّح في نموذج ملفات XML التالي:

/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>

/layout/my_widget_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:background="@drawable/my_widget_background" />