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

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

يكون حجم الأداة 2x2 افتراضيًا. يمكن تغيير حجم الأداة إلى 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: يحتوي على الحد الأعلى لعرض نسخة التطبيق المصغّر، بوحدات بكسل مستقل الكثافة.
  • 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 غير مرئي وبحجم صفري ويمكنك استخدامه لتضخيم موارد التنسيق عند وقت التشغيل.

دعم السلوك المرتبط بالحالة

يتيح نظام التشغيل 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، والآخر يستهدف الأجهزة السابقة التي تعمل بالإصدار Android 11 أو الإصدارات الأقدم في مجلد 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 دائمًا أقل من قيمة system_app_widget_background_radius بمقدار 8 بكسل مستقل الكثافة.
  • إذا كان التطبيق المصغّر لا يستخدم العلامة @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" />