إنشاء إشعار

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

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

إضافة AndroidX Core Library

على الرغم من أنّ معظم المشاريع التي تم إنشاؤها باستخدام "استوديو 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 لواجهة برمجة التطبيقات) والإصدارات الأحدث الحصول على إذن التشغيل لنشر الإشعارات غير المعفاة (بما في ذلك الإشعارات عن الخدمات التي تعمل في المقدّمة) من أحد التطبيقات.

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

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

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

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

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

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

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

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

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

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

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

استخدام أسلوب المراسلة

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