ตั้งแต่ Android API ระดับ 26 เป็นต้นไป จะต้องมีการแจ้งเตือนอย่างต่อเนื่องสำหรับบริการที่ทำงานอยู่เบื้องหน้า ข้อกำหนดนี้มีไว้เพื่อป้องกันไม่ให้คุณซ่อนบริการที่อาจใช้ทรัพยากรระบบมากเกินไป ซึ่งรวมถึงแบตเตอรี่ ข้อกำหนดนี้อาจก่อให้เกิดปัญหาขึ้น ถ้าแอปที่มีบริการที่ทำงานอยู่เบื้องหน้าหลายแอปไม่ได้จัดการการแจ้งเตือนอย่างรอบคอบจนทำให้แชร์กับบริการทั้งหมด อาจมีการแจ้งเตือนที่ปิดไม่ได้ถาวรหลายรายการ ทำให้รายการการแจ้งเตือนที่ใช้งานอยู่ดูรกรุงรัง
ปัญหานี้จะยิ่งท้าทายมากขึ้นเมื่อคุณใช้ SDK เช่น Navigation SDK ซึ่งเรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยไม่ขึ้นอยู่กับแอปที่มีการแจ้งเตือนถาวรเป็นของตนเอง ทำให้รวมได้ยาก
เพื่อแก้ไขปัญหาเหล่านี้ Navigation SDK v1.11 ได้เปิดตัว API แบบง่ายเพื่อช่วยจัดการการแจ้งเตือนถาวรในแอป ซึ่งรวมถึงภายใน SDK
คอมโพเนนต์
ตัวจัดการบริการที่ทำงานอยู่เบื้องหน้ามี Wrapper สำหรับคลาสบริการที่ทำงานอยู่เบื้องหน้าของ Android และคลาสการแจ้งเตือนถาวร หน้าที่หลักของ Wrapper นี้คือการบังคับใช้รหัสการแจ้งเตือนซ้ำเพื่อให้แชร์การแจ้งเตือนในบริการที่ทำงานอยู่เบื้องหน้าทั้งหมดที่ใช้ตัวจัดการ
Navigation SDK มีวิธีแบบคงที่สำหรับการเริ่มต้นและรับซิงเกิล ForegroundServiceManager
ซิงเกิลตันนี้จะเริ่มต้นได้เพียงครั้งเดียวตลอดอายุการใช้งานของ Navigation SDK ดังนั้น หากใช้การเรียกเริ่มต้นรายการใดรายการหนึ่ง (initForegroundServiceManagerMessageAndIntent()
หรือ initForegroundServiceManagerProvider()
) คุณก็ควรล้อมรอบด้วยการบล็อก ให้ลองจับเผื่อไว้ในกรณีที่มีการป้อนเส้นทางอีกครั้ง Navigation SDK จะส่งข้อยกเว้นรันไทม์หากคุณเรียกใช้เมธอดใดเมธอดหนึ่งมากกว่า 1 ครั้ง เว้นแต่คุณจะล้างการอ้างอิงไปยัง ForegroundServiceManager
และการเรียกใช้ clearForegroundServiceManager()
ทั้งหมดก่อนการเรียกครั้งต่อไปแต่ละครั้ง
พารามิเตอร์ 4 ตัวของ initForegroundServiceManagerMessageAndIntent()
คือ application
, notificationId
, defaultMessage
และ resumeIntent
หากพารามิเตอร์ 3 รายการสุดท้ายเป็น Null การแจ้งเตือนจะเป็นการแจ้งเตือน
Navigation SDK มาตรฐาน คุณยังคงสามารถซ่อนบริการที่ทำงานอยู่เบื้องหน้าอื่นๆ
ในแอปหลังการแจ้งเตือนนี้ได้ พารามิเตอร์ notificationId
จะระบุรหัสการแจ้งเตือนที่ควรใช้สำหรับการแจ้งเตือน หากเป็นค่าว่าง ระบบจะใช้ค่าที่กำหนดเอง คุณสามารถตั้งค่าแบบเจาะจงเพื่อหลีกเลี่ยงข้อขัดแย้งกับการแจ้งเตือนอื่นๆ เช่น การแจ้งเตือนจาก SDK อื่น โดย defaultMessage
เป็นสตริงที่แสดงเมื่อระบบไม่ได้ไปยังส่วนต่างๆ resumeIntent
คือ Intent ที่เริ่มทำงานเมื่อมีการคลิกการแจ้งเตือน หาก resumeIntent
เป็นค่าว่าง ระบบจะไม่สนใจการคลิกที่การแจ้งเตือนนั้น
พารามิเตอร์ 3 ตัวของ initForegroundServiceManagerProvider()
คือ application
, notificationId
และ notificationProvider
หากพารามิเตอร์ 2 รายการสุดท้ายเป็น Null การแจ้งเตือนจะเป็นการแจ้งเตือน Navigation SDK แบบมาตรฐาน พารามิเตอร์ notificationId
จะระบุรหัสการแจ้งเตือนที่ควรใช้สำหรับการแจ้งเตือน หากเป็นค่าว่าง ระบบจะใช้ค่าที่กำหนดเอง คุณตั้งค่าอย่างชัดแจ้งเพื่อป้องกันความขัดแย้งกับการแจ้งเตือนอื่นๆ ได้ เช่น การแจ้งเตือนจาก SDK อื่น หากตั้งค่า notificationProvider
แล้ว ผู้ให้บริการจะเป็นผู้รับผิดชอบในการสร้างการแจ้งเตือนเพื่อให้แสดงผลเสมอ
เมธอด Navigation SDK getForegroundServiceManager()
จะแสดงผล Singleton สำหรับตัวจัดการบริการที่ทำงานอยู่เบื้องหน้า หากยังไม่ได้สร้างพารามิเตอร์ดังกล่าว ก็เทียบเท่ากับการเรียกใช้ initForegroundServiceManagerMessageAndIntent()
ด้วยพารามิเตอร์ Null สําหรับ notificationId
, defaultMessage
และ resumeIntent
ForegroundServiceManager
มี 3 วิธีการง่ายๆ 2 ประเภทแรกมีไว้สำหรับการย้ายบริการเข้าและออกจากเบื้องหน้า และมักเรียกใช้จากภายในบริการที่สร้างขึ้น การใช้วิธีการเหล่านี้ช่วยให้มั่นใจว่าบริการเชื่อมโยงกับการแจ้งเตือนถาวรที่แชร์ไว้ วิธีสุดท้ายคือ updateNotification()
จะแจ้งผู้จัดการว่ามีการเปลี่ยนแปลงการแจ้งเตือนแล้ว และควรแสดงผลอีกครั้ง
หากต้องการควบคุมการแจ้งเตือนถาวรที่แชร์อย่างสมบูรณ์ API จะมีอินเทอร์เฟซ NotificationContentProvider
สำหรับกำหนดผู้ให้บริการการแจ้งเตือน ซึ่งมีวิธีรับการแจ้งเตือนเกี่ยวกับเนื้อหาปัจจุบันด้วยวิธีการเดียว นอกจากนี้ยังมีคลาสพื้นฐาน ซึ่งคุณสามารถเลือกใช้เพื่อช่วยกำหนดผู้ให้บริการ จุดประสงค์หลักอย่างหนึ่งของคลาสพื้นฐานคือให้วิธีเรียกใช้ updateNotification()
โดยไม่ต้องเข้าถึง ForegroundServiceManager
หากคุณใช้อินสแตนซ์ของผู้ให้บริการการแจ้งเตือนเพื่อรับข้อความแจ้งเตือนใหม่ คุณจะเรียกใช้วิธีการภายในนี้ได้โดยตรงเพื่อแสดงข้อความในการแจ้งเตือน
สถานการณ์การใช้งาน
ส่วนนี้จะอธิบายถึงสถานการณ์การใช้งานต่างๆ ในการใช้การแจ้งเตือนถาวรที่แชร์
- ซ่อนการแจ้งเตือนถาวรของบริการที่ทำงานอยู่เบื้องหน้าอื่นๆ ของแอป
- สถานการณ์ที่ง่ายที่สุดคือการรักษาลักษณะการทำงานปัจจุบันไว้ และใช้เฉพาะการแจ้งเตือนแบบถาวรสำหรับแสดงผลข้อมูล Navigation SDK บริการอื่นๆ จะซ่อนอยู่หลังการแจ้งเตือนนี้ได้โดยใช้เมธอด
startForeground()
และstopForeground()
ของตัวจัดการบริการที่ทำงานอยู่เบื้องหน้า - ซ่อนการแจ้งเตือนตลอดเวลาของบริการที่ทำงานอยู่เบื้องหน้าอื่นๆ ของแอป แต่ตั้งค่าข้อความเริ่มต้นที่แสดงเมื่อไม่มีการนำทาง
- สถานการณ์ที่ 2 ที่ง่ายที่สุดคือการรักษาลักษณะการทำงานปัจจุบันไว้ และใช้การแจ้งเตือนตลอดเวลาเพื่อแสดงข้อมูล Navigation SDK เท่านั้น ยกเว้นในกรณีที่ระบบไม่ได้นำทาง เมื่อระบบไม่ได้นำทาง สตริงที่ส่งไปยัง
initForegroundServiceManagerMessageAndIntent()
จะแสดงแทนสตริงการนำทาง SDK เริ่มต้นที่กล่าวถึง "Google Maps" คุณยังใช้การเรียกนี้เพื่อกำหนด Intent การกลับมาทำงานอีกครั้งที่เริ่มทำงานเมื่อมีการคลิกการแจ้งเตือนได้ด้วย - ควบคุมการแสดงผลของการแจ้งเตือนถาวรได้อย่างเต็มที่
- สถานการณ์สุดท้ายต้องมีการกำหนดและสร้างผู้ให้บริการการแจ้งเตือน แล้วส่งไปยัง
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 การนำทางเข้ากับ SDK นี้โดยใช้โค้ดต่อไปนี้
ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);
ข้อควรระวังและแผนการในอนาคต
- โปรดเรียกใช้
initForegroundServiceManagerMessageAndIntent()
หรือinitForegroundServiceManagerProvider()
ตั้งแต่เนิ่นๆ เพื่อกำหนดสถานการณ์การใช้งานที่คาดไว้เป็นอย่างดี คุณต้องเรียกใช้เมธอดนี้ก่อนที่จะสร้าง Navigator ใหม่ - อย่าลืมหาข้อยกเว้นจากการเรียกใช้ไปยัง
initForegroundServiceManagerMessageAndIntent()
หรือinitForegroundServiceManagerProvider()
ในกรณีที่มีการป้อนเส้นทางโค้ดมากกว่า 1 ครั้ง ใน Navigation SDK v2.0 การเรียกใช้เมธอดนี้หลายครั้งจะทำให้เกิดข้อยกเว้นที่ทำเครื่องหมายแล้วแทนที่จะเป็นข้อยกเว้นรันไทม์ - Google ยังอาจมีงานที่ต้องทำอีกเพื่อจัดรูปแบบให้สอดคล้องกันตลอดอายุของการแจ้งเตือนที่ตรงกับการจัดรูปแบบส่วนหัว
- เมื่อกำหนดผู้ให้บริการการแจ้งเตือน คุณจะควบคุมพฤติกรรมการแจ้งเตือนด้วยลำดับความสำคัญได้
- Google ไม่มีวิธีการง่ายๆ ในการดึงข้อมูลแบบเลี้ยวต่อเลี้ยวที่ผู้ให้บริการการแจ้งเตือนอาจแทรกในการแจ้งเตือน