ادغام اعلان‌های تلفن همراه

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

این مشکل زمانی چالش‌برانگیزتر می‌شود که از کیت‌های توسعه نرم‌افزاری مثل Navigation SDK استفاده کنید که سرویس‌های پیش‌زمینه‌ای را مستقل از برنامه‌ای که اعلان‌های دائمی مستقل خود را دارد اجرا می‌کنند و ادغام آن‌ها را دشوار می‌سازد. برای رفع این مشکلات، Navigation SDK نسخه ۱.۱۱ یک API ساده معرفی کرد تا به مدیریت اعلان‌های دائمی در سراسر برنامه، ازجمله در SDK، کمک کند.

ادغام اعلان‌های دائمی

اجزا

مدیر سرویس پیش‌زمینه‌ای پوششی را برای کلاس سرویس پیش‌زمینه‌ای Android و کلاس اعلان دائم فراهم می‌کند. عملکرد اصلی این پوشاننده، اجباری کردن استفاده مجدد از «شناسه اعلان» است تا اعلان در همه سرویس‌های پیش‌زمینه‌ای که از مدیر استفاده می‌کنند هم‌رسانی شود.


‫Navigation SDK حاوی روش‌های ثابتی برای مقداردهی اولیه و دریافت ForegroundServiceManager singleton است. این سینگلتون فقط یک‌بار در طول عمر Navigation SDK می‌تواند مقداردهی اولیه شود. درنتیجه، اگر از یکی از فراخوانی‌های مقداردهی اولیه (initForegroundServiceManagerMessageAndIntent() یا initForegroundServiceManagerProvider()) استفاده می‌کنید، باید آن را با یک بلوک try-catch احاطه کنید تا درصورت ورود مجدد به آن مسیر، خطاها مدیریت شوند. اگر هریک از این روش‌ها را بیش‌از یک بار فراخوانی کنید، Navigation SDK استثنای زمان اجرا ایجاد می‌کند، مگراینکه ابتدا همه ارجاع‌ها به ForegroundServiceManager را پاک کنید و قبل‌از هر فراخوانی بعدی، clearForegroundServiceManager() را فراخوانی کنید.

چهار پارامتر initForegroundServiceManagerMessageAndIntent() عبارت‌اند از application،‏ notificationId،‏ defaultMessage، و resumeIntent. اگر سه پارامتر آخر تهی باشند، اعلان همان اعلان استاندارد Navigation SDK است. هنوز هم می‌توان سایر سرویس‌های پیش‌زمینه‌ای را در برنامه پشت این اعلان پنهان کرد. پارامتر notificationId شناسه اعلانی را که باید برای اعلان استفاده شود مشخص می‌کند. اگر null باشد، از مقدار دلخواه استفاده می‌شود. می‌توانید آن را به‌طور صریح تنظیم کنید تا تداخل با اعلان‌های دیگر، مانند اعلان‌های کیت توسعه نرم‌افزار دیگر، را دور بزند. defaultMessage رشته‌ای است که وقتی سیستم درحال پیمایش نیست نمایش داده می‌شود. resumeIntent قصدی است که وقتی روی اعلان کلیک می‌شود، اجرا می‌شود. اگر resumeIntent تهی باشد، کلیک‌ها روی اعلان نادیده گرفته می‌شود.

سه پارامتر initForegroundServiceManagerProvider() عبارتند از application، notificationId، و notificationProvider. اگر دو پارامتر نهایی تهی باشند، اعلان همان اعلان استاندارد Navigation SDK است. پارامتر notificationId شناسه اعلانی را مشخص می‌کند که باید برای اعلان استفاده شود. اگر تهی باشد، از مقدار دلخواه استفاده می‌شود. می‌توانید آن را به‌طور صریح تنظیم کنید تا تداخل با سایر اعلان‌ها، مانند اعلان‌های کیت توسعه نرم‌افزار دیگر، را برطرف کند. اگر notificationProvider تنظیم شده باشد، ارائه‌دهنده همیشه مسئول تولید اعلانی است که باید ارائه شود.

روش getForegroundServiceManager() کیت توسعه نرم‌افزار پیمایش، مدیر سرویس پیش‌زمینه‌ای سینگلتون را برمی‌گرداند. اگر هنوز آن را تولید نکرده‌اید، معادل فراخوانی initForegroundServiceManagerMessageAndIntent() با پارامترهای تهی برای notificationId، defaultMessage، و resumeIntent است.

‫ForegroundServiceManager سه روش ساده دارد. دو مورد اول برای انتقال سرویس به پیش‌نما و خارج کردن آن از پیش‌نما هستند و معمولاً از داخل سرویسی که ایجاد شده است فراخوانی می‌شوند. استفاده از این روش‌ها تضمین می‌کند که سرویس‌ها با اعلان دائمی مشترک مرتبط هستند. روش نهایی، updateNotification()، به مدیر اطلاع می‌دهد که اعلان تغییر کرده است و باید دوباره ارائه شود.

اگر به کنترل کامل اعلان همیشگی هم‌رسانی‌شده نیاز دارید، میانای برنامه‌سازی کاربردی یک میانای NotificationContentProvider برای تعریف ارائه‌دهنده اعلان ارائه می‌دهد که حاوی یک روش برای دریافت اعلان با محتوای فعلی است. همچنین یک کلاس پایه ارائه می‌دهد که می‌توانید به‌صورت اختیاری از آن برای کمک به تعریف ارائه‌دهنده استفاده کنید. یکی از اهداف اصلی کلاس پایه این است که روشی برای فراخوانی updateNotification() بدون نیاز به دسترسی به ForegroundServiceManager ارائه می‌دهد. اگر از نمونه‌ای از ارائه‌دهنده اعلان برای دریافت پیام‌های اعلان جدید استفاده می‌کنید، می‌توانید این روش داخلی را مستقیماً برای ارائه پیام در اعلان فراخوانی کنید.

سناریوهای استفاده

این بخش سناریوهای استفاده از اعلان‌های ماندگار هم‌رسانی‌شده را به‌طور دقیق شرح می‌دهد.

پنهان کردن اعلان‌های دائمی سرویس‌های پیش‌زمینه‌ای برنامه‌های دیگر
ساده‌ترین سناریو حفظ رفتار فعلی و استفاده از اعلان دائمی فقط برای ارائه اطلاعات Navigation SDK است. سرویس‌های دیگر می‌توانند بااستفاده از روش‌های startForeground() و stopForeground() مدیر سرویس پیش‌زمینه‌ای پشت این اعلان پنهان شوند.
اعلان‌های دائمی سرویس‌های پیش‌زمینه برنامه دیگر را پنهان کنید، اما نوشتار پیش‌فرض را برای نمایش در زمانی که ناوبری نمی‌کنید تنظیم کنید
دومین سناریو آسان حفظ رفتار فعلی است و فقط از اعلان دائمی برای ارائه اطلاعات Navigation SDK استفاده می‌شود، به‌جز زمانی که سیستم درحال پیمایش نیست. وقتی سیستم درحال پیمایش نیست، رشته ارائه‌شده به initForegroundServiceManagerMessageAndIntent() به‌جای رشته پیش‌فرض Navigation SDK که به «Google Maps» اشاره می‌کند نمایش داده می‌شود. همچنین می‌توانید از این فراخوانی برای تنظیم هدف ازسرگیری که هنگام کلیک کردن روی اعلان فعال می‌شود استفاده کنید.
کنترل کامل پردازش اعلان دائمی را دردست بگیرید
سناریو نهایی مستلزم تعریف و ایجاد ارائه‌دهنده اعلان و ارسال آن به 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، بااستفاده از کد زیر، کیت توسعه نرم‌افزار پیمایش را به آن متصل می‌کنید:

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

هشدارها و برنامه‌های آینده

  • حتماً initForegroundServiceManagerMessageAndIntent() یا initForegroundServiceManagerProvider() را زودتر فراخوانی کنید تا سناریوی استفاده موردانتظار به‌خوبی تعریف شود. باید این روش را قبل‌از ایجاد «راه‌بر» جدید فراخوانی کنید.
  • حتماً استثناهای تماس با initForegroundServiceManagerMessageAndIntent() یا initForegroundServiceManagerProvider() را درصورتی‌که مسیر کد بیش‌از یک بار وارد شده باشد، دریافت کنید. در Navigation SDK نسخه ۲.۰، فراخوانی این روش به‌دفعات، به‌جای استثنای زمان اجرا، استثنای بررسی‌شده ایجاد می‌کند.
  • Google still might have work to do to get consistent styling over the lifetime of the notification that matches the header styling.
  • وقتی ارائه‌دهنده اعلان را تعریف می‌کنید، می‌توانید رفتار اعلان‌های گذرا را با اولویت کنترل کنید.
  • Google روش ساده‌ای برای بازیابی اطلاعات گام‌به‌گام که ممکن است ارائه‌دهنده اعلان در اعلان درج کند ارائه نمی‌دهد.