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