دمج إشعارات الجوّال

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

تزداد صعوبة هذه المشكلة عند استخدام حِزم تطوير البرامج (SDK)، مثل حزمة SDK للتنقّل، التي تشغّل خدمات تعمل في المقدّمة بشكل مستقل عن التطبيق الذي يتضمّن إشعاراته المستمرة المستقلة، ما يجعل من الصعب دمجها. لمعالجة هذه المشاكل، تم في الإصدار 1.11 من حزمة تطوير البرامج (SDK) لخدمة Navigation تقديم واجهة برمجة تطبيقات بسيطة للمساعدة في إدارة الإشعارات المستمرة في التطبيق، بما في ذلك داخل حزمة تطوير البرامج (SDK).

دمج الإشعارات المستمرة

المكونات

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


تحتوي حزمة تطوير البرامج (SDK) للتنقّل على طرق ثابتة لإعداد واسترداد العنصر الفردي ForegroundServiceManager. لا يمكن إعداد هذا النمط الفردي إلا مرة واحدة في عمر حزمة تطوير البرامج (SDK) للتنقّل. وبالتالي، إذا كنت تستخدم إحدى طلبات الإعداد (initForegroundServiceManagerMessageAndIntent() أو initForegroundServiceManagerProvider())، عليك إحاطتها بكتلة try-catch في حال إعادة إدخال هذا المسار. تعرض حزمة تطوير البرامج (SDK) للتنقّل استثناءً في وقت التشغيل إذا طلبت أيًا من الطريقتَين أكثر من مرة ما لم يتم أولاً محو جميع الإشارات إلى ForegroundServiceManager وطلب clearForegroundServiceManager() قبل كل طلب لاحق.

المَعلمات الأربع لـ "initForegroundServiceManagerMessageAndIntent()" هي application وnotificationId وdefaultMessage وresumeIntent. إذا كانت المَعلمات الثلاث الأخيرة فارغة، يكون الإشعار هو إشعار حزمة تطوير البرامج (SDK) العادي للتنقّل. لا يزال من الممكن إخفاء الخدمات الأخرى التي تعمل في المقدّمة في التطبيق خلف هذا الإشعار. تحدّد المَعلمة notificationId معرّف الإشعار الذي يجب استخدامه للإشعار. إذا كانت القيمة فارغة، يتم استخدام قيمة عشوائية. يمكنك ضبطه بشكل صريح لتجنُّب التعارض مع الإشعارات الأخرى، مثل تلك الواردة من حزمة تطوير برامج (SDK) أخرى. ‫defaultMessage هو سلسلة يتم عرضها عندما لا يكون النظام في وضع التنقّل. ‫resumeIntent هو هدف يتم تنفيذه عند النقر على الإشعار. إذا كانت قيمة resumeIntent فارغة، يتم تجاهل النقرات على الإشعار.

المَعلمات الثلاث لـ "initForegroundServiceManagerProvider()" هي application وnotificationId وnotificationProvider. إذا كانت آخر مَعلمتَين فارغتَين، يكون الإشعار هو الإشعار العادي في حزمة تطوير البرامج (SDK) للتنقّل. تحدّد المَعلمة notificationId معرّف الإشعار الذي يجب استخدامه للإشعار. وإذا كانت القيمة فارغة، يتم استخدام قيمة عشوائية. يمكنك ضبطه بشكل صريح لتجنُّب التعارض مع الإشعارات الأخرى، مثل تلك الواردة من حزمة تطوير برامج (SDK) أخرى. إذا تم ضبط notificationProvider، يكون مقدّم الخدمة مسؤولاً دائمًا عن إنشاء الإشعار الذي سيتم عرضه.

تُنتج طريقة getForegroundServiceManager() في حزمة تطوير البرامج (SDK) للتنقّل الخدمة الفردية لإدارة الخدمات التي تعمل في المقدّمة. إذا لم يسبق لك إنشاء واحد، فهذا يعادل استدعاء initForegroundServiceManagerMessageAndIntent() باستخدام مَعلمات فارغة لـ notificationId وdefaultMessage وresumeIntent.

تتضمّن واجهة برمجة التطبيقات ForegroundServiceManager ثلاث طرق بسيطة. الأولان مخصصان لنقل الخدمة إلى المقدّمة وخارجها، ويتم استدعاؤهما عادةً من داخل الخدمة التي تم إنشاؤها. يضمن استخدام هذه الطرق ربط الخدمات بالإشعار الثابت المشترك. الطريقة الأخيرة، updateNotification()، تضع علامة على المدير بأن الإشعار قد تغير، ويجب إعادة عرضه.

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

سيناريوهات الاستخدام

يوضّح هذا القسم سيناريوهات استخدام الإشعارات المستمرة المشتركة.

إخفاء الإشعارات المستمرة للخدمات التي تعمل في المقدّمة في التطبيقات الأخرى
أسهل سيناريو هو الحفاظ على السلوك الحالي، واستخدام الإشعار المستمر فقط لعرض معلومات Navigation SDK. يمكن للخدمات الأخرى الاختباء خلف هذا الإشعار باستخدام طريقتَي startForeground() وstopForeground() في مدير الخدمات التي تعمل في المقدّمة.
إخفاء الإشعارات المستمرة للخدمات الأخرى التي تعمل في المقدّمة، ولكن يجب ضبط النص التلقائي الذي يظهر في حال عدم التنقّل
السيناريو الثاني الأسهل هو الحفاظ على السلوك الحالي، واستخدام الإشعار المستمر فقط لعرض معلومات حزمة تطوير البرامج (SDK) الخاصة بالتنقّل، باستثناء الحالات التي لا يكون فيها النظام في وضع التنقّل. عندما لا يكون النظام في وضع التنقّل، يتم عرض السلسلة المقدَّمة إلى initForegroundServiceManagerMessageAndIntent() بدلاً من سلسلة Navigation 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، يمكنك ربط حزمة تطوير البرامج (SDK) للتنقّل بها باستخدام الرمز التالي:

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

التحذيرات والخطط المستقبلية

  • يُرجى الاتصال بالرقم initForegroundServiceManagerMessageAndIntent() أو initForegroundServiceManagerProvider() مبكرًا حتى يتم تحديد سيناريو الاستخدام المتوقّع بشكل جيد. يجب استدعاء هذه الطريقة قبل إنشاء Navigator جديد.
  • احرص على رصد الاستثناءات من طلبات initForegroundServiceManagerMessageAndIntent() أو initForegroundServiceManagerProvider() في حال إدخال مسار الرمز أكثر من مرة. في الإصدار 2.0 من حزمة تطوير البرامج (SDK) الخاصة بالتنقّل، يؤدي استدعاء هذه الطريقة عدة مرات إلى ظهور استثناء تم التحقّق منه بدلاً من استثناء وقت التشغيل.
  • قد لا يزال لدى Google عمل يتعيّن عليها القيام به للحصول على نمط متسق على مدار عمر الإشعار الذي يتطابق مع نمط العنوان.
  • عند تحديد مقدّم إشعارات، يمكنك التحكّم في سلوك الإشعارات العاجلة باستخدام الأولوية.
  • لا توفّر Google وسيلة بسيطة لاسترداد معلومات الاتجاهات المفصّلة التي قد يُدرجها مقدّم الإشعارات في الإشعار.