إنشاء إشعار

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

يستخدم الرمز في هذه الصفحة واجهات برمجة تطبيقات NotificationCompat من مكتبة AndroidX. تتيح لك واجهات برمجة التطبيقات هذه إضافة ميزات متوفرة فقط على الإصدارات الأحدث من نظام التشغيل Android مع مواصلة توفير التوافق مع Android 9 (المستوى 28 من واجهة برمجة التطبيقات). ومع ذلك، تؤدي بعض الميزات، مثل إجراء الرد المضمّن، إلى عدم التشغيل في الإصدارات السابقة.

إضافة مكتبة AndroidX Core

مع أنّ معظم المشاريع التي تم إنشاؤها باستخدام "استوديو Android" تتضمّن الملحقات اللازمة لاستخدام NotificationCompat، تأكَّد من أنّ ملف build.gradle على مستوى الوحدة يتضمّن الاعتمادية التالية:

رائع

dependencies {
    implementation "androidx.core:core:2.2.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:2.2.0")
}

إنشاء إشعار أساسي

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

الشكل 1. إشعار به رمز وعنوان وبعض النصوص.

لمزيد من التفاصيل حول كل جزء من الإشعار، يمكنك الاطّلاع على تحليلات الإشعارات.

إعلان إذن التشغيل

يتيح نظام التشغيل Android 13 (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث أذونات وقت التشغيل لنشر الإشعارات غير المستثناة (بما في ذلك الإشعارات التي تعمل في المقدّمة (FGS) من أحد التطبيقات.

يظهر الإذن الذي يجب الإفصاح عنه في ملف بيان تطبيقك في مقتطف الرمز التالي:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

للحصول على مزيد من التفاصيل حول أذونات وقت التشغيل، يُرجى الاطّلاع على إذن تشغيل الإشعارات.

ضبط محتوى الإشعار

للبدء، عليك ضبط محتوى الإشعار وقناته باستخدام كائن NotificationCompat.Builder. يوضّح المثال التالي كيفية إنشاء إشعار بما يلي:

  • رمز صغير تم ضبطه من قِبل setSmallIcon(). وهذا هو المحتوى الوحيد المرئي للمستخدم.

  • عنوان تم ضبطه من قِبل setContentTitle().

  • النص الأساسي، الذي تم ضبطه من قِبل setContentText().

  • أولوية الإشعار، التي تم ضبطها من خلال setPriority(). وتحدِّد الأولوية مدى تداخل الإشعار مع نظام التشغيل Android 7.1 والإصدارات الأقدم. بالنسبة إلى الإصدار Android 8.0 والإصدارات الأحدث، اضبط أهمية القناة كما هو موضّح في القسم التالي.

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

تتطلب منك الدالة الإنشائية NotificationCompat.Builder تقديم معرّف قناة. يجب تنفيذ هذا الإجراء للتوافق مع الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث، ولكن تجاهلته الإصدارات السابقة.

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

الشكل 2. هو إشعار قابل للتوسيع بأشكاله المصغّرة والموسّعة.

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

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

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

إنشاء قناة وتحديد أهميتها

لكي تتمكّن من إرسال الإشعار على الإصدار Android 8.0 والإصدارات الأحدث، يجب تسجيل قناة الإشعارات في تطبيقك لدى النظام من خلال إرسال مثيل من NotificationChannel إلى createNotificationChannel(). يتم حظر الرمز التالي بسبب شرط في إصدار SDK_INT:

Kotlin

private fun createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.channel_name)
        val descriptionText = getString(R.string.channel_description)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            description = descriptionText
        }
        // Register the channel with the system.
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

Java

private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = getString(R.string.channel_name);
        String description = getString(R.string.channel_description);
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this.
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
}

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

تتطلب الدالة الإنشائية NotificationChannel السمة importance، باستخدام أحد القيم الثابتة من الفئة NotificationManager. وتحدّد هذه المعلمة كيفية مقاطعة أي إشعار تابع للمستخدم يعود إلى هذه القناة. اضبط الأولوية على setPriority() للتوافق مع الإصدار 7.1 من نظام التشغيل Android والإصدارات الأقدم، كما هو موضح في المثال السابق.

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

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

ضبط إجراء النقر على الإشعار

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

يوضّح المقتطف التالي كيفية إنشاء هدف أساسي لفتح نشاط عندما ينقر المستخدم على الإشعار:

Kotlin

// Create an explicit intent for an Activity in your app.
val intent = Intent(this, AlertDetails::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

Java

// Create an explicit intent for an Activity in your app.
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true);

يستدعي هذا الرمز الرمز setAutoCancel()، مما يؤدي إلى إزالة الإشعار تلقائيًا عندما ينقر المستخدم عليه.

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

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

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

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

عرض الإشعار

لإظهار الإشعار، عليك طلب NotificationManagerCompat.notify()، وتمرير معرّف فريد للإشعار ونتيجة NotificationCompat.Builder.build(). يظهر ذلك في المثال التالي:

Kotlin

with(NotificationManagerCompat.from(this)) {
    if (ActivityCompat.checkSelfPermission(
            this@MainActivity,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        // ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
        //                                        grantResults: IntArray)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.

        return@with
    }
    // notificationId is a unique int for each notification that you must define.
    notify(NOTIFICATION_ID, builder.build())
}

Java

with(NotificationManagerCompat.from(this)) {
   if (ActivityCompat.checkSelfPermission(
           this@MainActivity,
           Manifest.permission.POST_NOTIFICATIONS
       ) != PackageManager.PERMISSION_GRANTED
   ) {
       // TODO: Consider calling
       // ActivityCompat#requestPermissions
       // here to request the missing permissions, and then overriding
       // public void onRequestPermissionsResult(int requestCode, String[] permissions,
       //                                        int[] grantResults)
       // to handle the case where the user grants the permission. See the documentation
       // for ActivityCompat#requestPermissions for more details.

       return
   }
   // notificationId is a unique int for each notification that you must define.
   notify(NOTIFICATION_ID, builder.build())
}

احفظ معرّف الإشعار الذي تمرره إلى NotificationManagerCompat.notify()، لأنك تحتاجه عندما تريد تحديث أو إزالة الإشعار.

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

إضافة أزرار الإجراءات

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

الشكل 3. إشعار مع زر إجراء واحد.

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

على سبيل المثال، يوضح الرمز التالي كيفية إرسال بث إلى مستقبِل محدّد:

Kotlin


val ACTION_SNOOZE = "snooze"

val snoozeIntent = Intent(this, MyBroadcastReceiver::class.java).apply {
    action = ACTION_SNOOZE
    putExtra(EXTRA_NOTIFICATION_ID, 0)
}
val snoozePendingIntent: PendingIntent =
    PendingIntent.getBroadcast(this, 0, snoozeIntent, 0)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent)

Java


String ACTION_SNOOZE = "snooze"

Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(ACTION_SNOOZE);
snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0);
PendingIntent snoozePendingIntent =
        PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent);

لمزيد من المعلومات حول إنشاء BroadcastReceiver لتشغيل عمل في الخلفية، يُرجى الاطّلاع على نظرة عامة على عمليات البث.

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

إضافة إجراء ردّ مباشر

يتيح إجراء الرد المباشر، الذي تم تقديمه في الإصدار Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات)، للمستخدمين إدخال النص مباشرةً في الإشعار. ثم يتم تسليم النص إلى التطبيق دون فتح نشاط. على سبيل المثال، يمكنك استخدام إجراء رد مباشر للسماح للمستخدمين بالرد على الرسائل النصية أو تحديث قوائم المهام من داخل الإشعار.

الشكل 4. يؤدي النقر على الزر "رد" إلى فتح إدخال النص.

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

إضافة زر الرد

لإنشاء إجراء إشعار يتيح إمكانية الرد المباشر، اتبع الخطوات التالية:

  1. يمكنك إنشاء مثيل من RemoteInput.Builder يمكنك إضافته إلى إجراء الإشعار. تقبل الدالة الإنشائية لهذه الفئة سلسلة يستخدمها النظام كمفتاح لإدخال النص. ويستخدم تطبيقك لاحقًا هذا المفتاح لاسترداد نص الإدخال.

    Kotlin

      // Key for the string that's delivered in the action's intent.
      private val KEY_TEXT_REPLY = "key_text_reply"
      var replyLabel: String = resources.getString(R.string.reply_label)
      var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
          setLabel(replyLabel)
          build()
      }
      

    Java

      // Key for the string that's delivered in the action's intent.
      private static final String KEY_TEXT_REPLY = "key_text_reply";
    
      String replyLabel = getResources().getString(R.string.reply_label);
      RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
              .setLabel(replyLabel)
              .build();
      
  2. إنشاء PendingIntent لإجراء الرد

    Kotlin

      // Build a PendingIntent for the reply action to trigger.
      var replyPendingIntent: PendingIntent =
          PendingIntent.getBroadcast(applicationContext,
              conversation.getConversationId(),
              getMessageReplyIntent(conversation.getConversationId()),
              PendingIntent.FLAG_UPDATE_CURRENT)
      

    Java

      // Build a PendingIntent for the reply action to trigger.
      PendingIntent replyPendingIntent =
              PendingIntent.getBroadcast(getApplicationContext(),
                      conversation.getConversationId(),
                      getMessageReplyIntent(conversation.getConversationId()),
                      PendingIntent.FLAG_UPDATE_CURRENT);
      
  3. أرفِق الكائن RemoteInput بالإجراء باستخدام addRemoteInput().

    Kotlin

      // Create the reply action and add the remote input.
      var action: NotificationCompat.Action =
          NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
              getString(R.string.label), replyPendingIntent)
              .addRemoteInput(remoteInput)
              .build()
      

    Java

      // Create the reply action and add the remote input.
      NotificationCompat.Action action =
              new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
                      getString(R.string.label), replyPendingIntent)
                      .addRemoteInput(remoteInput)
                      .build();
      
  4. يمكنك تطبيق الإجراء على إشعار وإصداره.

    Kotlin

      // Build the notification and add the action.
      val newMessageNotification = Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build()
    
      // Issue the notification.
      with(NotificationManagerCompat.from(this)) {
          notificationManager.notify(notificationId, newMessageNotification)
      }
      

    Java

      // Build the notification and add the action.
      Notification newMessageNotification = new Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build();
    
      // Issue the notification.
      NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
      notificationManager.notify(notificationId, newMessageNotification);
      

يطلب النظام من المستخدم إدخال رد عند تشغيل إجراء الإشعار، كما هو موضح في الشكل 4.

استرداد البيانات التي أدخلها المستخدم من الردّ

لتلقّي البيانات من المستخدم من واجهة المستخدم الخاصة بالرد على الإشعار، يمكنك الاتصال بالرقم RemoteInput.getResultsFromIntent()، مع تمرير قيمة Intent إليه من خلال BroadcastReceiver:

Kotlin

private fun getMessageText(intent: Intent): CharSequence? {
    return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY)
}

Java

private CharSequence getMessageText(Intent intent) {
    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
    if (remoteInput != null) {
        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
    }
    return null;
 }

بعد معالجة النص، يمكنك تعديل الإشعار من خلال طلب إدخال "NotificationManagerCompat.notify()" برقم التعريف والعلامة نفسيهما في حال استخدامهما. وهذا من الضروري إخفاء واجهة المستخدم الخاصة بالردّ المباشر والتأكّد للمستخدم من تلقّي ردّه ومعالجتها بشكل صحيح.

Kotlin

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
val repliedNotification = Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build()

// Issue the new notification.
NotificationManagerCompat.from(this).apply {
    notificationManager.notify(notificationId, repliedNotification)
}

Java

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
Notification repliedNotification = new Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build();

// Issue the new notification.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, repliedNotification);

عند التعامل مع هذا الإشعار الجديد، استخدِم السياق الذي تم تمريره إلى طريقة onReceive() المستلِم.

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

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

إضافة شريط تقدّم

يمكن أن تتضمّن الإشعارات مؤشر تقدّم متحركًا يُظهر للمستخدمين حالة العملية الجارية.

الشكل 5. شريط التقدم أثناء عملية ما.

إذا كان بإمكانك تقدير نسبة اكتمال العملية في أي وقت، استخدِم صيغة "تحديد" للمؤشر، كما هو موضّح في الشكل 5، من خلال استدعاء setProgress(max, progress, false). أمّا المَعلمة الأولى، فهي عبارة عن قيمة "complete"، مثل 100. والثاني هو مدى الاكتمال. يشير الأخير إلى أن هذا شريط تقدم محدد.

أثناء متابعة العملية، يمكنك الاتصال بخدمة setProgress(max, progress, false) باستمرار مع إضافة قيمة معدّلة لـ progress وإعادة إصدار الإشعار، كما هو موضّح في المثال التالي.

Kotlin

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentTitle("Picture Download")
    setContentText("Download in progress")
    setSmallIcon(R.drawable.ic_notification)
    setPriority(NotificationCompat.PRIORITY_LOW)
}
val PROGRESS_MAX = 100
val PROGRESS_CURRENT = 0
NotificationManagerCompat.from(this).apply {
    // Issue the initial notification with zero progress.
    builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
    notify(notificationId, builder.build())

    // Do the job that tracks the progress here.
    // Usually, this is in a worker thread.
    // To show progress, update PROGRESS_CURRENT and update the notification with:
    // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
    // notificationManager.notify(notificationId, builder.build());

    // When done, update the notification once more to remove the progress bar.
    builder.setContentText("Download complete")
            .setProgress(0, 0, false)
    notify(notificationId, builder.build())
}

Java

...
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentTitle("Picture Download")
        .setContentText("Download in progress")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW);

// Issue the initial notification with zero progress.
int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
notificationManager.notify(notificationId, builder.build());

// Do the job that tracks the progress here.
// Usually, this is in a worker thread.
// To show progress, update PROGRESS_CURRENT and update the notification with:
// builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
// notificationManager.notify(notificationId, builder.build());

// When done, update the notification once more to remove the progress bar.
builder.setContentText("Download complete")
        .setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());

في نهاية العملية، يجب أن يساوي progress القيمة max. يمكنك ترك شريط التقدم لإظهار أن العملية قد تمت أو إزالتها. في كلتا الحالتين، قم بتحديث نص الإشعار لتوضيح أن العملية قد اكتملت. لإزالة شريط التقدّم، يمكنك طلب الرقم setProgress(0, 0, false).

لعرض شريط تقدّم غير محدَّد (شريط لا يشير إلى النسبة المئوية للاكتمال)، اتصِل بالرقم setProgress(0, 0, true). النتيجة هي مؤشر له نفس نمط شريط التقدم السابق باستثناء أنه رسم متحرك مستمر لا يشير إلى الاكتمال. تعمل الرسوم المتحركة للتقدم حتى تتصل بـ setProgress(0, 0, false) ثم تُعدِّل الإشعار لإزالة مؤشر النشاط.

وتذكَّر تغيير نص الإشعار للإشارة إلى اكتمال العملية.

ضبط فئة على مستوى النظام

يستخدم Android فئات محددة مسبقًا على مستوى النظام لتحديد ما إذا كان يجب إزعاج المستخدم بإشعار معيّن عندما يفعّل المستخدم وضع "عدم الإزعاج".

إذا كان إشعارك يندرج ضمن إحدى فئات الإشعارات المحدّدة في NotificationCompat، مثل CATEGORY_ALARM أو CATEGORY_REMINDER أو CATEGORY_EVENT أو CATEGORY_CALL، يمكنك الإفصاح عن ذلك من خلال تمرير الفئة المناسبة إلى setCategory():

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE);

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

عرض رسالة عاجلة

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

عند استدعاء الإشعار، ستظهر للمستخدمين إحدى الحالات التالية بناءً على حالة قفل الجهاز:

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

يوضّح مقتطف الرمز التالي كيفية ربط إشعارك بطلب ملء الشاشة:

Kotlin

val fullScreenIntent = Intent(this, ImportantActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
    fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true)

Java

Intent fullScreenIntent = new Intent(this, ImportantActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true);

ضبط إذن الوصول إلى شاشة القفل

للتحكّم في مستوى التفاصيل المرئية في الإشعار من شاشة القفل، انقر على رمز setVisibility() وحدِّد إحدى القيم التالية:

  • VISIBILITY_PUBLIC: يظهر المحتوى الكامل للإشعارات على شاشة القفل.

  • VISIBILITY_SECRET: لا يظهر أي جزء من الإشعار على شاشة القفل.

  • VISIBILITY_PRIVATE: تظهر المعلومات الأساسية فقط على شاشة القفل، مثل رمز الإشعار وعنوان المحتوى. لا يظهر المحتوى الكامل للإشعار.

عند ضبط السمة VISIBILITY_PRIVATE، يمكنك أيضًا تقديم نسخة بديلة من محتوى الإشعار الذي يخفي تفاصيل معيّنة. فمثلاً، قد يعرض تطبيق SMS إشعارًا يعرض الرسالة "لديك 3 رسائل نصية جديدة"، ولكنه يخفي محتوى الرسالة ومرسليها. لتقديم هذا الإشعار البديل، عليك أولاً إنشاء الإشعار البديل من خلال NotificationCompat.Builder كالمعتاد. بعد ذلك، يمكنك إرفاق الإشعار البديل بالإشعار العادي باستخدام الرمز setPublicVersion().

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

تعديل إشعار

لتعديل إشعار بعد إصداره، عليك طلب الرقم NotificationManagerCompat.notify() مجددًا مع تمرير رقم التعريف نفسه الذي سبق لك استخدامه. إذا تم إغلاق الإشعار السابق، سيتم إنشاء إشعار جديد بدلاً من ذلك.

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

إزالة إشعار

وتظل الإشعارات مرئية إلى أن يحدث أي مما يلي:

  • يستبعد المستخدم الإشعار.
  • ينقر المستخدم على الإشعار، في حال الاتصال بـ setAutoCancel() عند إنشاء الإشعار.
  • يمكنك الاتصال بالرقم cancel() للحصول على معرّف محدد للإشعار. تؤدي هذه الطريقة أيضًا إلى حذف الإشعارات المستمرة.
  • يمكنك الاتصال بالرقم cancelAll()، مما يؤدي إلى إزالة جميع الإشعارات التي سبق أن أصدرتها.
  • تنقضي المدة المحدّدة، في حال ضبط مهلة عند إنشاء الإشعار، باستخدام setTimeoutAfter(). يمكنك، إذا لزم الأمر، إلغاء إشعار قبل انقضاء مدة المهلة المحدّدة.

أفضل الممارسات لتطبيقات المراسلة

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

استخدام MessagingStyle

بدءًا من الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات)، يوفّر Android نموذج نمط إشعار مخصَّصًا خصيصًا لمحتوى المراسلة. باستخدام الصف NotificationCompat.MessagingStyle، يمكنك تغيير العديد من التصنيفات المعروضة في الإشعار، بما في ذلك عنوان المحادثة والرسائل الإضافية وعرض المحتوى للإشعار.

يوضح مقتطف الرمز التالي كيفية تخصيص نمط إشعار باستخدام فئة MessagingStyle.

Kotlin

val user = Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build()

val notification = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with $sender")
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build()

Java

Person user = new Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build();

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with " + sender)
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(new NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build();

وبدءًا من الإصدار Android 9.0 (المستوى 28 من واجهة برمجة التطبيقات)، يجب أيضًا استخدام فئة Person لعرض الإشعار والصور الرمزية بالشكل الأمثل.

عند استخدام "NotificationCompat.MessagingStyle"، اتّبِع الخطوات التالية:

  • يمكنك الاتصال بالرقم MessagingStyle.setConversationTitle() لتحديد عنوان للمحادثات الجماعية التي تضم أكثر من شخصين. قد يكون عنوان المحادثة الجيد هو اسم الدردشة الجماعية أو قائمة بالمشاركين في المحادثة إذا لم يكن له اسم. بدون ذلك، قد يتم اعتبار الرسالة أنها تنتمي إلى محادثة فردية مع مُرسِل أحدث رسالة في المحادثة.
  • استخدِم الطريقة MessagingStyle.setData() لتضمين رسائل الوسائط مثل الصور. يتم دعم أنواع MIME للنمط image/*.

استخدام ميزة "الرد المباشر"

تتيح ميزة "الرد المباشر" للمستخدم الرد المضمّن على الرسالة.

  • بعد أن يردّ المستخدم باستخدام إجراء الرد المضمّن، يمكنك استخدام MessagingStyle.addMessage() لتعديل إشعار MessagingStyle، ولا تسحب الإشعار أو تلغيه. يؤدي عدم إلغاء الإشعار إلى السماح للمستخدم بإرسال ردود متعددة من الإشعار.
  • لجعل إجراء الردّ المضمّن متوافقًا مع Wear OS، يمكنك الاتصال على الرقم Action.WearableExtender.setHintDisplayInlineAction(true).
  • يمكنك استخدام طريقة addHistoricMessage() لتوفير سياق لمحادثة الردّ المباشر من خلال إضافة رسائل سابقة إلى الإشعار.

تفعيل ميزة "الرد السريع"

  • لتفعيل ميزة "الرد السريع"، يمكنك الاتصال setAllowGeneratedResponses(true) بإجراء الرد. ويؤدي ذلك إلى إتاحة ردود "الرد السريع" للمستخدمين عند ربط الإشعار بجهاز Wear OS. يتم إنشاء الردود عبر ميزة "الرد السريع" من خلال نموذج لتعلُّم الآلة داخل الساعة بالكامل باستخدام السياق الذي يقدّمه إشعار NotificationCompat.MessagingStyle ولا يتم تحميل أي بيانات على الإنترنت لإنشاء الردود.

إضافة البيانات الوصفية للإشعارات

  • يمكنك تعيين البيانات الوصفية للإشعارات لإخبار النظام بكيفية التعامل مع إشعارات التطبيق عندما يكون الجهاز في Do Not Disturb mode. على سبيل المثال، استخدِم الطريقة addPerson() أو setCategory(Notification.CATEGORY_MESSAGE) لإلغاء وضع "عدم الإزعاج".