איחוד התראות בנייד

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

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

איחוד ההתראות הקבועות

רכיבים

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


ה-SDK של הניווט מכיל שיטות סטטיות לאתחול ולקבלה של הסינגלטון ForegroundServiceManager. ניתן לאתחל את הסינגלטון הזה רק פעם אחת בכל משך החיים של ה-SDK של הניווט. לכן, אם אתם משתמשים באחת מקריאות האתחול (initForegroundServiceManagerMessageAndIntent() או initForegroundServiceManagerProvider()), עליכם להקיף אותה בבלוק מסוג Try-catch (איתור מהיר) למקרה שהנתיב יוזן מחדש. ה-SDK של הניווט יוצר חריג בזמן ריצה במקרה שקוראים לאחת מהשיטות יותר מפעם אחת, אלא אם מסירים קודם את כל ההפניות ל-ForegroundServiceManager וקוראים ל-clearForegroundServiceManager() לפני כל קריאה נוספת.

ארבעת הפרמטרים של initForegroundServiceManagerMessageAndIntent() הם application, notificationId, defaultMessage ו-resumeIntent. במקרה ששלושת הפרמטרים האחרונים הם null, ההודעה היא ההודעה הרגילה של ה-SDK לניווט. עדיין אפשר להסתיר שירותים אחרים שפועלים בחזית באפליקציה שמאחורי ההתראה הזו. הפרמטר notificationId מציין את מזהה ההתראה שצריך להשתמש בו עבור ההתראה. אם הוא null, אז נעשה שימוש בערך שרירותי. אפשר להגדיר אותו במפורש כך שימנע התנגשויות עם התראות אחרות, כמו הודעות מ-SDK אחר. הערך defaultMessage הוא מחרוזת שמוצגת כשהמערכת לא מנווטת. השדה resumeIntent הוא Intent שמופעלת כשלוחצים על ההתראה. אם הערך של resumeIntent הוא null, המערכת מתעלמת מהקליקים על ההתראה.

שלושת הפרמטרים של initForegroundServiceManagerProvider() הם application, notificationId ו-notificationProvider. אם שני הפרמטרים האחרונים הם null, ההודעה היא ההודעה הרגילה של ה-SDK לניווט. הפרמטר notificationId מציין את מזהה ההתראה שצריך להשתמש בו להתראה. אם הוא null, אז נעשה שימוש בערך שרירותי. אפשר להגדיר אותה במפורש לצורך עקיפת התנגשויות עם התראות אחרות, כמו הודעות מ-SDK אחר. אם השדה notificationProvider מוגדר, הספק תמיד אחראי ליצור את ההתראה שתוצג.

השיטה getForegroundServiceManager() של הניווט SDK מחזירה את הסינגלטון של מנהל השירות שפועל בחזית. אם עדיין לא יצרתם אותו, היא מקבילה לקריאה ל-initForegroundServiceManagerMessageAndIntent() עם פרמטרים ריקים עבור notificationId, defaultMessage ו-resumeIntent.

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

אם אתם צריכים שליטה מלאה בהתראה הקבועה המשותפת, ה-API מספק ממשק NotificationContentProvider להגדרת ספק התראות, שמכיל שיטה אחת לקבלת התראה עם התוכן הנוכחי. הוא גם מספק מחלקת בסיס, שאפשר להשתמש בה כדי להגדיר את הספק. אחת המטרות העיקריות של מחלקת הבסיס היא שהיא מספקת דרך להפעיל את updateNotification() בלי שתצטרכו לגשת אל ForegroundServiceManager. אם משתמשים במופע של ספק ההתראות כדי לקבל התראות חדשות, אפשר לקרוא לשיטה הפנימית הזו ישירות כדי לעבד את ההודעה בהתראה.

תרחישי שימוש

בקטע הזה מתוארים תרחישי השימוש לגבי השימוש בהתראות הקבועות המשותפות.

הסתרת ההתראות הקבועות לגבי שירותים אחרים שפועלים בחזית של האפליקציה
התרחיש הקל ביותר הוא לשמור על ההתנהגות הנוכחית ולהשתמש רק בהתראה הקבועה כדי לעבד את המידע מה-SDK של הניווט. שירותים אחרים יכולים להסתיר מאחורי ההתראה הזו באמצעות השימוש במנהל השירות שפועל בחזית startForeground() ובשיטות stopForeground().
הסתרת התראות קבועות על שירותים אחרים שפועלים בחזית של האפליקציה, אבל הגדרה של טקסט ברירת המחדל שיוצג כשלא מנווטים
התרחיש השני הקל ביותר הוא לשמור על ההתנהגות הנוכחית ולהשתמש רק בהתראה הקבועה לעיבוד מידע מה-SDK של הניווט, למעט כאשר המערכת לא מנווטת. כשהמערכת לא מנווטת, המחרוזת שצוינה אל initForegroundServiceManagerMessageAndIntent() מוצגת במקום מחרוזת ברירת המחדל של ה-SDK לניווט, שמציינת את "מפות Google". אפשר להשתמש בקריאה הזו גם כדי להגדיר את כוונת המשך שיופעל כשלוחצים על ההתראה.
יש לך אפשרות לשלוט באופן מלא על אופן ההצגה של ההתראה הקבועה
בתרחיש האחרון, צריך להגדיר וליצור ספק התראות ולהעביר אותו ל-ForegroundServiceManager באמצעות initForegroundServiceManagerProvider(). אפשרות זו נותנת לך שליטה מלאה על מה שמוצג בהודעה, אבל היא גם מנתקת את המידע על ההודעה של ה-SDK של הניווט מההתראה. כתוצאה מכך, הודעות המסלול המפורטות שמוצגות בהתראה. Google לא מספקת אמצעי פשוט לאחזור המידע הזה ולהכנסתו להודעה.

דוגמה של ספק התראות

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

public class NotificationContentProviderImpl
   extends NotificationContentProviderBase
   implements NotificationContentProvider {
 private String channelId;
 private Context context;
 private String message;

 /** Constructor */
 public NotificationContentProviderImpl(Application application) {
   super(application);
   message = "-- uninitialized --";
   channelId = null;
   this.context = application;
 }

 /**
  * Sets message to display in the notification. Calls updateNotification
  * to display the message immediately.
  *
  * @param msg The message to display in the notification.
  */
 public void setMessage(String msg) {
   message = msg;
   updateNotification();
 }

 /**
  * Returns the notification as it should be rendered.
  */
 @Override
 public Notification getNotification() {
   Notification notification;

   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     Spanned styledText = Html.fromHtml(message, FROM_HTML_MODE_LEGACY);
     String channelId = getChannelId(context);
     notification =
         new Notification.Builder(context, channelId)
             .setContentTitle("Notifications Demo")
             .setStyle(new Notification.BigTextStyle()
                 .bigText(styledText))
             .setSmallIcon(R.drawable.ic_navigation_white_24dp)
             .setTicker("ticker text")
             .build();
   } else {
     notification = new Notification.Builder(context)
         .setContentTitle("Notification Demo")
         .setContentText("testing non-O text")
         .build();
   }

   return notification;
 }

 // Helper to set up a channel ID.
 private String getChannelId(Context context) {
   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     if (channelId == null) {
       NotificationManager notificationManager =
           (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
       NotificationChannel channel = new NotificationChannel(
           "default", "navigation", NotificationManager.IMPORTANCE_DEFAULT);
       channel.setDescription("For navigation persistent notification.");
       notificationManager.createNotificationChannel(channel);
       channelId = channel.getId();
     }
     return channelId;
   } else {
     return "";
   }
 }
}

אחרי שיצרתם את NotificationContentProviderImpl, תחברו אליו את ה-API של הניווט באמצעות הקוד הבא:

ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);

אזהרות ותוכניות עתידיות

  • חשוב להתקשר ל-initForegroundServiceManagerMessageAndIntent() או ל-initForegroundServiceManagerProvider() לפני כן כדי שתרחיש השימוש הצפוי מוגדר בצורה טובה. צריך לקרוא לשיטה הזו לפני שיוצרים כלי ניווט חדש.
  • חשוב לשים לב לחריגים משיחות אל initForegroundServiceManagerMessageAndIntent() או אל initForegroundServiceManagerProvider() במקרה שנתיב הקוד הוזן יותר מפעם אחת. ב-API של הניווט בגרסה 2.0, הפעלת השיטה הזו מספר פעמים תגרום לחריג שנבדק ולא לחריג בזמן הריצה.
  • יכול להיות ש-Google עדיין תצטרך לעשות כדי לשמור על סגנון עקבי במשך משך החיים של ההתראה שיתאים לעיצוב הכותרת.
  • כשמגדירים ספק התראות, אפשר להשתמש בעדיפות.
  • Google לא מספקת אמצעי פשוט לאחזור מידע מפורט שספק התראות עשוי להוסיף להודעה.