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

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

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

تجميع الإشعارات الثابتة

المكونات

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


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

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

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

تعرض طريقة getForegroundServiceManager() في Navigation SDK العنصر الفردي لمدير خدمات المقدّمة. إذا لم تكن قد أنشأت مثيلًا بعد، فإنّه يعادل استدعاء initForegroundServiceManagerMessageAndIntent() مع مَعلمات فارغة للعناصر notificationId وdefaultMessage و resumeIntent.

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

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

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

يوضّح هذا القسم بالتفصيل سيناريوهات استخدام رسائل التنبيه الدائمة المشترَكة.

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

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

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

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