การเปิดใช้บริการที่ทำงานอยู่เบื้องหน้าจากแอปมี 2 ขั้นตอน ขั้นแรก คุณ
ต้องเริ่มบริการโดยเรียก
context.startForegroundService() จากนั้นให้บริการเรียก ServiceCompat.startForeground() เพื่อเลื่อนระดับเป็นบริการที่ทำงานอยู่เบื้องหน้า
สิ่งที่ต้องมีก่อน
แอปอาจมีข้อจำกัดในการเปิดใช้บริการที่ทำงานอยู่เบื้องหน้า ทั้งนี้ขึ้นอยู่กับระดับ API ที่แอปกำหนดเป้าหมาย
แอปที่กำหนดเป้าหมายเป็น Android 12 (ระดับ API 31) ขึ้นไปไม่ได้รับอนุญาตให้เริ่มบริการที่ทำงานอยู่เบื้องหน้าขณะที่แอปทำงานอยู่ในเบื้องหลัง ยกเว้นในบางกรณี ดูข้อมูลเพิ่มเติมและ ข้อมูลเกี่ยวกับ ข้อยกเว้นของกฎนี้ได้ที่ ข้อจำกัดในการเริ่ม บริการที่ทำงานอยู่เบื้องหน้า จากเบื้องหลัง
แอปที่กำหนดเป้าหมายเป็น Android 14 (ระดับ API 34) ขึ้นไปต้องขอสิทธิ์ที่เหมาะสมสำหรับประเภทบริการที่ทำงานอยู่เบื้องหน้า เมื่อแอปพยายามที่จะ เลื่อนระดับบริการเป็นบริการที่ทำงานอยู่เบื้องหน้า ระบบจะตรวจสอบสิทธิ์ที่เหมาะสม และแสดง
SecurityExceptionหาก แอปไม่มีสิทธิ์ดังกล่าว ตัวอย่างเช่น หากคุณพยายามเปิดใช้บริการที่ทำงานอยู่เบื้องหน้าประเภทlocationระบบจะตรวจสอบว่าแอปของคุณมีสิทธิ์ACCESS_COARSE_LOCATIONหรือACCESS_FINE_LOCATIONอยู่แล้ว เอกสารประกอบเกี่ยวกับประเภทบริการที่ทำงานอยู่เบื้องหน้าforeground service typeจะแสดงรายการ สิ่งที่ต้องมีก่อนสำหรับบริการที่ทำงานอยู่เบื้องหน้าแต่ละประเภท
เปิดใช้บริการ
หากต้องการเปิดใช้บริการที่ทำงานอยู่เบื้องหน้า คุณต้องเปิดใช้บริการดังกล่าวเป็นบริการทั่วไป (ที่ไม่ใช่บริการที่ทำงานอยู่เบื้องหน้า) ก่อน โดยทำดังนี้
Kotlin
val intent = Intent(...) // Build the intent for the service context.startForegroundService(intent)
Java
Context context = getApplicationContext(); Intent intent = new Intent(...); // Build the intent for the service context.startForegroundService(intent);
ประเด็นสำคัญเกี่ยวกับโค้ด
- ข้อมูลโค้ดจะเปิดใช้บริการ แต่บริการยังไม่ได้ทำงานอยู่ในเบื้องหน้า คุณต้องเรียก
ServiceCompat.startForeground()ภายในบริการเองเพื่อเลื่อนระดับบริการเป็นบริการที่ทำงานอยู่เบื้องหน้า
เลื่อนระดับบริการเป็นบริการที่ทำงานอยู่เบื้องหน้า
เมื่อบริการทำงานอยู่ คุณต้องเรียก
ServiceCompat.startForeground() เพื่อขอให้บริการ
ทำงานอยู่ในเบื้องหน้า โดยปกติแล้วคุณจะเรียกเมธอดนี้ในเมธอดของบริการ
onStartCommand()
ServiceCompat.startForeground() รับพารามิเตอร์ต่อไปนี้
- บริการ
- จำนวนเต็มบวกที่ระบุการแจ้งเตือนของบริการในแถบสถานะอย่างไม่ซ้ำกัน
- ออบเจ็กต์
Notificationเอง - ประเภทบริการที่ทำงานอยู่เบื้องหน้าหรือประเภทต่างๆ ที่ระบุงานที่บริการทำ
ประเภทบริการที่ทำงานอยู่เบื้องหน้าที่คุณส่งไปยัง startForeground()
จะต้องเป็นประเภทที่ประกาศในไฟล์ Manifest ทั้งนี้ขึ้นอยู่กับ Use Case ที่เฉพาะเจาะจง จากนั้นหากต้องการเพิ่มประเภทบริการอื่นๆ คุณสามารถเรียก startForeground() อีกครั้งได้
ตัวอย่างเช่น สมมติว่าแอปฟิตเนสเรียกใช้บริการติดตามการวิ่งที่ต้องใช้ข้อมูล location เสมอ แต่อาจไม่จำเป็นต้องเล่นสื่อ คุณจะต้องประกาศทั้ง location และ mediaPlayback ในไฟล์ Manifest หากผู้ใช้เริ่มวิ่งและต้องการเพียงแค่ติดตามตำแหน่ง แอปของคุณควรเรียก startForeground() และส่งเฉพาะสิทธิ์ ACCESS_FINE_LOCATION จากนั้นหากผู้ใช้ต้องการเริ่มเล่นเสียง ให้เรียก startForeground() อีกครั้งและส่งการรวมแบบบิตไวส์ของประเภทบริการที่ทำงานอยู่เบื้องหน้าทั้งหมด (ในกรณีนี้คือ ACCESS_FINE_LOCATION|FOREGROUND_SERVICE_MEDIA_PLAYBACK)
ตัวอย่างต่อไปนี้แสดงโค้ดที่บริการกล้องจะใช้เพื่อเลื่อนระดับตัวเองเป็นบริการที่ทำงานอยู่เบื้องหน้า
Kotlin
class MyCameraService: Service() { private fun startForeground() { // Before starting the service as foreground check that the app has the // appropriate runtime permissions. In this case, verify that the user has // granted the CAMERA permission. val cameraPermission = PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA) if (cameraPermission != PermissionChecker.PERMISSION_GRANTED) { // Without camera permissions the service cannot run in the foreground // Consider informing user or updating your app UI if visible. stopSelf() return } try { val notification = NotificationCompat.Builder(this, "CHANNEL_ID") // Create the notification to display while the service is running .build() ServiceCompat.startForeground( /* service = */ this, /* id = */ 100, // Cannot be 0 /* notification = */ notification, /* foregroundServiceType = */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA } else { 0 }, ) } catch (e: Exception) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e is ForegroundServiceStartNotAllowedException) { // App not in a valid state to start foreground service // (e.g. started from bg) } // ... } } }
Java
public class MyCameraService extends Service { private void startForeground() { // Before starting the service as foreground check that the app has the // appropriate runtime permissions. In this case, verify that the user // has granted the CAMERA permission. int cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA); if (cameraPermission == PackageManager.PERMISSION_DENIED) { // Without camera permissions the service cannot run in the // foreground. Consider informing user or updating your app UI if // visible. stopSelf(); return; } try { Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID") // Create the notification to display while the service // is running .build(); int type = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { type = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; } ServiceCompat.startForeground( /* service = */ this, /* id = */ 100, // Cannot be 0 /* notification = */ notification, /* foregroundServiceType = */ type ); } catch (Exception e) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e instanceof ForegroundServiceStartNotAllowedException ) { // App not in a valid state to start foreground service // (e.g started from bg) } // ... } } //... }
ประเด็นสำคัญเกี่ยวกับโค้ด
- แอปได้ประกาศในไฟล์ Manifest แล้วว่าต้องใช้สิทธิ์
CAMERAอย่างไรก็ตาม แอปยังต้องตรวจสอบในรันไทม์เพื่อให้แน่ใจว่าผู้ใช้ให้สิทธิ์ดังกล่าวแล้ว หากแอปไม่มีสิทธิ์ที่ถูกต้อง แอปควรแจ้งให้ผู้ใช้ทราบถึงปัญหา - มีการเปิดตัวบริการที่ทำงานอยู่เบื้องหน้าประเภทต่างๆ ในแพลตฟอร์ม Android เวอร์ชันต่างๆ โค้ดนี้จะตรวจสอบเวอร์ชัน Android ที่กำลังทำงานอยู่และขอสิทธิ์ที่เหมาะสม
- โค้ดจะตรวจสอบ
ForegroundServiceStartNotAllowedExceptionในกรณีที่พยายามเริ่มบริการที่ทำงานอยู่เบื้องหน้าในสถานการณ์ที่ไม่ได้รับอนุญาต (เช่น หากพยายามเลื่อนระดับบริการเป็นบริการที่ทำงานอยู่เบื้องหน้า ขณะที่ แอปทำงานอยู่ในเบื้องหลัง)