از سطح ۲۶ رابط برنامهنویسی اندروید (Android API) به بعد، اعلانهای مداوم برای سرویسهای پیشزمینه الزامی هستند. این الزام به منظور جلوگیری از پنهان کردن سرویسهایی است که ممکن است تقاضای بیش از حد از منابع سیستم، از جمله باتری، را ایجاد کنند. این الزام یک مشکل بالقوه ایجاد میکند: اگر برنامهای با چندین سرویس پیشزمینه، اعلانها را به دقت مدیریت نکند تا در همه سرویسها به اشتراک گذاشته شوند، ممکن است چندین اعلان مداوم غیرقابل رد شدن وجود داشته باشد که منجر به شلوغی ناخواسته در لیست فعال اعلانها میشود.
این مشکل زمانی چالشبرانگیزتر میشود که از SDKهایی مانند Navigation SDK استفاده میکنید که سرویسهای پیشزمینه را مستقل از برنامه اجرا میکنند و اعلانهای دائمی مستقل خود را دارند و تجمیع آنها را دشوار میکنند. برای رفع این مشکلات، Navigation SDK نسخه ۱.۱۱ یک API ساده برای کمک به مدیریت اعلانهای دائمی در سراسر برنامه، از جمله درون SDK، معرفی کرده است.

قطعات
مدیر سرویس پیشزمینه، یک پوشش (wrapper) پیرامون کلاس سرویس پیشزمینه اندروید و کلاس اعلان پایدار (persistent notification) فراهم میکند. وظیفه اصلی این پوشش، اعمال استفاده مجدد از شناسه اعلان (Notification ID) است، به طوری که اعلان در تمام سرویسهای پیشزمینه که از مدیر استفاده میکنند، به اشتراک گذاشته شود.

کیت توسعه نرمافزار ناوبری (Navigation SDK) شامل متدهای استاتیک برای مقداردهی اولیه و دریافت تکلایه ForegroundServiceManager است. این تکلایه فقط میتواند یک بار در طول عمر کیت توسعه نرمافزار ناوبری مقداردهی اولیه شود. در نتیجه، اگر از یکی از فراخوانیهای مقداردهی اولیه ( initForegroundServiceManagerMessageAndIntent() یا initForegroundServiceManagerProvider() ) استفاده کنید، باید آن را با یک بلوک try-catch احاطه کنید تا در صورت ورود مجدد آن مسیر، با مشکل مواجه نشوید. کیت توسعه نرمافزار ناوبری (Navigation SDK) در صورت فراخوانی بیش از یک بار هر یک از متدها، یک خطای زمان اجرا ایجاد میکند، مگر اینکه ابتدا تمام ارجاعات به ForegroundServiceManager را پاک کرده و قبل از هر فراخوانی بعدی، clearForegroundServiceManager() را فراخوانی کنید.
چهار پارامتر initForegroundServiceManagerMessageAndIntent() عبارتند از application ، notificationId ، defaultMessage و resumeIntent . اگر سه پارامتر آخر null باشند، اعلان، اعلان استاندارد Navigation SDK است. همچنان میتوان سایر سرویسهای پیشزمینه را در برنامه پشت این اعلان پنهان کرد. پارامتر notificationId شناسه اعلانی را که باید برای اعلان استفاده شود، مشخص میکند. اگر null باشد، از یک مقدار دلخواه استفاده میشود. میتوانید آن را به طور صریح تنظیم کنید تا در صورت تداخل با سایر اعلانها، مانند اعلانهای SDK دیگر، تداخل ایجاد نکند. defaultMessage رشتهای است که وقتی سیستم در حال پیمایش نیست نمایش داده میشود. resumeIntent یک intent است که هنگام کلیک روی اعلان اجرا میشود. اگر resumeIntent null باشد، کلیک روی اعلان نادیده گرفته میشود.
سه پارامتر initForegroundServiceManagerProvider() عبارتند از application ، notificationId و notificationProvider . اگر دو پارامتر آخر null باشند، اعلان، اعلان استاندارد Navigation SDK است. پارامتر notificationId شناسه اعلانی را که باید برای اعلان استفاده شود، مشخص میکند. اگر null باشد، از یک مقدار دلخواه استفاده میشود. میتوانید آن را به طور صریح تنظیم کنید تا تداخل با اعلانهای دیگر، مانند اعلانهای SDK دیگر، را برطرف کند. اگر notificationProvider تنظیم شده باشد، ارائه دهنده همیشه مسئول تولید اعلانی است که باید رندر شود.
متد getForegroundServiceManager() در کیت توسعهی ناوبری (Navigation SDK) یک singleton از مدیریت سرویس پیشزمینه (foreground service manager) را برمیگرداند. اگر هنوز یکی ایجاد نکردهاید، معادل فراخوانی initForegroundServiceManagerMessageAndIntent() با پارامترهای null برای notificationId ، defaultMessage و resumeIntent است.
ForegroundServiceManager سه متد ساده دارد. دو متد اول برای انتقال یک سرویس به داخل و خارج از پیشزمینه هستند و معمولاً از داخل سرویسی که ایجاد شده است فراخوانی میشوند. استفاده از این متدها تضمین میکند که سرویسها با اعلان پایدار مشترک مرتبط هستند. متد آخر، updateNotification() ، به مدیر اعلام میکند که اعلان تغییر کرده است و باید دوباره رندر شود.
اگر به کنترل کامل اعلان پایدار مشترک نیاز دارید، API یک رابط NotificationContentProvider برای تعریف یک ارائهدهنده اعلان ارائه میدهد که شامل یک متد واحد برای دریافت اعلان با محتوای فعلی است. همچنین یک کلاس پایه ارائه میدهد که میتوانید به صورت اختیاری برای کمک به تعریف ارائهدهنده از آن استفاده کنید. یکی از اهداف اصلی کلاس پایه این است که راهی برای فراخوانی updateNotification() بدون نیاز به دسترسی به ForegroundServiceManager فراهم میکند. اگر از نمونهای از ارائهدهنده اعلان برای دریافت پیامهای اعلان جدید استفاده میکنید، میتوانید این متد داخلی را مستقیماً برای رندر کردن پیام در اعلان فراخوانی کنید.
سناریوهای استفاده
این بخش جزئیات سناریوهای استفاده از اعلانهای مداوم مشترک را شرح میدهد.
- اعلانهای مداوم سایر سرویسهای پیشزمینه برنامه را پنهان کنید
- سادهترین سناریو این است که رفتار فعلی را حفظ کنیم و فقط از اعلانهای دائمی برای رندر کردن اطلاعات Navigation SDK استفاده کنیم. سایر سرویسها میتوانند با استفاده از متدهای
startForeground()وstopForeground()در مدیریت سرویس پیشزمینه، پشت این اعلانها پنهان شوند. - اعلانهای مداوم سایر سرویسهای پیشزمینه برنامه را پنهان کنید، اما متن پیشفرض را برای نمایش در هنگام عدم پیمایش تنظیم کنید
- دومین سناریوی ساده، حفظ رفتار فعلی و استفاده از اعلان پایدار فقط برای رندر کردن اطلاعات Navigation SDK است، مگر زمانی که سیستم در حال پیمایش نباشد. وقتی سیستم در حال پیمایش نیست، رشتهای که به
initForegroundServiceManagerMessageAndIntent()ارائه میشود، به جای رشته پیشفرض Navigation SDK که به "Google Maps" اشاره دارد، نمایش داده میشود. همچنین میتوانید از این فراخوانی برای تنظیم قصد از سرگیری که هنگام کلیک روی اعلان اجرا میشود، استفاده کنید. - کنترل کامل رندر کردن اعلانهای مداوم را در دست بگیرید
- سناریوی آخر نیاز به تعریف و ایجاد یک ارائهدهنده اعلان و ارسال آن به
ForegroundServiceManagerبا استفاده ازinitForegroundServiceManagerProvider()دارد. این گزینه به شما کنترل کامل آنچه در اعلان ارائه میشود را میدهد، اما همچنین اطلاعات اعلان Navigation SDK را از اعلان جدا میکند و در نتیجه، پیامهای مفید گام به گام نشان داده شده در اعلان را حذف میکند. گوگل روش سادهای برای بازیابی این اطلاعات و درج آن در اعلان ارائه نمیدهد.
ارائه دهنده اعلان نمونه
مثال کد زیر نحوه ایجاد و بازگرداندن اعلانها را با استفاده از یک ارائهدهنده محتوای اعلان ساده نشان میدهد.
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()را در مراحل اولیه فراخوانی کنید تا سناریوی استفاده مورد انتظار به خوبی تعریف شده باشد. شما باید این متد را قبل از ایجاد یک Navigator جدید فراخوانی کنید. - در صورتی که مسیر کد بیش از یک بار وارد شود، حتماً استثنائات ناشی از فراخوانیهای
initForegroundServiceManagerMessageAndIntent()یاinitForegroundServiceManagerProvider()را دریافت کنید. در Navigation SDK نسخه ۲.۰، فراخوانی چندین باره این متد، به جای استثنای زمان اجرا، یک استثنای بررسیشده (checked exception) ایجاد میکند. - گوگل هنوز ممکن است برای ایجاد یک ظاهر طراحیشدهی ثابت در طول عمر اعلان که با ظاهر طراحیشدهی هدر مطابقت داشته باشد، نیاز به کار داشته باشد.
- وقتی یک ارائهدهنده اعلان تعریف میکنید، میتوانید رفتار هشداردهنده را با اولویت کنترل کنید.
- گوگل ابزار سادهای برای بازیابی اطلاعات گام به گام که یک ارائهدهنده اعلان ممکن است در اعلان درج کند، ارائه نمیدهد.