إنشاء إشعار

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

تستخدِم الرموز البرمجية في هذه الصفحة واجهات برمجة التطبيقات NotificationCompat من مكتبة AndroidX. تتيح لك واجهات برمجة التطبيقات هذه إضافة ميزات متاحة فقط على الإصدارات الأحدث من Android مع الحفاظ على التوافق مع الإصدار 9 من Android (المستوى 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 منك تقديم معرّف channel. هذا الإجراء مطلوب للتوافق مع 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);

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

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

لكي تتمكّن من إرسال الإشعار على الإصدار 8.0 من نظام التشغيل Android والإصدارات الأحدث، عليك تسجيل قناة الإشعارات في النظام من خلال تمرير مثيل 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);
    }
}

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

تتطلّب الدالة الإنشائية 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 لتشغيل مهمة في background ، يُرجى الاطّلاع على نظرة عامة على "البثّات".

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

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

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

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

تعديل إشعار

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

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

إزالة إشعار

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

  • يرفض المستخدم الإشعار.
  • ينقر المستخدم على الإشعار، إذا كنت تستدعي 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();

بدءًا من الإصدار 9.0 من Android (المستوى 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) لإلغاء وضع "عدم الإزعاج".