استخدام إشعارات Android

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

مقدمة

الإشعارات هي رسائل تظهر للمستخدم خارج واجهة مستخدم التطبيق. تظهر الإشعارات في أعلى الشاشة إذا كان الجهاز غير مقفل أو استنادًا إلى إعدادات الأمان على شاشة القفل عندما يكون الجهاز مقفلاً.

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

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

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

في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية إنشاء الإشعارات واستخدامها في تطبيق متوافق مع Android.

ما يجب معرفته

ويجب أن تكون على دراية بما يلي:

  • كيفية إنشاء تطبيقات Android في Kotlin. وعلى وجه الخصوص، يمكنك العمل مع Android SDK.
  • كيفية تصميم بنية أساسية باستخدام "مكونات البنية" وربط البيانات.
  • فهم أساسي لأجهزة BroadcastReceivers
  • فهم أساسيات AlarmManager

ما ستتعرَّف عليه

  • كيفية إنشاء إشعار وتصميمه وإرساله.
  • كيفية إلغاء الإشعارات.
  • كيفية إنشاء قنوات الإشعارات
  • كيفية إضافة إجراءات سريعة إلى الإشعارات
  • طريقة عرض شارات الإشعارات على رمز التطبيق.

الإجراءات التي ستنفذّها

  • أضِف إشعارًا إلى تطبيق إجراء التفعيل.
  • ألغِ الإشعار الذي أرسلته سابقًا.
  • أنشئ قنوات لأنواع مختلفة من الإشعارات.
  • يمكنك تخصيص الإشعارات في تطبيق إجراء التفعيل.
  • يمكنك إضافة إجراءات سريعة لجعل الإشعار تفاعليًا.
  • أوقِف شارات الإشعارات.

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

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

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

للحصول على نموذج التطبيق، يمكنك تنفيذ أي مما يلي:

يمكنك نسخ المستودع من GitHub والتبديل إلى الفرع Starter.

$  git clone https://github.com/googlecodelabs/android-kotlin-notifications


بدلاً من ذلك، يمكنك تنزيل المستودع كملف Zip وفك ضغطه وفتحه في"استوديو Android".

تنزيل ملف Zip

  1. افتح التطبيق وشغِّله في "استوديو Android".

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

  1. افحص رمز المصدر. يتكون تطبيق إجراء التفعيل من نشاط واحد يُسمى MainActivity. هناك ثلاث حِزم فرعية باسم receiver وui وutil.

  • /receiver: تحتوي حزمة receiver على جهازَي استقبال، وهما AlarmReceiver وSnoozeReceiver. يتم تشغيل AlarmReceiver بواسطة AlarmManager لإرسال الإشعار عند انتهاء المؤقت الذي يحدده المستخدم. يتعامل SnoozeReceiver مع نقرة المستخدم لتأجيل الإشعار.
  • /ui: يحتوي هذا العمود على EggTimerFragment التي تشكّل جزءًا من جزء واجهة المستخدم في التطبيق. وتقع على EggTimerViewModel مسؤولية بدء الموقّت وإلغائه ومهام التطبيق الأخرى المتعلقة بمراحل الحياة.
  • /util: في هذه الحزمة، هناك ملفان. يحتوي BindingUtils.kt على محوّلات ربط لتفعيل ربط البيانات بين واجهة مستخدم التطبيق وViewModel. NotificationUtils.kt لديه طرق إضافة على NotificationManager.

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

الخطوة 1: إنشاء إشعار أساسي

في هذه المهمة، يتم إنشاء إشعار جديد وإعداد رسالة للمستخدم وإرسال الإشعار.

  1. افتح الصف NotificationUtils.kt وابحث عن TODO: Step 1.1. ستجد&#39، مهام المطابقة في هذا الدرس التطبيقي ورمز التطبيق.
  2. افحص الدالة sendNotification() المحدّدة. سيتم توسيع دالة الإضافة هذه إلى NotificationManager لإرسال الإشعارات.
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
 * Builds and delivers a notification.
 *
 * @param messageBody, notification text.
 * @param context, activity context.
 */
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
  1. احصل على مثيل لأداة إنشاء الإشعارات، ووفّر في سياق التطبيق ومعرّف القناة. معرّف القناة هو قيمة سلسلة للقناة.

قنوات الإشعارات هي طريقة لتجميع الإشعارات. ومن خلال تجميع أنواع إشعارات مشابهة معًا، يمكن لمطوّري البرامج والمستخدمين التحكّم في كل الإشعارات في القناة. وبعد إنشاء القناة، يمكن استخدامها لإرسال أي عدد من الإشعارات.

//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
        applicationContext,
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. يمكنك ضبط رمز الإشعار ليمثّل تطبيقك وعنوانًا ونص المحتوى للرسالة التي تريد إرسالها إلى المستخدم. سترى المزيد من الخيارات لتخصيص الإشعار مرة أخرى في درس تطبيقي حول الترميز، ولكن هذا هو الحد الأدنى للبيانات التي تحتاج إلى إعدادها لإرسال إشعار.
//NotificationUtils.kt
   // TODO: Step 1.3 set title, text and icon to builder
   .setSmallIcon(R.drawable.cooked_egg)
   .setContentTitle(applicationContext.getString(R.string.notification_title))
   .setContentText(messageBody)
  1. وبعد ذلك، عليك استدعاء notify() باستخدام معرّف فريد لإشعارك وكائن Notification من أداة الإنشاء.

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

//NotificationUtils.kt
   // TODO: Step 1.4 call notify to send the notification
    // Deliver the notification
    notify(NOTIFICATION_ID, builder.build())
  1. افتح ui/EggTimerViewModel.kt وابحث عن دالة startTimer(). تنشئ هذه الدالة منبّهًا باستخدام الفاصل الزمني المحدّد عندما يفعّل المستخدم موقّت البيض.
  2. سيؤدي إلى إرسال إشعار في هذه الوظيفة عندما يبدأ المستخدم الموقّت. لاستدعاء الدالة sendNotification() التي نفَّذتها سابقًا، تحتاج إلى مثيل NotificationManager. NotificationManager هي خدمة نظام توفّر كل الوظائف التي تم الكشف عنها من خلال واجهة برمجة التطبيقات للإشعارات، بما في ذلك وظيفة الإضافة التي أضفتها. وفي أي وقت تريد فيه إرسال إشعار أو إلغائه أو تعديله، عليك طلب مثيل لنظام التشغيل NotificationManager من النظام. يجب استدعاء الدالة sendNotification()| مع رسالة الإشعار والسياق.
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification

val notificationManager = ContextCompat.getSystemService(
    app, 
    NotificationManager::class.java
) as NotificationManager
                notificationManager.sendNotification(app.getString(R.string.timer_running), app)

أنت على وشك الانتهاء ومع ذلك، إذا شغَّلت تطبيقك الآن واضبطت الموقِّت، لن تتلقى إشعارًا.

  1. افتح logcat وابحث عن "No Channel found". من المفترض أن تظهر لك رسالة خطأ تفيد بأنّ egg_channel غير متوفّر. في الخطوات التالية، ستتعرّف على المزيد من المعلومات عن قنوات الإشعارات وحل هذه المشكلة.

الخطوة 2: قنوات الإشعارات

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

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

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

لقد استخدمت في egg_notification_channel_id 1.1 قناة الإشعارات الخاصة بك، لذا عليك الآن إنشاء وتخصيص إعدادات الإشعارات وتخصيصها لهذه القناة.

  1. افتح EggTimerFragment.kt وابحث عن دالة createChannel().
  2. تمرير معرّف القناة الفريد إلى منشئ NotificationChannel
  3. أدخِل اسم قناة الإشعار، والذي سيظهر للمستخدمين أيضًا في شاشة الإعدادات.
  4. بصفتك المعلمة الأخيرة، يجب تمرير مستوى الأهمية لقناة الإشعارات. سيتم تناول مستويات الأهمية لاحقًا في هذا الدرس التطبيقي، حتى يمكنك في الوقت الحالي استخدام NotificationManager.IMPORTANCE_LOW.
  5. في الكائن notificationChannel، يتم ضبط enableLights على "صحيح". سيؤدي هذا الإعداد إلى تفعيل الأضواء عندما يتم عرض إشعار.
  6. في الكائن notificationChannel، اضبط lightColor على اللون الأحمر لعرض ضوء أحمر عند عرض إشعار.
  7. في الكائن notificationChannel، يتم ضبط السياسة enableVibration على "صحيح" لتفعيل الاهتزاز.
  8. في عنصر notificationChannel، اضبط وصف القناة على ‘Time for breakfast'.
  9. يمكنك الحصول على مثال من NotificationManager من خلال الاتصال بـ getSystemService().
  10. يمكنك طلب الرقم createNotificationChannel() على NotificationManager وتمرير العنصر notificationChannel الذي أنشأته في الخطوة السابقة.
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
    // TODO: Step 1.6 START create a channel
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val notificationChannel = NotificationChannel(
            channelId,
            channelName,
            // TODO: Step 2.4 change importance
            NotificationManager.IMPORTANCE_LOW
        )
        // TODO: Step 2.6 disable badges for this channel

        notificationChannel.enableLights(true)
        notificationChannel.lightColor = Color.RED
        notificationChannel.enableVibration(true)
        notificationChannel.description = "Time for breakfast"

        val notificationManager = requireActivity().getSystemService(
            NotificationManager::class.java
        )
        notificationManager.createNotificationChannel(notificationChannel)
    }
    // TODO: Step 1.6 END create channel
}
  1. ولإنشاء قناة، عليك استدعاء دالة createChannel() التي كتبتها للتو (الخطوة 1.7). تتطلب هذه الدالة معلَمتَين، هما معرّف القناة واسم القناة. يجب البحث عن معرّف القناة واسم القناة من مصادر السلاسل المتوفّرة في مشروعك.
// EggTimerFragment.kt
    // TODO: Step 1.7 call createChannel
    createChannel(
          getString(R.string.egg_notification_channel_id),
          getString(R.string.egg_notification_channel_name)
    )
  1. يجب تمرير معرّف القناة إلى أداة إنشاء الإشعارات. هذا ما فعلته في الخطوة 1.2. وفي حال ضبط قيمة غير صحيحة لأنّ معرّف القناة سيؤدي إلى تعذّر إرسال الإشعار. افتح NotificationUtils.kt لإثبات صحة رقم تعريف القناة الذي ضبطته في السابق.
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
        applicationContext,
       // TODO: Step 1.8 verify the notification channel name
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. شغِّل التطبيق، وسترى التطبيق يرسل إشعارًا في كل مرة تبدأ فيها الموقّت.
  2. اسحب شريط الحالة ولاحظ أنّ عنوان الإشعار ومحتواه ورمزه سيتم ضبطهما في الخطوات السابقة.
  3. لإثبات ملكية القناة التي تم إنشاؤها حديثًا، أغلق التطبيق وابحث عن رمز التطبيق. انقر مع الاستمرار على رمز التطبيق واختَر معلومات التطبيق.

  1. انقر على الإشعارات من قائمة الإعدادات. من المفترض أن تظهر قناة جديدة تُسمّى البيضة تحت الإعداد عرض الإشعارات مباشرةً.

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

الخطوة 3: إضافة إشعارات إلى تطبيقك

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

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

يستخدم تطبيقك AlarmManager لإعداد منبّه. سبق أن تم إدخال الرمز المرتبط بالرمز AlarmManager في رمز التفعيل ويتم استخدامه لعرض رسالة الترخيص. يتتبّع AlarmManager اختيار الوقت المطلوب، وسيشغّل الدالة onReceive() الدالة AlarmReceiver.kt عند انتهاء الوقت. إذا فتحت AlarmReceiver.kt وانتقلت إلى onReceive()، من المفترض أن تظهر لك رسالة الخبز المحمّل التي يتم عرضها في كل مرة يتم فيها ضبط موقّت بيض.

  1. افتح AlarmReceiver.kt، مثال عن NotificationManager، واستدعِ الدالة sendNotification() باستخدام نص الرسالة ومعلمات السياق.
// AlarmReceiver.kt
   // TODO: Step 1.9 add call to sendNotification
   val notificationManager = ContextCompat.getSystemService(
       context, 
       NotificationManager::class.java
   ) as NotificationManager
             
   notificationManager.sendNotification(
       context.getText(R.string.eggs_ready).toString(), 
       context
   )
  1. يمكنك اختياريًا إزالة الخبز المحمّل لأن تطبيقك سيرسل إشعارًا عند انتهاء الموقّت.
// AlarmReceiver.kt
     // TODO: Step 1.10 [Optional] remove toast
//   Toast.makeText(
//       context, 
//       context.getText(R.string.eggs_ready),
//       Toast.LENGTH_SHORT
//   ).show()
  1. شغِّل تطبيقك . من المفترض أن يظهر لك إشعار في كل مرة تبدأ فيها الموقّت وكل مرة ينتهي فيها الموقّت.

وهذا ليس مثاليًا. أنت لا تريد إرسال عدد كبير جدًا من الإشعارات إلى المستخدمين. يمكنك إزالة الإشعار الأول الذي يتم إرساله عندما يبدأ المستخدم الموقّت.

  1. افتح EggTimerFragment.kt وأزِل رمز الإشعار للخطوة 1.5.
// EggTimeViewModel.kt

// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
//      app,
//      NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
  1. شغِّل تطبيقك مرة أخرى.
  2. يمكنك ضبط موقّت ووضعه في الخلفية والانتظار حتى انتهاء الوقت. سيظهر لك إشعار. هذا الإشعار أكثر فائدة.

الخطوة 4: إضافة هدف للمحتوى

  1. شغِّل التطبيق مرة أخرى، إذا لم يكن قيد التشغيل.
  2. انقر على الإشعار. لا يحدث أي تغيير.

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

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

  1. افتح NotificationUtils.kt وابحث عن دالة الإضافة sendNotification().
  2. يمكنك إنشاء Intent باستخدام applicationContext والنشاط الذي سيتم إطلاقه MainActivity::class.java.
// NotificationUtils.kt

fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
    // Create the content intent for the notification, which launches
    // this activity
   // TODO: Step 1.11 create intent
    val contentIntent = Intent(applicationContext, MainActivity::class.java)

لقد أنشأت الهدف، ولكن يتم عرض الإشعار خارج تطبيقك. ولإجراء نية الشراء خارج تطبيقك، عليك إنشاء PendingIntent جديد.

يمنح PendingIntent الحقوق لتطبيق آخر أو للنظام لتنفيذ عملية نيابة عن التطبيق. إنّ السمة PendingIntent نفسها هي إشارة إلى رمز مميّز يحفظه النظام يصف البيانات الأصلية المستخدَمة لاستردادها. وهذا يعني أنه حتى في حال إنهاء عملية تقديم الطلب، ستظل PendingIntent نفسها قابلة للاستخدام من خلال العمليات الأخرى التي تم تقديمها إليها. في هذه الحالة، سيستخدِم النظام النية بالشراء المعلّقة لفتح التطبيق نيابةً عنك، بغض النظر عما إذا كان تطبيق الموقّت قيد التشغيل أم لا.

  1. إنشاء PendingIntent باستخدام applicationContext وNOTIFICATION_ID وcontentIntent التي أنشأتها في الخطوة السابقة وعلامة PendingIntent. تحدّد العلامة PendingIntent خيار إنشاء PendingIntent جديد أو استخدام علامة حالية. يجب ضبط العلامة PendingIntent.FLAG_UPDATE_CURRENT على أنها العلامة، حيث إنك لا تريد إنشاء إشعار جديد في حال توفّر إشعار حالي. وبهذه الطريقة، ستعدّل PendingIntent الحالية المرتبطة بالنية بالشراء.
// NotificationUtils.kt
   // TODO: Step 1.12 create PendingIntent
    val contentPendingIntent = PendingIntent.getActivity(
        applicationContext, 
        NOTIFICATION_ID,
        contentIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )
  1. يُرجى تمرير PendingIntent إلى الإشعار. يمكنك إجراء ذلك من خلال الاتصال بـ setContentIntent() على NotificationBuilder. والآن، عند النقر على الإشعار، سيتم تشغيل PendingIntent، ما يؤدي إلى فتح MainActivity.
  2. يمكنك أيضًا ضبط setAutoCancel() على true. وبالتالي، عندما ينقر المستخدم على الإشعار، يتم إغلاق الإشعار نفسه عند نقله إلى التطبيق.
// NotificationUtils.kt
    // TODO: Step 1.13 set content intent
    .setContentIntent(contentPendingIntent)
    .setAutoCancel(true)
  1. شغِّل التطبيق مرة أخرى.
  2. يمكنك ضبط موقّت ووضع التطبيق في الخلفية والانتظار حتى ظهور الإشعار.
  3. بعد رؤية الإشعار، انقر على الإشعار من خلال سحب شريط الحالة لأسفل، ولاحظ كيفية عرض التطبيق في المقدّمة.

الخطوة 5: إلغاء الإشعار

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

ولحل هذه المشكلة، عليك محو الإشعار السابق عند بدء موقّت جديد. ابدأ بإنشاء وظيفة إضافة أخرى في NotificationUtils.kt. لدى NotificationManager واجهة برمجة تطبيقات لإلغاء جميع الإشعارات النشطة التي تُسمى cancelAll().

  1. فتح NotificationsUtil.kt
  2. عليك إضافة دالة الإضافة على NotificationManager والتي تستدعي cancelAll().
// NotificationUtils.kt

// TODO: Step 1.14 Cancel all notifications
/**
 * Cancels all notifications.
 *
 */
fun NotificationManager.cancelNotifications() {
    cancelAll()
}
  1. افتح EggTimerViewModel.kt وانتقِل إلى الدالة startTimer().
  2. في startTimer()، احصل على مثيل NotificationManager من النظام واستدعِ cancelNotifications().
//  EggTimerViewModel.kt
   //TODO Step 1.15 call cancel notification
    val notificationManager =
       ContextCompat.getSystemService(
            app,
            NotificationManager::class.java
        ) as NotificationManager
    notificationManager.cancelNotifications()       
  1. شغِّل التطبيق وابدأ الموقّت.
  2. بعد رؤية الإشعار، يمكنك بدء الموقِّت مرة أخرى وملاحظة كيفية حذف التطبيق للإشعار السابق تلقائيًا من شريط الحالة.

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

الخطوة 1: اختيار نمط الإشعار

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

يوفّر NotificationCompat أنماطًا مضمّنة لما يلي:

  • BigTextStyle، والذي يمكنه عرض مجموعة كبيرة من النصوص، مثل عرض محتوى رسالة إلكترونية عند توسيعه.
  • BigPictureStyle، والذي يعرض إشعارات كبيرة الحجم تتضمن مرفقًا كبيرًا للصورة.
  • InboxStyle، الذي يعرض محتوى نصيًا على شكل محادثة
  • MediaStyle: يعرض هذا القسم عناصر التحكّم لتشغيل الوسائط.
  • MessagingStyle، والذي يعرض الإشعارات ذات التنسيق الكبير التي تتضمن رسائل متعددة بين أي عدد من الأشخاص.

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

  1. افتح NotificationUtils.kt وابحث عن دالة sendNotification().
  2. ابدأ بتحميل صورة من resources باستخدام BitmapFactory.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
  1. يمكنك إنشاء BigPictureStyle جديد وتحديد صورتك.
  2. اضبط bigLargeIcon() على null بحيث يختفي الرمز الكبير عند توسيع الإشعار.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
        .bigPicture(eggImage)
        .bigLargeIcon(null)
  1. ضبط النمط باستخدام setStyle() على bigPicStyle
  2. يمكنك ضبط الرمز الكبير باستخدام setLargeIcon() على eggImage، حتى يتم عرض الصورة كرمز أصغر عند تصغير الإشعار.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
  1. تشغيل التطبيق وضبط موقّت عند عرض الإشعار لأول مرة، يصبح في الحالة المصغّرة في درج الإشعارات. في حال توسيع الإشعار، تظهر صورة كبيرة في منطقة الإشعار الموسّعة.

الخطوة 2: إجراءات الإشعارات

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

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

لإضافة زر إجراء، مرِّر دالة PendingIntent إلى الدالة addAction() على أداة الإنشاء. هذا مشابه لإعداد إجراء النقر التلقائي للإشعار عن طريق الاتصال بـ setContentIntent()، باستثناء بدلاً من تشغيل نشاط، يمكنك تنفيذ مجموعة متنوعة من الإجراءات الأخرى، على سبيل المثال، بدء BroadcastReceiver يؤدي مهمة في الخلفية بحيث لا تقاطع الإجراء التطبيق الذي سبق له فتحه.

في هذا الدرس التطبيقي حول الترميز، حصلت على BoadcastReceiver بالاسم SnoozeReceiver. ستستخدم SnoozeReceiver لتلقي نقرة المستخدم على إجراء الإشعار. في الخطوات التالية، ستضيف رمزًا لتأجيل إشعار موقّت البيض لمدة 60 ثانية عندما ينقر المستخدم على زر الإجراء "تأجيل". عند النقر على إجراء التأجيل، سيتلقّى SnoozeReceiver رسالة intent وينشئ منبّهًا جديدًا لإرسال إشعار جديد بعد 60 ثانية.

  1. فتح SnoozeReceiver.kt هذا الصف مشابه لصف AlarmReceiver الذي استخدمته من قبل. وفي الخطوات التالية، ستضيف رمزًا سيؤدي إلى تشغيل دالة onReceive() في SnoozeReceiver. وباختصار، سينشئ الرمز في SnoozeReceiver إنذارًا جديدًا لإرسال إشعار جديد بعد دقيقة واحدة. انتقِل للأسفل إلى أسفل دالة onReceived، واحصل على نسخة من ManagerManager من النظام واطلب "إلغاء الكل".
// SnoozeReceiver.kt
        val notificationManager = ContextCompat.getSystemService(
            context,
            NotificationManager::class.java
        ) as NotificationManager
        notificationManager.cancelAll()
  1. لاستخدام SnoozeReceiver، افتح NotificationUtils.kt.
  2. أنشئ Intent snoozeIntent جديدة للسمة SnoozeReceiver بعد النمط مباشرةً في دالة sendNotification().
  3. أنشئ هدفًا معلّقًا من خلال استدعاء الطريقة getBroadcast() في PendingIntent والتي تتوقع المعلمات في الخطوات التالية. سيستخدم النظام جهاز PendingIntent هذا لإعداد منبّه جديد لنشر إشعار جديد بعد 60 ثانية عندما ينقر المستخدم على زر "تأجيل".
  4. المعلمة الأولى هي سياق التطبيق الذي يجب أن يبدأ فيه PendingIntent النشاط.
  5. المعلّمة الثانية هي رمز الطلب، وهو رمز الطلب لهذه النية المعلّقة. إذا كنت بحاجة إلى تعديل حالة intent هذه في انتظار المراجعة أو إلغائها، عليك استخدام هذا الرمز للوصول إلى النية بالشراء.
  6. بعد ذلك، أضِف العنصر snoozeIntent، الذي يمثل الهدف من النشاط الذي سيتم إطلاقه.
  7. أخيرًا، أضِف قيمة العلامة #FLAG_ONE_SHOT بما أنّه سيتم استخدام النية مرة واحدة فقط. سيختفي الإجراء السريع والإشعار بعد النقرة الأولى، ولهذا السبب يمكن استخدام تلك intent مرة واحدة فقط.
// NotificationUtils.kt

// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
    applicationContext, 
    REQUEST_CODE, 
    snoozeIntent, 
    FLAGS
)
  1. بعد ذلك، عليك استدعاء دالة addAction() على notificationBuilder. تتوقع هذه الدالة رمزًا ونصًا يصف الإجراء الذي تنفذه للمستخدم. عليك أيضًا إضافة snoozeIntent. سيتم استخدام هذا الهدف لتشغيل boadcastReceiver الصحيح عند النقر على الإجراء.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
    R.drawable.egg_icon, 
    applicationContext.getString(R.string.snooze),
    snoozePendingIntent
)
  1. يمكنك تشغيل تطبيق موقّت البيض لاختبار إجراء التأجيل.
  2. تشغيل الموقّت ووضع التطبيق في الخلفية بعد انتهاء الموقّت، يمكنك توسيع الإشعار وسيظهر أمامك الآن زر يتضمّن إجراء تأجيل يؤدي إلى تأجيل موقّت البيض لمدة دقيقة أخرى.

الخطوة 3: أهمية الإشعار

يحدِّد مدى الأهمية التي يجب أن يؤثر بها الإشعار على المستخدم بشكل مرئي وبسمعة سمعية. ستكون الإشعارات ذات الأهمية الأعلى أكثر مقاطعة للمستخدمين.

يجب تحديد مستوى الأهمية في طريقة وضع NotificationChannel. لقد حدّدت في الأساس قيمة منخفضة لتطبيق موقّت البيض. ويمكنك استخدام أحد مستويات الأهمية الخمسة، بدءًا من IMPORTANCE_NONE(0) إلى IMPORTANCE_HIGH(4). ينطبق مستوى الأهمية الذي تحدده لقناتك على جميع رسائل الإشعارات التي تنشرها فيها.

مستويات أهمية القناة

مستوى الأهمية المرئي للمستخدم

الأهمية (Android 8.0 والإصدارات الأحدث)

الأولوية (الإصدار Android 7.1 والإصدارات الأقدم)

يصدر صوتًا ويظهر كإشعار رأس (ينبثق في أعلى الشاشة)

IMPORTANCE_HIGH

PRIORITY_HIGH / PRIORITY_MAX

إصدار صوت

IMPORTANCE_DEFAULT

PRIORITY_DEFAULT

بلا صوت

IMPORTANCE_LOW

PRIORITY_LOW

بلا صوت ولا يظهر في شريط الحالة

IMPORTANCE_MIN

PRIORITY_MIN

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

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

  1. لتغيير مستوى أهمية قناة الإشعارات في تطبيقك، افتح EggTimerFragment.kt وانتقِل إلى createChannel(). تغيير مستوى الأهمية من IMPORTANCE_LOW إلى IMPORTANCE_HIGH.
// EggTimerFragment.kt
    val notificationChannel = NotificationChannel(
        channelId,
        channelName,
        // TODO: Step 2.4 change importance
        NotificationManager.IMPORTANCE_HIGH
    )

لإتاحة الأجهزة التي تعمل بنظام التشغيل Android 7.1 (المستوى 25 من واجهة برمجة التطبيقات) أو الإصدارات الأقدم، يجب أيضًا الاتصال بالرقم setPriority() لكل إشعار باستخدام ثابت الأولوية من الفئة NotificationCompat.

  1. افتح NotificationUtils.kt وأضِف ما يلي إلى عنصر أداة إنشاء الإشعارات.
// NotificationUtils.kt
   .addAction(
       R.drawable.common_google_signin_btn_icon_dark,
       applicationContext.getString(R.string.snooze),
       snoozePendingIntent
    )
   // TODO: Step 2.5 set priority
    .setPriority(NotificationCompat.PRIORITY_HIGH)
  1. قبل تشغيل التطبيق، انقر مع الاستمرار على رمز التطبيق على جهازك أو المحاكي واختَر إلغاء التثبيت لمحو إعدادات القناة السابقة. في حال تعذّر إلغاء تثبيت التطبيق، لن تتغير إعدادات أولوية القناة، ولن ينتج عن ذلك أي تغيير في السلوك عند نشر الإشعار.
  2. شغِّل التطبيق الآن مرة أخرى وابدأ الموقّت. هذه المرة، عندما يتم تسليم الإشعار، من المفترض أن تظهر نافذة منبثقة في أعلى الشاشة، بغض النظر عما إذا كان التطبيق يعمل في المقدّمة أو الخلفية.

الخطوة 4: شارات الإشعارات

شارات الإشعارات هي نقاط صغيرة تظهر على رمز مشغّل التطبيقات للتطبيق المرتبط عندما يحتوي التطبيق على إشعار نشط. ويمكن للمستخدمين الضغط مع الاستمرار على رمز التطبيق للاطّلاع على الإشعارات.

تظهر هذه النقاط المعروفة باسم الشارات تلقائيًا، ولا يلزم أن ينفّذ تطبيقك أي إجراء، ولكن قد تكون هناك حالات لا تسري فيها الشارات على الإشعارات، لذا يمكنك إيقافها على أساس كل قناة من خلال استدعاء setShowBadge(false) في الكائن NotificationChannel. وبما أنّ موقّت البيض يحتوي على إشعار نشط واحد فقط في وقت معيّن، لا تقدّم الشارة على رمز تطبيقك أي فائدة للمستخدمين. في الخطوات التالية، عليك إيقاف الشارة وعرض إشعار لموقت البيض فقط.

  1. أضِف setShowBadge(false) إلى رمز إنشاء القناة لموقّت البيض لإيقاف الشارات.
// EggTimerFragment.kt

    ).apply {
        // TODO: Step 2.6 disable badges for this channel
        setShowBadge(false)
    }
  1. شغِّل التطبيق مرة أخرى وابدأ الموقّت وشاهد رمز التطبيق. من المفترض ألا ترى أي شارات على رمز التطبيق.

يمكنك العثور على رمز الحل في الفرع الرئيسي للرمز الذي تم تنزيله.

دورة Udacity:

مستندات مطوّر برامج Android:

للحصول على روابط إلى دروس تطبيقية أخرى حول الترميز في هذه الدورة التدريبية، اطّلِع على الصفحة المقصودة للإصدارات المتقدّمة من Android في لغة ترميز Kotlin.