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

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

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

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

للحصول على معلومات حول طريقة تصميم تطبيقك المصغّر، يُرجى الاطّلاع على نظرة عامة على أدوات التطبيقات.

مكونات الأداة

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

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

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

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

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

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

تعريف ملف AppWidgetProviderInfo بتنسيق XML

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

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

نظام التشغيل 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 تحدد هذه السمة النشاط الذي يتم إطلاقه عندما يضيف المستخدم الأداة، ما يتيح له ضبط خصائص الأداة. راجِع تفعيل المستخدمين لضبط التطبيقات المصغّرة. بدءًا من نظام التشغيل Android 12، يمكن لتطبيقك تخطي الإعدادات الأولية. راجِع استخدام الإعدادات التلقائية للتطبيق المصغّر للحصول على التفاصيل.
description تحدّد هذه السمة الوصف الذي سيعرضه أداة اختيار التطبيقات المصغّرة. تم طرحه في نظام التشغيل Android 12.
previewLayout (Android 12) وpreviewImage (Android 11 والإصدارات الأقدم)
  • بدءًا من نظام التشغيل Android 12، تحدّد السمة previewLayout معاينة قابلة للتطوير يتم توفيرها كتنسيق XML يتم ضبطه على الحجم التلقائي للأداة. ومن الناحية المثالية، يكون تنسيق XML المحدّد لهذه السمة هو تنسيق XML نفسه الذي يتضمّن التطبيق المصغّر الفعلي مع قيم تلقائية واقعية.
  • في نظام التشغيل Android 11 أو الإصدارات الأقدم، تحدد السمة 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: يحتوي على الحد الأعلى لعرض مثيل الأداة، بوحدات بكسل مستقلة الكثافة.
  • OPTION_APPWIDGET_MAX_HEIGHT: يحتوي على الحد الأقصى للارتفاع، بوحدات بكسل مستقلة الكثافة، لمثيل تطبيق مصغّر.
  • 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 غير مرئي بحجم صفري يمكنك استخدامه لتضخيم موارد التنسيق في وقت التشغيل.

دعم السلوك المستنِد إلى حالة

يتيح الإصدار 12 من نظام التشغيل Android إمكانية التحكّم بسلوك حالات الرصد باستخدام المكوّنات الحالية التالية:

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

مثال على تطبيق مصغّر لقائمة التسوّق يعرض سلوكًا يؤدي إلى بيانات الحالة
الشكل 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 وحدة بكسل مستقلة الكثافة.

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

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

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

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

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

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

  • ويمكن لمشغِّلات التطبيقات التابعة لجهات خارجية والشركات المصنّعة للأجهزة إلغاء مَعلمة system_app_widget_background_radius لتصبح أصغر من 28 وحدة بكسل مستقلة الكثافة. وتكون المَعلمة system_app_widget_inner_radius دائمًا أقلّ بمقدار 8 وحدات بكسل مستقلة الكثافة (dp) من قيمة system_app_widget_background_radius.
  • إذا كان التطبيق المصغّر لا يستخدم @android:id/background أو يحدّد خلفية يتم فيها اقتصاص المحتوى استنادًا إلى المخطط، مع ضبط قيمة android:clipToOutline على true، سيحدّد مشغّل التطبيقات الخلفية تلقائيًا ويقتطع التطبيق المصغّر باستخدام مستطيل بزوايا مستديرة تصل إلى 16 وحدة بكسل مستقلة الكثافة. يُرجى الاطّلاع على التأكد من توافق التطبيق المصغّر مع 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" />