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