יצירת התראה

ההתראות מספקות מידע קצר ועדכני על אירועים באפליקציה בזמן שהיא לא בשימוש. במאמר הזה מוסבר איך ליצור התראה עם תכונות שונות. בסקירה הכללית על התראות מוסבר איך ההתראות מוצגות ב-Android. קוד לדוגמה שמשתמש בהתראות זמין בדוגמה של SociaLite ב-GitHub.

הקוד בדף הזה משתמש בממשקי NotificationCompat API מהספרייה AndroidX. ממשקי ה-API האלה מאפשרים להוסיף תכונות שזמינות רק בגרסאות חדשות יותר של Android, ועדיין לספק תאימות עד Android 9 (רמת API‏ 28). עם זאת, חלק מהתכונות, כמו פעולת התשובה בתוך ההודעה, לא פועלות בגרסאות קודמות.

יצירת התראה בסיסית

ההתראה בפורמט הבסיסי והקומפקטי ביותר שלה – שנקרא גם פורמט מכווץ – מציגה סמל, כותרת וכמות קטנה של תוכן טקסט. בקטע הזה מוסבר איך ליצור התראה שהמשתמש יכול להקיש עליה כדי להפעיל פעילות באפליקציה.

איור 1. התראה עם סמל, כותרת וטקסט.

לפרטים נוספים על כל חלק בהתראה, אפשר לקרוא על המבנה של ההתראה.

הצהרה על ההרשאה בזמן ריצה

‫Android מגרסה 13 (רמת API‏ 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 (רמת API‏ 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...")
        <b>.setStyle(NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))</b>
        .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...")
        <b>.setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))</b>
        .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. הפרמטר הזה קובע איך להפריע למשתמש בכל התראה ששייכת לערוץ הזה. כדי לתמוך ב-Android 7.1 ומטה, מגדירים את העדיפות באמצעות setPriority(), כמו בדוגמה הקודמת.

למרות שצריך להגדיר את רמת החשיבות או העדיפות של ההתראה כמו בדוגמה הבאה, המערכת לא מבטיחה את התנהגות ההתראה שתקבלו. במקרים מסוימים, המערכת עשויה לשנות את רמת החשיבות על סמך גורמים אחרים, והמשתמש תמיד יכול להגדיר מחדש את רמת החשיבות של ערוץ מסוים.

מידע נוסף על המשמעות של הרמות השונות זמין במאמר בנושא רמות החשיבות של ההתראות.

הגדרת פעולת ההקשה של ההתראה

כל התראה צריכה להגיב להקשה, בדרך כלל כדי לפתוח פעילות באפליקציה שתואמת להתראה. כדי לעשות זאת, מציינים כוונת תוכן שמוגדרת באמצעות אובייקט PendingIntent ומעבירים אותו אל setContentIntent().

קטע הקוד הבא מראה איך ליצור intent בסיסי לפתיחת פעילות כשמשתמש מקיש על ההתראה:

Kotlin

// Create an explicit intent for an Activity in your app.
<b>val intent = Intent(this, AlertDetails::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}</b>
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.
        <b>.setContentIntent(pendingIntent)</b>
        .setAutoCancel(true)

Java

// Create an explicit intent for an Activity in your app.
<b>Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);</b>
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.
        <b>.setContentIntent(pendingIntent)</b>
        .setAutoCancel(true);

הקוד הזה קורא ל-setAutoCancel(), שמסיר את ההתראה באופן אוטומטי כשהמשתמש מקיש עליה.

דגלי הכוונה בדוגמה הקודמת שומרים על חוויית הניווט הצפויה של המשתמש אחרי שהוא פותח את האפליקציה באמצעות ההתראה. יכול להיות שתרצו להשתמש בו בהתאם לסוג הפעילות שאתם מתחילים, שיכול להיות אחד מהסוגים הבאים:

  • פעילות שקיימת רק כדי להגיב להתראה. אין סיבה שהמשתמש ינווט לפעילות הזו במהלך שימוש רגיל באפליקציה, ולכן הפעילות מתחילה משימה חדשה במקום להתווסף למשימה ולערימת הפעולות הקודמות הקיימות באפליקציה. זהו סוג הכוונה שנוצר בדוגמה הקודמת.

  • פעילות שקיימת בתהליך הרגיל של האפליקציה. במקרה הזה, התחלת הפעילות יוצרת ערימת חזרה כדי לשמור על הציפיות של המשתמשים לגבי הלחצנים 'הקודם' ו'למעלה'.

מידע נוסף על הדרכים השונות להגדרת הכוונה של ההתראה זמין במאמר בנושא הפעלת פעילות מתוך התראה.

הצגת ההתראה

כדי שההתראה תופיע, קוראים ל-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&lt;out String&gt;,
        //                                        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

if (ActivityCompat.checkSelfPermission(this, android.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;
}
NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, builder.build());

שומרים את מזהה ההתראה שמעבירים אל NotificationManagerCompat.notify(), כי תצטרכו אותו כשתרצו לעדכן או להסיר את ההתראה.

בנוסף, כדי לבדוק התראות בסיסיות במכשירים עם Android מגרסה 13 ואילך, צריך להפעיל את ההתראות באופן ידני או ליצור תיבת דו-שיח לבקשת התראות.

הוספת כפתורי פעולה

התראה יכולה לכלול עד שלושה לחצני פעולה שמאפשרים למשתמש להגיב במהירות, למשל להעביר תזכורת למצב נודניק או לענות להודעת טקסט. אבל לחצני הפעולה האלה לא יכולים לשכפל את הפעולה שמתבצעת כשמשתמש מקיש על ההתראה.

איור 3. התראה עם כפתור פעולה אחד.

כדי להוסיף לחצן פעולה, מעבירים PendingIntent לשיטה addAction(). זה דומה להגדרת פעולת ברירת המחדל של ההתראה בלחיצה, רק שבמקום להפעיל פעילות, אפשר לבצע פעולות אחרות כמו הפעלה של BroadcastReceiver שמבצעת עבודה ברקע, כך שהפעולה לא מפריעה לאפליקציה שכבר פתוחה.

לדוגמה, הקוד הבא מראה איך לשלוח שידור למקלט ספציפי:

Kotlin

val ACTION_SNOOZE = "snooze"

<b>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)</b>
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        <b>.addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent)</b>

Java

String ACTION_SNOOZE = "snooze"

<b>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);</b>

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)
        <b>.addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent);</b>

מידע נוסף על יצירת BroadcastReceiver להפעלת משימות ברקע זמין במאמר סקירה כללית על שידורים.

אם אתם מנסים ליצור התראה עם לחצני הפעלה של מדיה, כמו השהיה ודילוג על טראקים, תוכלו לקרוא איך ליצור התראה עם אמצעי בקרה של מדיה.

הוספת פעולה של תגובה ישירה

הפעולה 'תשובה ישירה', שהוצגה ב-Android 7.0 (רמת API ‏24), מאפשרת למשתמשים להזין טקסט ישירות בהתראה. הטקסט מועבר לאפליקציה בלי לפתוח פעילות. לדוגמה, אפשר להשתמש בפעולת תשובה ישירה כדי לאפשר למשתמשים להשיב להודעות טקסט או לעדכן רשימות משימות מתוך ההתראה.

איור 4. הקשה על הלחצן 'תשובה' פותחת את הזנת הטקסט.

פעולת התשובה הישירה מופיעה כלחצן נוסף בהתראה, שפותח שדה להזנת טקסט. כשהמשתמש מסיים להקליד, המערכת מצרפת את תגובת הטקסט ל-Intent שציינתם לפעולת ההתראה ושולחת את ה-Intent לאפליקציה.

הוספת לחצן התשובה

כדי ליצור פעולת התראה שתומכת בתשובה ישירה, פועלים לפי השלבים הבאים:

  1. יוצרים מופע של RemoteInput.Builder שאפשר להוסיף לפעולת ההתראה. הקונסטרוקטור של המחלקה הזו מקבל מחרוזת שהמערכת משתמשת בה כמפתח לקלט הטקסט. האפליקציה משתמשת במפתח הזה מאוחר יותר כדי לאחזר את הטקסט של הקלט. ‪* {Kotlin} ```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} ```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} ```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} ```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} ```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} ```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} ```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} ```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);

אחזור נתונים אחרים

הטיפול בסוגי נתונים אחרים דומה לטיפול ב-RemoteInput. בדוגמה הבאה נעשה שימוש בתמונה כקלט.

Kotlin

  // Key for the data that's delivered in the action's intent.
  private val KEY_REPLY = "key_reply"
  var replyLabel: String = resources.getString(R.string.reply_label)
  var remoteInput: RemoteInput = RemoteInput.Builder(KEY_REPLY).run {
      setLabel(replyLabel)
      // Allow for image data types in the input
  // This method can be used again to
  // allow for other data types
      setAllowDataType("image/*", true)
      build()
}

קוראים ל-RemoteInput#getDataResultsFromIntent ומחלצים את הנתונים המתאימים.

Kotlin

  import android.app.RemoteInput;
  import android.content.Intent;
  import android.os.Bundle;

  class ReplyReceiver: BroadcastReceiver()  {

      public static final String KEY_DATA = "key_data";

      public static void handleRemoteInput(Intent intent) {
          Bundle dataResults = RemoteInput.getDataResultsFromIntent(intent, KEY_DATA);
          val imageUri: Uri? = dataResults.values.firstOrNull()
          if (imageUri != null) {
              // Extract the image
          try {
                  val inputStream = context.contentResolver.openInputStream(imageUri)
                  val bitmap = BitmapFactory.decodeStream(inputStream)
                  // Display the image
                  // ...
              } catch (e: Exception) {
                  Log.e("ReplyReceiver", "Failed to process image URI", e)
              }
      }
  }

כשעובדים עם ההתראה החדשה הזו, צריך להשתמש בהקשר שמועבר לשיטה onReceive() של הנמען.

תצרף את התשובה לחלק התחתון של ההתראה על ידי קריאה ל- setRemoteInputHistory(). עם זאת, אם אתם מפתחים אפליקציית הודעות, כדאי ליצור התראה בסגנון הודעה ולצרף את ההודעה החדשה לשיחה.

טיפים נוספים לגבי התראות מאפליקציות לשליחת הודעות מפורטים בקטע שיטות מומלצות לשימוש באפליקציות לשליחת הודעות.

הצגת הודעה דחופה

יכול להיות שהאפליקציה שלכם תצטרך להציג הודעה דחופה שצריך להגיב אליה במהירות, כמו שיחה טלפונית נכנסת או שעון מעורר מצלצל. במקרים כאלה, אפשר לשייך כוונה למסך מלא להתראה.

כשמופעלת ההתראה, המשתמשים רואים אחת מהאפשרויות הבאות, בהתאם לסטטוס הנעילה של המכשיר:

  • אם המכשיר של המשתמש נעול, מוצגת פעילות במסך מלא שמכסה את מסך הנעילה.
  • אם המכשיר של המשתמש לא נעול, ההתראה תופיע בצורה מורחבת עם אפשרויות לטיפול בהתראה או לסגירה שלה.

בקטע הקוד הבא מוצג איך משייכים את ההתראה ל-Intent במסך מלא:

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)
        <b>.setFullScreenIntent(fullScreenPendingIntent, true)</b>

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)
        <b>.setFullScreenIntent(fullScreenPendingIntent, true);</b>

הגדרת סטטוס השיתוף של מסך הנעילה

כדי לשלוט ברמת הפירוט שמוצגת בהתראה במסך הנעילה, צריך להתקשר אל setVisibility() ולציין אחד מהערכים הבאים:

  • VISIBILITY_PUBLIC: התוכן המלא של ההתראה מוצג במסך הנעילה.

  • VISIBILITY_SECRET: אף חלק מההתראה לא מוצג במסך הנעילה.

  • VISIBILITY_PRIVATE: במסך הנעילה מוצגים רק פרטים בסיסיים, כמו הסמל של ההתראה וכותרת התוכן. התוכן המלא של ההתראה לא מוצג.

כשמגדירים את הערך VISIBILITY_PRIVATE, אפשר גם לספק גרסה חלופית של תוכן ההתראה שבה פרטים מסוימים מוסתרים. לדוגמה, אפליקציית SMS עשויה להציג התראה עם הכיתוב 'יש לך 3 הודעות טקסט חדשות', אבל להסתיר את תוכן ההודעות ואת השולחים. כדי לספק את ההתראה החלופית הזו, צריך קודם ליצור את ההתראה החלופית באמצעות NotificationCompat.Builder כרגיל. לאחר מכן, מצרפים את התזכורת החלופית לתזכורת הרגילה באמצעות setPublicVersion().

חשוב לזכור שהמשתמש תמיד יכול להחליט אם ההתראות שלו יוצגו במסך הנעילה, והוא יכול לשלוט בהן על סמך ערוצי ההתראות של האפליקציה.

עדכון התראה

כדי לעדכן התראה אחרי ששולחים אותה, צריך להתקשר שוב אל NotificationManagerCompat.notify() ולהעביר לה את אותו מזהה שבו השתמשתם קודם. אם ההתראה הקודמת נסגרה, נוצרת במקומה התראה חדשה.

אפשר להפעיל את הפונקציה setOnlyAlertOnce() כדי שההתראה תפריע למשתמש – באמצעות צליל, רטט או רמזים ויזואליים – רק בפעם הראשונה שההתראה מופיעה ולא בעדכונים מאוחרים יותר.

הסרת התראה

ההתראות יוצגו עד שאחד מהדברים הבאים יקרה:

  • המשתמש סוגר את ההתראה.
  • המשתמש מקיש על ההתראה, אם מתקשרים אל setAutoCancel() כשיוצרים את ההתראה.
  • מתקשרים אל cancel() לגבי מזהה התראה ספציפי. השיטה הזו מוחקת גם התראות שוטפות.
  • אתם מתקשרים אל cancelAll(), שמסיר את כל ההתראות שהוצאו קודם.
  • אם הגדרתם פסק זמן כשיוצרים את ההתראה באמצעות setTimeoutAfter(), ההתראה תפוג אחרי משך הזמן שצוין. אם צריך, אפשר לבטל התראה לפני שחלף הזמן הקצוב לתפוגה שצוין.

שיטות מומלצות לשימוש באפליקציות להעברת הודעות

כדאי לפעול לפי השיטות המומלצות שמפורטות כאן כשיוצרים התראות לאפליקציות של הודעות וצ'אט.

שימוש ב-MessagingStyle

החל מ-Android 7.0 (רמת API‏ 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 (רמת API‏ 28), נדרש גם להשתמש במחלקה Person כדי לקבל עיבוד אופטימלי של ההתראה והאווטרים שלה.

כשמשתמשים ב-NotificationCompat.MessagingStyle, מבצעים את הפעולות הבאות:

  • שיחה MessagingStyle.setConversationTitle() כדי להגדיר שם לצ'אטים קבוצתיים עם יותר משני אנשים. שם טוב לשיחה יכול להיות השם של הצ'אט הקבוצתי, או אם אין לו שם, רשימה של המשתתפים בשיחה. בלי זה, יכול להיות שההודעה תזוהה בטעות כהודעה בשיחה אישית עם השולח של ההודעה האחרונה בשיחה.
  • משתמשים בשיטה MessagingStyle.setData() כדי לכלול הודעות מדיה כמו תמונות. יש תמיכה בסוגי MIME של התבנית image/* ‎.

איך משתמשים בתשובה ישירה

התכונה 'תשובה ישירה' מאפשרת למשתמשים להוסיף תשובה בשרשור.

  • אחרי שמשתמש משיב באמצעות פעולת התשובה בתוך ההודעה, צריך להשתמש ב-MessagingStyle.addMessage() כדי לעדכן את ההתראה MessagingStyle, ולא לבטל או להסיר את ההתראה. אם לא מבטלים את ההתראה, המשתמש יכול לשלוח כמה תשובות מההתראה.
  • כדי שהפעולה של התשובה בתוך ההודעה תהיה תואמת ל-Wear OS, צריך לקרוא ל-Action.WearableExtender.setHintDisplayInlineAction(true).
  • אפשר להשתמש בשיטה addHistoricMessage() כדי לספק הקשר לשיחה בתגובה ישירה על ידי הוספת הודעות קודמות להתראה.

הפעלת התכונה 'תשובה מהירה'

  • כדי להפעיל את התשובה המהירה, קוראים לפונקציה setAllowGeneratedResponses(true) בפעולת התשובה. כתוצאה מכך, התשובות המהירות זמינות למשתמשים כשההתראה מועברת למכשיר WearOS. התשובות של 'תשובה חכמה' נוצרות על ידי מודל למידת מכונה שפועל כולו בשעון, על סמך ההקשר שמופיע בNotificationCompat.MessagingStyleההתראה, ולא מתבצעת העלאה של נתונים לאינטרנט כדי ליצור את התשובות.

הוספת מטא-נתונים של התראות