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

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

تحتوي حزمة تطوير البرامج (SDK) الخاصة بخدمة "التنقّل" على طرق ثابتة لتهيئة والحصول على ForegroundServiceManager singleton. لا يمكن تهيئة هذا العنصر إلا مرة واحدة خلال مدة استخدام حزمة Navigation SDK. نتيجةً لذلك، إذا كنت تستخدم إحدى عمليات استدعاء التهيئة (initForegroundServiceManagerMessageAndIntent() أو initForegroundServiceManagerProvider())، عليك تضمينها في كتلة try-catch في حال إعادة إدخال هذا المسار. تعرض حزمة تطوير البرامج (SDK) الخاصة بخدمة Navigation استثناء وقت التشغيل إذا استدعيت أيًا من الطريقتين أكثر من مرة ما لم تمحُ أولاً جميع المراجع إلى ForegroundServiceManager وتستدعي clearForegroundServiceManager() قبل كل استدعاء لاحق.
المَعلمات الأربع لـ initForegroundServiceManagerMessageAndIntent() هي application وnotificationId وdefaultMessage وresumeIntent. إذا كانت المَعلمات الثلاث الأخيرة فارغة، يكون الإشعار هو إشعار Navigation SDK العادي. سيظل بإمكانك إخفاء الخدمات الأخرى التي تعمل في المقدّمة داخل التطبيق خلف هذا الإشعار. تحدّد المَعلمة notificationId رقم تعريف الإشعار الذي يجب استخدامه للإشعار. إذا كانت القيمة فارغة، سيتم استخدام قيمة عشوائية. يمكنك ضبطه بشكل صريح لتجنُّب التعارضات مع الإشعارات الأخرى، مثل الإشعارات الواردة من حزمة تطوير برامج أخرى. defaultMessage هي سلسلة يتم عرضها عندما لا يكون النظام في وضع التنقّل. resumeIntent هو هدف يتم تنشيطه عند النقر على الإشعار. إذا كانت قيمة resumeIntent فارغة، سيتم تجاهل النقرات على الإشعار.
المَعلمات الثلاث الخاصة بـ initForegroundServiceManagerProvider() هي application وnotificationId وnotificationProvider. إذا كانت المَعلمتان الأخيرتان فارغتين، يكون الإشعار هو إشعار Navigation 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(). يمنحك هذا الخيار تحكّمًا كاملاً في المحتوى الذي يتم عرضه في الإشعار، ولكنّه يؤدي أيضًا إلى فصل معلومات إشعار Navigation 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) الخاصة بخدمة Navigation API بها باستخدام الرمز التالي:
ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);
القيود والخطط المستقبلية
- احرص على طلب
initForegroundServiceManagerMessageAndIntent()أوinitForegroundServiceManagerProvider()في وقت مبكر حتى يكون سيناريو الاستخدام المتوقّع محدّدًا بشكل جيد. يجب استدعاء هذه الطريقة قبل إنشاء عنصر Navigator جديد. - احرص على رصد الاستثناءات من طلبات البيانات إلى
initForegroundServiceManagerMessageAndIntent()أوinitForegroundServiceManagerProvider()في حال تم إدخال مسار الرمز البرمجي أكثر من مرة. في الإصدار 2.0 من Navigation SDK، يؤدي استدعاء هذه الطريقة عدة مرات إلى ظهور استثناء تم التحقّق منه بدلاً من استثناء وقت التشغيل. - قد تحتاج Google إلى بعض الوقت لتوفير تنسيق متّسق للإشعار طوال مدة عرضه، على أن يتطابق هذا التنسيق مع تنسيق العنوان.
- عند تحديد موفّر إشعارات، يمكنك التحكّم في سلوك الإشعارات المنبثقة باستخدام الأولوية.
- لا توفّر Google طريقة بسيطة لاسترداد المعلومات الخاصة بالاتّجاهات المفصّلة التي قد يدرجها موفّر الإشعارات في الإشعار.