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

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

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

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

المكونات

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


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

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

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

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

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

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

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

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

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