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

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

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

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

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

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

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

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

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

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

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

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

إدراج ملف 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.

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

استخدِم السمتَين 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: يحتوي على الحد الأدنى لعرض مثيل التطبيق المصغّر، بوحدات dp.
  • OPTION_APPWIDGET_MIN_HEIGHT: يحتوي على الحد الأدنى للارتفاع، بوحدات dp، لحالة التطبيق المصغّر.
  • 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)

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

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

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

أهم AppWidgetProvider callback هو 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.

يتيح RemoteViews أيضًا استخدام ViewStub، وهو View غير مرئي وحجمه صفر يمكنك استخدامه لتضخيم موارد 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" />