هذا الدرس العملي حول الترميز هو جزء من دورة "تطبيقات متقدّمة متوافقة مع نظام Android باستخدام لغة Kotlin". ستستفيد إلى أقصى حدّ من هذه الدورة التدريبية إذا تابعت دروس الترميز بالتسلسل، ولكن هذا ليس إلزاميًا. يمكنك الاطّلاع على جميع دورات الترميز في الدورة التدريبية على الصفحة المقصودة لدورات الترميز في "تطبيقات متقدمة متوافقة مع نظام Android باستخدام لغة Kotlin".
مقدمة
الإشعارات هي رسائل تظهر للمستخدم خارج واجهة مستخدم تطبيقك. تظهر الإشعارات في أعلى الشاشة إذا كان الجهاز غير مقفل، أو على شاشة القفل عندما يكون الجهاز مقفلاً، وذلك حسب إعدادات الأمان.
يتألف الإشعار النموذجي من عنوان ووصف ورمز. يمكن أن يتضمّن الإشعار أيضًا إجراءات قابلة للنقر وردًا سريعًا ومحتوى قابلاً للتوسيع وصورًا.
يمكن أن تقدّم الإشعارات مواد في الوقت المناسب، ويمكن أن تتضمّن أزرارًا للسماح للمستخدم بتنفيذ إجراءات سريعة، مثل إرسال ردّ أو تأجيل رنين المنبّه. عند النقر على إشعار، يتم نقل المستخدم إلى طريقة عرض في تطبيقك ذات صلة بمحتوى الإشعار.
تُعدّ الإشعارات طريقة مفيدة لتذكير المستخدمين بمهمة مهمة أو إعلامهم بحدوث أمر ما أو إبلاغهم بمعلومات مهمة يحتاجون إليها على الفور أثناء تشغيل تطبيقك في الخلفية. استخدِم الإشعارات بشكل ضئيل. لا يراعي هذا الإجراء المستخدمين فحسب، بل يزيد أيضًا من احتمال أن يحظى إشعار تطبيقك بالاهتمام الذي يستحقه.
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية إنشاء الإشعارات واستخدامها في تطبيق Android.
ما يجب معرفته
يجب أن تكون على دراية بما يلي:
- كيفية إنشاء تطبيقات Android باستخدام لغة Kotlin على وجه الخصوص، يمكنك استخدام حزمة تطوير البرامج (SDK) لنظام التشغيل Android.
- كيفية تصميم التطبيقات باستخدام "مكوّنات البنية" وربط البيانات
- فهم أساسي لـ BroadcastReceivers
- فهم أساسي لفئة AlarmManager
أهداف الدورة التعليمية
- كيفية إنشاء إشعار وتصميمه وإرساله
- كيفية إلغاء الإشعارات
- كيفية إنشاء قنوات للإشعارات
- كيفية إضافة إجراءات سريعة إلى الإشعارات
- كيفية عرض شارات الإشعارات على رمز التطبيق
الإجراءات التي ستنفذّها
- أضِف إشعارًا إلى التطبيق الأوّلي.
- ألغِ الإشعار الذي أرسلته سابقًا.
- إنشاء قنوات لأنواع مختلفة من الإشعارات
- خصِّص الإشعارات في تطبيق البداية.
- أضِف "الإجراءات السريعة" لجعل إشعاراتك تفاعلية.
- أوقِف شارات الإشعارات.
إنّ طهي البيض بسيط، ولكنّه قد يكون مهمة صعبة إذا لم تتمكّن من تتبُّع الوقت. في هذا الدرس العملي، ستعمل على تطبيق مؤقت طهي البيض وستجعله مثاليًا، تمامًا مثل البيض الذي ستطهوه في المستقبل. ستبدأ بتطبيق مؤقت بيض يعمل ويتيح للمستخدم ضبط إعدادات مختلفة لوقت الطهي لأنواع مختلفة من البيض. يبدأ الموقّت بالعدّ التنازلي من الفاصل الزمني المحدّد ويعرض رسالة تنبيه عندما يصبح البيض جاهزًا.
قد يبدو هذا الإجراء عمليًا، لكنّه بعيد عن الكمال، ولا يراعي تجربة المستخدم. في البداية، لا تظهر رسالة الإشعار إلا لفترة وجيزة، وبالتالي من السهل عدم ملاحظتها. بالإضافة إلى ذلك، إذا لم يكن التطبيق في المقدّمة أو كان الجهاز مقفلاً، لن يظهر أي مؤشر مرئي لحالة المؤقت بعد اختفاء رسالة الإشعار.
من المفترض أن يستخدم مؤقت البيض الإشعارات لإعلام المستخدمين بانتهاء الوقت. يجب أن يعرف المستخدم أنّ البيض جاهز على الفور، وإلا سيتم طهيه أكثر من اللازم. الإشعارات مرئية ويمكن أن تتضمّن أصواتًا ويمكن أن تجعل الجهاز يهتز، وكلها طرق لجذب انتباه المستخدم. بهذه الطريقة، يمكنك الحصول على بيض مثالي وإرضاء المستخدمين.
للحصول على التطبيق النموذجي، يمكنك اتّباع أحد الإجراءَين التاليَين:
استنسِخ المستودع من GitHub وانتقِل إلى فرع starter.
$ git clone https://github.com/googlecodelabs/android-kotlin-notifications
بدلاً من ذلك، يمكنك تنزيل المستودع كملف Zip وفك ضغطه وفتحه في Android Studio.
- افتح التطبيق وشغِّله في "استوديو Android".
ستظهر لك صورة بيضة وقائمة منسدلة تتضمّن قائمة بفواصل زمنية محدّدة مسبقًا لطهي البيض. انقر على المثلث الخاص بالقائمة المنسدلة بيض مسلوق. يتم توفير الخيار الأول في القائمة لأغراض الاختبار ويضبط المنبّه على 10 ثوانٍ فقط. بجانب القائمة، يوجد مفتاح تبديل يبدأ مؤقت البيض. يمكنك استخدام هذا المفتاح لبدء مؤقت البيض وإيقافه في أي وقت. الرمز الأولي يعمل بشكل كامل، ما يعني أنّه يمكنك إعداد مؤقت البيض ومشاهدته وهو يعدّ تنازليًا إلى 0. بعد انتهاء المؤقت، يتم عرض رسالة إشعار مؤقت، كما هو موضّح أدناه.
- فحص رمز المصدر يتألف التطبيق الأولي من نشاط واحد باسم
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: إنشاء إشعار أساسي
في هذه المهمة، ستنشئ إشعارًا جديدًا وتضبط رسالة للمستخدم وترسل الإشعار.
- افتح صف
NotificationUtils.kt
وابحث عنTODO: Step 1.1
. ستجد مهامًا مطابقة في هذا الدرس التطبيقي حول الترميز ورمز التطبيق. - افحص الدالة
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) {
- احصل على مثيل لأداة إنشاء الإشعارات، وأدخِل سياق التطبيق ومعرّف القناة. معرّف القناة هو قيمة سلسلة للقناة.
قنوات الإشعارات هي طريقة لتجميع الإشعارات. من خلال تجميع أنواع الإشعارات المتشابهة معًا، يمكن للمطوّرين والمستخدمين التحكّم في جميع الإشعارات في القناة. بعد إنشاء قناة، يمكن استخدامها لإرسال أي عدد من الإشعارات.
//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)
)
- اضبط رمز الإشعار لتمثيل تطبيقك، وعنوانًا، ونص المحتوى للرسالة التي تريد تقديمها للمستخدم. ستظهر لك المزيد من الخيارات لتخصيص الإشعار بشكل أكبر في الدرس العملي، ولكن هذا هو الحد الأدنى من البيانات التي تحتاج إلى ضبطها لإرسال إشعار.
//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)
- بعد ذلك، عليك استدعاء
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())
- افتح
ui/EggTimerViewModel.kt
وابحث عن الدالةstartTimer()
. تنشئ هذه الدالة منبّهًا بفاصل زمني محدّد عندما يفعّل المستخدم مؤقت البيض. - سيتم تشغيل إشعار في هذه الدالة عندما يبدأ المستخدم المؤقت. لاستدعاء الدالة
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)
أنت على وشك الانتهاء. ومع ذلك، إذا شغّلت تطبيقك الآن وضبطت المؤقت، لن تتلقّى إشعارًا.
- افتح
logcat
وابحث عن"No Channel found"
. من المفترض أن تظهر لك رسالة خطأ تفيد بأنّegg_channel
غير متوفّر. في الخطوات التالية، ستتعرّف على مزيد من المعلومات حول "قنوات الإشعارات" وكيفية حلّ هذه المشكلة.
الخطوة 2: قنوات الإشعارات
اعتبارًا من المستوى 26 لواجهة برمجة التطبيقات، يجب ربط جميع الإشعارات بقناة. إذا نقرت مع الاستمرار على رمز مشغّل التطبيق، ثم اخترت معلومات التطبيق، ثم نقرت على الإشعارات، ستظهر لك قائمة بقنوات الإشعارات المرتبطة بالتطبيق. والقائمة فارغة حاليًا لأنّ تطبيقك لم ينشئ أي قنوات.
تمثّل القنوات "نوعًا" من الإشعارات، على سبيل المثال، يمكن لموقّت البيض إرسال إشعار عند انتهاء الطهي، ويمكنه أيضًا استخدام قناة أخرى لإرسال إشعارات يومية لتذكيرك بتناول البيض مع وجبة الإفطار. يتم تجميع كل الإشعارات في قناة واحدة، ويمكن للمستخدمين ضبط إعدادات الإشعارات لقناة بأكملها. يتيح ذلك للمستخدمين تخصيص إعدادات الإشعارات استنادًا إلى نوع الإشعار الذي يهمّهم. على سبيل المثال، يمكن للمستخدمين إيقاف إشعارات وجبة الفطور، ولكن يمكنهم مواصلة تلقّي الإشعارات من المؤقّت.
يضبط المطوّرون الإعدادات الأولية والأهمية والسلوك ليتم تطبيقها على جميع الإشعارات في القناة. بعد ضبط الإعدادات الأولية، يمكن للمستخدمين تجاوز هذه الإعدادات.
في الخطوة 1.1، استخدمت egg_notification_channel_id
كقناة إشعارات، لذا عليك الآن إنشاء إعدادات الإشعارات وسلوك هذه القناة وتخصيصهما.
- افتح
EggTimerFragment.kt
وابحث عن الدالةcreateChannel()
. - مرِّر معرّف القناة الفريد إلى أداة إنشاء
NotificationChannel
. - مرِّر اسم قناة الإشعارات الذي سيظهر أيضًا للمستخدمين في شاشة الإعدادات.
- كمَعلمة أخيرة، مرِّر مستوى الأهمية لقناة الإشعارات. سيتم تناول مستويات الأهمية لاحقًا في هذا الدرس التطبيقي حول الترميز، لذا يمكنك استخدام
NotificationManag
er.IMPORTANCE_LOW
في الوقت الحالي. - في عنصر
notificationChannel
، اضبطenableLights
على "صحيح". سيؤدي هذا الإعداد إلى تفعيل الأضواء عند عرض إشعار. - اضبط
notificationChannel
مجموعة العناصرlightColor
على اللون الأحمر لعرض ضوء أحمر عند ظهور إشعار. - في عنصر
notificationChannel
، اضبطenableVibration
على "صحيح" لتفعيل الاهتزاز. - في عنصر
notificationChannel
، اضبط وصف القناة على‘Time for breakf
ast'. - احصل على مثيل من
NotificationManager
من خلال استدعاءgetSystemService()
. - استدعِ الدالة
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
}
- بعد ذلك، لإنشاء قناة، عليك استدعاء الدالة
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.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)
)
- شغِّل التطبيق، وسيظهر لك أنّه يرسل إشعارًا في كل مرة تبدأ فيها الموقّت.
- اسحب شريط الحالة ولاحظ أنّ عنوان الإشعار ومحتواه ورمزه هي كما ضبطتها في الخطوات السابقة.
- للتحقّق من القناة التي تم إنشاؤها حديثًا، أغلِق التطبيق وابحث عن رمز التطبيق. اضغط مع الاستمرار على رمز التطبيق واختَر معلومات التطبيق.
- اختَر الإشعارات من قائمة الإعدادات. من المفترض أن تظهر قناة جديدة باسم Egg أسفل خيار عرض الإشعارات مباشرةً.
عند تشغيل التطبيق، سيظهر الإشعار الآن. يمكنك أنت بصفتك مطوّر التطبيق والمستخدمين تخصيص الإعدادات والسلوك لجميع الإشعارات المرسَلة على هذه القناة. تهانينا، لقد أنشأت إشعارًا.
الخطوة 3: إضافة الإشعارات إلى تطبيقك
حتى الآن، يوضّح هذا المثال الاستخدام الأساسي لواجهة برمجة التطبيقات الخاصة بالإشعارات، ولكن إرسال إشعار بعد بدء المؤقت مباشرةً ليس منطقيًا. من المرجّح أنّ يفضّل المستخدمون تلقّي إشعار عندما تكون البيضة جاهزة. في الجزء التالي من الدرس العملي، ستعمل على حلّ هذه المشكلة وتغيير رسالة الإشعار المؤقت إلى إشعار.
لقد أرسلت الإشعار من قبل ولاحظت طريقة ظهوره للمستخدمين، ولكن هذه كانت الخطوة الأولى فقط نحو إنشاء إشعارات رائعة. في هذه الخطوة، ستغيّر وقت إرسال الإشعار إلى وقت أكثر ملاءمة.
يستخدم تطبيقك الإذن AlarmManager
لضبط منبّه. يتم تقديم الرمز البرمجي المرتبط بـ AlarmManager
في الرمز البرمجي الأولي واستخدامه لعرض رسالة الإشعار. تتتبّع AlarmManager
الوقت المطلوب وتفعّل الدالة onReceive()
في AlarmReceiver.kt
عند انتهاء الوقت. إذا فتحت AlarmReceiver.kt
وانتقلت إلى onReceive()
، من المفترض أن تظهر لك رسالة الإشعار التي يتم عرضها في كل مرة تُعدّ فيها مؤقتًا للبيض.
- افتح
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
)
- يمكنك اختياريًا إزالة الإشعار المؤقت لأنّ تطبيقك سيرسل إشعارًا عند انتهاء الموقّت.
// AlarmReceiver.kt
// TODO: Step 1.10 [Optional] remove toast
// Toast.makeText(
// context,
// context.getText(R.string.eggs_ready),
// Toast.LENGTH_SHORT
// ).show()
- شغِّل تطبيقك . سيصلك إشعار في كل مرة تبدأ فيها الموقّت وفي كل مرة ينتهي فيها.
وهذا ليس مثاليًا. لا تريد إرسال عدد كبير جدًا من الإشعارات إلى المستخدمين. يمكنك إزالة الإشعار الأول الذي يتم إرساله عندما يبدأ المستخدم الموقّت.
- افتح
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)
- شغِّل تطبيقك مرة أخرى.
- اضبط مؤقتًا، ثم ضعه في الخلفية وانتظِر إلى أن ينتهي الوقت. سيظهر لك إشعار. هذا الإشعار أكثر فائدة.
الخطوة 4: إضافة هدف المحتوى
- أعِد تشغيل التطبيق إذا لم يكن قيد التشغيل.
- انقر على الإشعار. لا يحدث أي شيء!
إنّ عرض الإشعار وإعلام المستخدم أمر رائع، ولكن عندما ينقر المستخدم على إشعار، يتوقّع أن يعود إلى التطبيق المعنيّ. في هذا الجزء من الدرس العملي، ستضيف intent إلى الإشعار لإعادة المستخدم إلى شاشة المؤقّت.
Intent
هو عنصر مراسلة يمكنك استخدامه لطلب تنفيذ إجراء من أحد مكونات تطبيق آخر. يمكن استخدام الأهداف لبدء نشاط أو خدمة أو عرض بث. في هذه الحالة، يمكنك استخدام هذا الغرض لإخبار النظام بفتح MainActivity
عندما ينقر المستخدم على الإشعار. بما أنّ تطبيقك يتألف من طريقة عرض واحدة فقط، لن يتوفّر لك العديد من الخيارات هنا. ومع ذلك، في التطبيقات الأكبر حجمًا، يجب أن يوفّر الإشعار تجربة سلسة من خلال نقل المستخدم إلى شاشة مناسبة عند تفاعله مع الإشعار.
- افتح
NotificationUtils.kt
وابحث عن وظيفة إضافةsendNotification()
. - أنشئ
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
نفسه قابلاً للاستخدام من العمليات الأخرى التي تم منحه إذن الوصول إليها. في هذه الحالة، سيستخدم النظام PendingIntent لفتح التطبيق نيابةً عنك، بغض النظر عمّا إذا كان تطبيق الموقّت قيد التشغيل أم لا.
- أنشئ
PendingIntent
باستخدامapplicationContext
وNOTIFICATION_ID
وcontentIntent
الذي أنشأته في الخطوة السابقة وعلامةPendingIntent
. تحدّد العلامة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
)
- مرِّر
PendingIntent
إلى الإشعار. يمكنك إجراء ذلك من خلال الاتصال بالرقمsetContentIntent()
على الجهازNotificationBuilder
. الآن، عند النقر على الإشعار، سيتم تشغيلPendingIntent
، ما يؤدي إلى فتحMainActivity
. - اضبط أيضًا
setAutoCancel()
علىtrue
، حتى يتم تجاهل الإشعار تلقائيًا عندما ينقر المستخدم عليه، ما يؤدي إلى نقله إلى التطبيق.
// NotificationUtils.kt
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
.setAutoCancel(true)
- تشغيل التطبيق مرة أخرى
- اضبط موقّتًا، ثم ضع التطبيق في الخلفية وانتظر إلى أن يظهر الإشعار.
- بعد ظهور الإشعار، انقر عليه من خلال سحب شريط الحالة إلى الأسفل، ولاحظ كيف يتم نقل التطبيق إلى المقدّمة.
الخطوة 5: إلغاء الإشعار
لديك موقّت بيض يعمل مع إشعارات، ولكن هناك مشكلة بسيطة. إذا ضبطت المؤقت وتلقّيت إشعارًا ثم ضبطت المؤقت مرة أخرى، سيبقى الإشعار السابق في شريط الحالة أثناء عمل المؤقت الجديد. قد يؤدي ذلك إلى إرباك المستخدم إذا كان التطبيق يعمل في الخلفية، وقد يؤدي إلى عدم طهي البيض بشكل كافٍ.
لحلّ هذه المشكلة، عليك محو الإشعار السابق عند بدء مؤقّت جديد. ابدأ بإنشاء دالة إضافة أخرى في NotificationUtils.kt
. يتضمّن NotificationManager
واجهة برمجة تطبيقات لإلغاء جميع الإشعارات النشطة باسم cancelAll
()
.
- فتح "
NotificationsUtil.kt
" - أضِف دالة إضافة على
NotificationManager
تستدعيcancelAll()
.
// NotificationUtils.kt
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
- افتح
EggTimerViewModel.kt
وانتقِل إلى الدالةstartTimer()
. - داخل
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: تصميم الإشعار
سيؤدي تصميم الإشعار وفقًا لاحتياجاتك ومحتوى الإشعار إلى تمييز إشعاراتك وجعلها تبدو وكأنّها امتداد لتطبيقك. يتضمّن إطار عمل الإشعارات عدة أنماط مضمّنة للمساعدة، ويمكنك دائمًا إنشاء أنماطك الخاصة.
توفّر NotificationCompat
أنماطًا مدمجة لما يلي:
BigTextStyle
، التي يمكنها عرض كتلة كبيرة من النص، مثل عرض محتوى رسالة إلكترونية عند توسيعها-
BigPictureStyle
، الذي يعرض إشعارات بتنسيق كبير تتضمّن مرفق صورة كبيرة -
InboxStyle
، الذي يعرض محتوًى نصيًا بأسلوب محادثة MediaStyle
، الذي يعرض عناصر التحكّم في تشغيل الوسائطMessagingStyle
، الذي يعرض إشعارات بتنسيق كبير تتضمّن رسائل متعدّدة بين أي عدد من الأشخاص.
يمكنك العثور على مزيد من المعلومات حول الأنماط الأخرى في مستندات إنشاء إشعار قابل للتوسيع. في هذه الخطوة، ستستخدم NotificationCompat.BigPictureStyle
لإنشاء إشعار قابل للتوسيع يعرض صورة بيضة كبيرة عند توسيعه.
- افتح
NotificationUtils.kt
وابحث عن الدالةsendNotification()
. - ابدأ بتحميل صورة من
resources
باستخدامBitmapFactory
.
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
- أنشئ
BigPictureStyle
جديدًا واضبط صورتك. - اضبط
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)
- اضبط النمط باستخدام
setStyle()
علىbigPicStyle
. - اضبط الرمز الكبير الذي يتضمّن
setLargeIcon()
علىeggImage
، وبالتالي سيتم عرض الصورة كرمز أصغر عند تصغير الإشعار.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
- شغِّل التطبيق واضبط موقّتًا. عندما يظهر الإشعار لأول مرة، يكون في الحالة المصغّرة في درج الإشعارات. إذا وسّعت الإشعار، ستظهر صورة كبيرة في مساحة الإشعار الموسّع.
الخطوة 2: إجراءات الإشعارات
إجراءات الإشعارات هي عملية تخصيص أخرى يمكنك إضافتها إلى إشعاراتك. تعيد توجيه الإشعارات حاليًا إلى تطبيقك عندما ينقر المستخدمون عليها. بالإضافة إلى إجراء الإشعار التلقائي هذا، يمكنك إضافة أزرار إجراءات تُكمل مهمة متعلقة بالتطبيق من الإشعار.
يمكن أن يوفّر الإشعار ما يصل إلى ثلاثة أزرار إجراءات تتيح للمستخدم الردّ بسرعة، مثل تأجيل تذكير أو الردّ على رسالة نصية. ويجب ألا تكرّر أزرار الإجراءات هذه الإجراء الذي يتم تنفيذه عندما ينقر المستخدم على الإشعار.
لإضافة زر إجراء، مرِّر PendingIntent
إلى الدالة addAction()
في أداة الإنشاء. يشبه ذلك إعداد إجراء النقر التلقائي للإشعار من خلال استدعاء setContentIntent()
، ولكن بدلاً من تشغيل نشاط، يمكنك تنفيذ مجموعة متنوعة من الإجراءات الأخرى، مثل بدء BroadcastReceiver
ينفّذ مهمة في الخلفية حتى لا يؤدي الإجراء إلى مقاطعة التطبيق المفتوح حاليًا.
في هذا الدرس العملي، سيتم تزويدك مسبقًا بـ BoadcastReceiver
باسم SnoozeReceiver
. ستستخدِم SnoozeReceiver
لتلقّي نقرة المستخدم على إجراء الإشعار. في الخطوات التالية، ستضيف رمزًا برمجيًا لتأجيل إشعار مؤقت البيض لمدة 60 ثانية عندما ينقر المستخدم على زر إجراء التأجيل. عند النقر على إجراء تأجيل التنبيه، سيتلقّى SnoozeReceiver
هدفًا وسينشئ منبّهًا جديدًا لإرسال إشعار جديد بعد 60 ثانية.
- فتح "
SnoozeReceiver.kt
" هذا الصف مشابه للصفAlarmReceiver
الذي استخدمته سابقًا. في الخطوات التالية، ستضيف رمزًا سيؤدي إلى تشغيل الدالةonReceive()
الخاصة بـSnoozeReceiver
. باختصار، سينشئ الرمز البرمجي فيSnoozeReceiver
منبّهًا جديدًا لإرسال إشعار جديد بعد دقيقة واحدة. انتقِل إلى أسفل الدالة onReceive، واحصل على مثيل notificationManager من النظام، ثم استدعِ cancelAll.
// SnoozeReceiver.kt
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelAll()
- لاستخدام
SnoozeReceiver
، افتحNotificationUtils.kt
. - أنشئ
Intent
snoozeIntent
جديدًا لـSnoozeReceiver
بعد النمط مباشرةً في الدالةsendNotification()
. - أنشئ Intent في انتظار المراجعة من خلال استدعاء الطريقة
getBroadcast()
فيPendingIntent
التي تتوقّع المَعلمات في الخطوات التالية. سيتم استخدامPendingIntent
هذا من قِبل النظام لإعداد منبّه جديد لنشر إشعار جديد بعد 60 ثانية عندما ينقر المستخدم على زر الغفوة. - المَعلمة الأولى هي سياق التطبيق الذي يجب أن يبدأ فيه
PendingIntent
النشاط. - المَعلمة الثانية هي رمز الطلب، وهو رمز الطلب لهذا الغرض المعلّق. إذا كنت بحاجة إلى تعديل أو إلغاء هذه النية المعلّقة، عليك استخدام هذا الرمز للوصول إليها.
- بعد ذلك، أضِف العنصر
snoozeIntent
، وهو هدف النشاط الذي سيتم إطلاقه. - أخيرًا، أضِف قيمة العلامة
#FLAG_ONE_SHOT
لأنّه سيتم استخدام الغرض مرة واحدة فقط. سيختفي الإشعار والإجراء السريع بعد النقر الأول، ولهذا السبب لا يمكن استخدام الغرض إلا مرة واحدة.
// 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
)
- بعد ذلك، استدعِ الدالة
addAction()
علىnotificationBuilder
. تتوقّع هذه الدالة رمزًا ونصًا لوصف الإجراء للمستخدم. يجب أيضًا إضافةsnoozeIntent
. سيتم استخدام هذا الغرض لتفعيلboadcastReceiver
المناسب عند النقر على الإجراء.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
R.drawable.egg_icon,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
- شغِّل تطبيق مؤقّت البيض لاختبار إجراء تأجيل المنبّه.
- شغِّل المؤقت وافتح تطبيقًا آخر. بعد انتهاء الموقّت، وسِّع الإشعار وسترى أنّه يتضمّن الآن زر إجراء تأجيل يؤجّل الموقّت لمدة دقيقة أخرى.
الخطوة 3: أهمية الإشعارات
تحدّد الأهمية مقدار التشويش الذي يجب أن يسبّبه الإشعار للمستخدم بصريًا وسمعيًا. ستكون الإشعارات ذات الأهمية الأعلى أكثر إزعاجًا للمستخدمين.
يجب تحديد مستوى الأهمية في الدالة الإنشائية NotificationChannel
. لقد ضبطت في البداية مستوى أهمية منخفضًا لتطبيق "مؤقت البيض". يمكنك استخدام أحد مستويات الأهمية الخمسة، بدءًا من IMPORTANCE_NONE(0)
إلى IMPORTANCE_HIGH(4)
. ينطبق مستوى الأهمية الذي تحدّده لقناة على جميع رسائل الإشعارات التي تنشرها فيها.
مستويات أهمية القناة
مستوى الأهمية الظاهر للمستخدم | الأهمية (الإصدار 8.0 من نظام التشغيل Android والإصدارات الأحدث) | الأولوية (الإصدار 7.1 من نظام التشغيل Android والإصدارات الأقدم) |
إصدار تنبيه صوتي والظهور كإشعار عائم (يظهر في أعلى الشاشة) | ||
إصدار صوت | ||
بلا صوت | ||
بدون صوت ولا يظهر في شريط الحالة |
للحصول على معلومات حول اختيار مستوى أولوية مناسب، اطّلِع على "مستويات الأولوية" في دليل تصميم الإشعارات. يجب توخّي الحذر عند اختيار مستوى أهمية الإشعارات في تطبيقك، ويجب اختيار مستوى أهمية القناة مع مراعاة وقت المستخدم واهتمامه. عندما يتم إخفاء إشعار غير مهم على أنّه عاجل، يمكن أن يؤدي ذلك إلى إثارة القلق بلا داعٍ وتشتيت الانتباه. يتحكّم المستخدمون بشكل كامل في مستوى أهمية إشعاراتهم، لذا إذا أنشأت إشعارًا مزعجًا، يمكنهم إيقاف قناة الإشعارات الخاصة بك تمامًا.
عندما أنشأت الإشعار لأول مرة في الخطوة 1.6، تم ضبط مؤقت البيض لإرسال إشعارات بأولوية منخفضة لأنّه مصمّم لعدم إزعاج المستخدم بالإشعارات. ومع ذلك، قد يكون من المفيد لفت انتباه المستخدم قبل أن تنتهي مدة الطهي. لتغيير مستوى أهمية الإشعار، ابدأ بإعدادات القناة. تؤثّر أهمية القناة في مستوى مقاطعة جميع الإشعارات المنشورة في القناة، ويجب تحديدها في الدالة الإنشائية NotificationChannel
.
- لتغيير مستوى أهمية قناة إشعارات تطبيقك، افتح
EggTimerFragment.kt
وانتقِل إلىcreateChannel()
. غيِّر مستوى الأهمية منIMPORTANCE_LOW
إلىIMPORTANCE_HIGH
.
// EggTimerFragment.kt
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_HIGH
)
لإتاحة استخدام الأجهزة التي تعمل بالإصدار 7.1 من نظام التشغيل Android (المستوى 25 لواجهة برمجة التطبيقات) أو الإصدارات الأقدم، عليك أيضًا استدعاء setPriority()
لكل إشعار، وذلك باستخدام ثابت أولوية من الفئة NotificationCompat
.
- افتح
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)
- قبل تشغيل التطبيق، انقر مع الاستمرار على رمز التطبيق على جهازك أو المحاكي واختَر "إلغاء التثبيت" لمحو إعدادات القناة السابقة. في حال تعذّر إلغاء تثبيت التطبيق، لن تتغيّر إعدادات أولوية القناة، ولن يحدث أي تغيير في السلوك عند نشر الإشعار.
- الآن، شغِّل التطبيق مرة أخرى وابدأ المؤقت. في هذه المرة، عند تسليم الإشعار، من المفترض أن يظهر لك إشعار منبثق في أعلى الشاشة، بغض النظر عمّا إذا كان تطبيقك يعمل في المقدّمة أو الخلفية.
الخطوة 4: شارات الإشعارات
شارات الإشعارات هي نقاط صغيرة تظهر على رمز مشغّل التطبيق المرتبط به عندما يكون للتطبيق إشعار نشط. يمكن للمستخدمين الضغط مع الاستمرار على رمز التطبيق لعرض الإشعارات.
تظهر هذه النقاط، التي تُعرف باسم الشارات، تلقائيًا، ولا يحتاج تطبيقك إلى اتّخاذ أي إجراء. ومع ذلك، قد تكون هناك حالات لا تكون فيها الشارات مناسبة لإشعاراتك، لذا يمكنك إيقافها على أساس كل قناة على حدة من خلال استدعاء setShowBadge(false)
على عنصر NotificationChannel
. بما أنّ مؤقت البيض لا يعرض سوى إشعار نشط واحد في وقت معيّن، فإنّ الشارة على رمز تطبيقك لا تقدّم فائدة كبيرة للمستخدمين. في الخطوات التالية، سيتم إيقاف الشارة وعرض إشعار فقط لمؤقت البيض.
- أضِف
setShowBadge(false)
إلى رمز إنشاء القناة لإيقاف الشارات في مؤقّت البيض.
// EggTimerFragment.kt
).apply {
// TODO: Step 2.6 disable badges for this channel
setShowBadge(false)
}
- شغِّل التطبيق مرة أخرى وابدأ الموقّت وراقِب رمز التطبيق. لن تظهر أي شارات على رمز التطبيق.
يتوفّر رمز الحل في الفرع الرئيسي للرمز الذي تم تنزيله.
- استخدِم فئة NotificationManager لإنشاء إشعار وإرساله وتعديله وإلغائه.
- استخدِم عنصر NotificationChannel مع طريقة createNotificationChannel لضبط قناة للإشعار.
- استخدِم addAction() لإضافة إجراءات سريعة إلى إشعار.
- استخدِم setShowBadge() لتفعيل الشارات أو إيقافها.
- يمكنك تصميم الإشعارات باستخدام أنماط ممتدة من Notification.Style
- اضبط مستوى الأهمية باستخدام NotificationChannel.setImportance()
دورة Udacity التدريبية:
مستندات مطوّري تطبيقات Android:
للحصول على روابط تؤدي إلى دروس برمجية أخرى في هذه الدورة التدريبية، يمكنك الانتقال إلى الصفحة المقصودة للدروس البرمجية المتقدّمة حول Android بلغة Kotlin.