Background คือสถานะวงจรชีวิตของแอปที่แอปยังคงทำงานอยู่แต่ไม่แสดงบนหน้าจอ เราอธิบายพื้นฐานการทำงานเบื้องหลังบน iOS และ Android: ข้อจำกัด หมดเวลา งานพื้นหลังผ่าน beginBackgroundTask, WorkManager และ Service รวมถึงแนวทางปฏิบัติที่ดีที่สุดสำหรับการจัดการ Background ที่ถูกต้อง
ประเด็นสำคัญ
Background คือสถานะของแอปที่แอปยังคงอยู่ในระบบปฏิบัติการ เรียกใช้โค้ดและใช้ทรัพยากร แต่ไม่แสดงบนหน้าจออุปกรณ์ ผู้ใช้อยู่ที่หน้าจอหลัก ในแอปอื่น หรือหน้าจออุปกรณ์ถูกล็อค บน iOS Background ต่อจาก Inactive — ห่วงโซ่การเปลี่ยน: Active → Inactive → Background บน Android onStop บ่งชี้การเปลี่ยนของ Activity ไปยัง Background
ทั้งสองแพลตฟอร์มกำหนดข้อจำกัดที่เข้มงวดต่อการทำงานพื้นหลัง iOS ให้เวลาจำกัด (โดยปกติ 30 วินาที) ในการเรียกใช้โค้ดหลังจากเข้าสู่ Background หลังจากนั้นแอปจะเปลี่ยนเป็น Suspended Android ยืดหยุ่นกว่า: Foreground Service พร้อมการแจ้งเตือนที่มองเห็นได้สามารถทำงานได้อย่างไม่จำกัด แต่ Background Service ทั่วไปจำกัดไว้เพียงไม่กี่นาที งานหลักของนักพัฒนา คือการบันทึกสถานะอย่างถูกต้องและกำหนดเวลาการทำงานต่อผ่าน API งานพื้นหลังของระบบ
ระบบสามารถยุติแอปพื้นหลังได้ทุกเมื่อเมื่อหน่วยความจำไม่เพียงพอ เมื่อยุติแล้ว ข้อมูลที่ไม่ได้บันทึกทั้งหมดจะสูญหาย ดังนั้นจึงสำคัญอย่างยิ่งที่จะบันทึกสถานะใน applicationDidEnterBackground (iOS) หรือ onStop (Android) หลังจากการยุติ การเริ่มต้นครั้งถัดไปจะเริ่มจาก Not Running ด้วยการเริ่มต้นแบบเย็นและกู้คืนสถานะที่บันทึกไว้
สิ่งสำคัญคือต้องแยกความแตกต่างระหว่าง Background และ Suspended Background — แอปกำลังเรียกใช้โค้ดอย่างแข็งขัน Suspended — แอปอยู่ในหน่วยความจำแต่ไม่เรียกใช้โค้ด — มันถูกแช่แข็ง บน iOS แอปเปลี่ยนจาก Background เป็น Suspended หลังจากทำงานพื้นหลังเสร็จ Android ไม่มี Suspended — กระบวนการมีอยู่ (รวมถึง Background) หรือยุติ (Not Running) อย่างไรก็ตาม Android สามารถหยุดการทำงานของเธรดชั่วคราวผ่าน LMK (Low Memory Killer)
| คุณลักษณะ | iOS Background | Android Background |
|---|---|---|
| เรียกใช้โค้ด | ใช่ สูงสุด 30 วินาที | ใช่ ขึ้นอยู่กับ API |
| UI มองเห็น | ไม่ | ไม่ |
| หมดเวลาเริ่มต้น | ~30 วินาที (beginBackgroundTask) | หลายนาที (Service) |
| ทำงานไม่จำกัด | เฉพาะหมวดพิเศษ (เสียง, VoIP, นำทาง) | Foreground Service พร้อมการแจ้งเตือน |
| รับประกันการทำงาน | ไม่ — ระบบสามารถยุติได้ทุกเมื่อ | WorkManager รับประกันการทำงาน |
| ต้องได้รับอนุญาต | ใช่ — capabilities ใน Info.plist | ใช่ — การอนุญาต FOREGROUND_SERVICE |
| สถานะถัดไป | Suspended → Not Running | Not Running (หรือเริ่มใหม่) |
บน iOS Background ถูกจัดการผ่านเมธอดตัวแทน applicationDidEnterBackground ในเมธอดนี้ นักพัฒนาควรบันทึกสถานะผู้ใช้ ปล่อยทรัพยากร และทำงานพื้นหลังให้เสร็จ เพื่อเรียกใช้โค้ดหลังจากเข้าสู่ Background ใช้ beginBackgroundTask(expirationHandler:) — API ที่ขอเวลาเพิ่มเติมจากระบบ (โดยปกติ 30 วินาที) หากงานไม่เสร็จภายในเวลานี้ expirationHandler จะถูกเรียก และแอปจะถูกบังคับให้เปลี่ยนเป็น Suspended
กับ iOS 13 Apple เปิดตัว BGTaskScheduler — API ที่ทันสมัยสำหรับกำหนดเวลางานพื้นหลัง ต่างจาก beginBackgroundTask ที่ให้เวลาเฉพาะการสิ้นสุดหลังจากเข้าสู่พื้นหลัง BGTaskScheduler อนุญาตให้กำหนดเวลาการทำงานในอนาคต — ตัวอย่างเช่น อัปเดตเนื้อหาทุกชั่วโมงหรืออัปโหลดการวิเคราะห์ในเวลากลางคืน BGTaskScheduler เป็นแนวทางที่แนะนำ สำหรับโปรเจกต์ใหม่ เนื่องจากมีประสิทธิภาพด้านแบตเตอรี่มากกว่า
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
// แอปเข้าสู่พื้นหลัง — เริ่มงานพื้นหลัง
func applicationDidEnterBackground(_ application: UIApplication) {
saveAppState()
startBackgroundTask()
}
private func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
// หมดเวลา — กำลังบังคับสิ้นสุด
self?.endBackgroundTask()
}
// จำลองการทำงานพื้นหลัง (บันทึกข้อมูลไปยังเซิร์ฟเวอร์)
DispatchQueue.global().async { [weak self] in
uploadAnalyticsData()
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
guard backgroundTaskID != .invalid else { return }
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// การลงทะเบียน BGTaskScheduler
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.example.refresh",
using: nil
) { task in
handleAppRefresh(task: task as! BGAppRefreshTask)
}
return true
}
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 3600)
try? BGTaskScheduler.shared.submit(request)
}
func handleAppRefresh(task: BGAppRefreshTask) {
scheduleAppRefresh()
task.expirationHandler = { task.setTaskCompleted(success: false) }
fetchLatestData { result in
task.setTaskCompleted(success: result)
}
}
}โค้ดแสดงการจัดการ Background ที่สมบูรณ์บน iOS applicationDidEnterBackground เริ่มงานพื้นหลังผ่าน beginBackgroundTask พร้อมหมดเวลาและ expirationHandler พร้อมกันนั้น BGTaskScheduler ถูกลงทะเบียนสำหรับการอัปเดตเนื้อหาเป็นระยะ beginBackgroundTask ใช้สำหรับงานปิดเครื่องทันที BGTaskScheduler ใช้สำหรับการวางแผนระยะยาว API ทั้งสองต้องการการจัดการตัวระบุงานที่เหมาะสม
บน Android Background ถูกจัดการผ่านหลาย API Service แบบดั้งเดิมอนุญาตให้เรียกใช้โค้ดในพื้นหลัง แต่ตั้งแต่ Android 8+ (API 26) Background Service ถูกจำกัด: ระบบจะยุติมันไม่กี่นาทีหลังจากแอปเข้าสู่พื้นหลัง Foreground Service พร้อมการแจ้งเตือนถาวรสามารถทำงานได้อย่างไม่จำกัด WorkManager เป็นโซลูชันที่แนะนำสำหรับงานพื้นหลังพร้อมรับประกันการทำงานแม้หลังจากรีสตาร์ทอุปกรณ์
Android ต่างจาก iOS ที่รองรับกระบวนการพื้นหลังที่ยาวนาน Foreground Service ใช้สำหรับงานที่ผู้ใช้ควรเห็น — การเล่นเพลง การนำทาง การติดตามการออกกำลังกาย JobScheduler และ WorkManager ใช้สำหรับงานที่สามารถเลื่อนออกไปได้: การซิงค์ข้อมูล การอัปโหลดล็อก การอัปเดตแคช ความแตกต่างหลัก: Android อนุญาตให้กำหนดเวลางานพร้อมเงื่อนไข — Wi-Fi, การชาร์จ, อุปกรณ์ว่าง — ซึ่งประหยัดแบตเตอรี่และปริมาณการใช้งาน
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*
// 1. Foreground Service สำหรับการทำงานพื้นหลังที่ยาวนาน
class SyncService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(NOTIFICATION_ID, notification)
performBackgroundWork()
return START_STICKY
}
private fun performBackgroundWork() {
Thread {
// การซิงค์ข้อมูลกับเซิร์ฟเวอร์
syncDataToServer()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 2. WorkManager สำหรับงานพื้นหลังที่เลื่อนออกไป
class DataSyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// อัปโหลดการวิเคราะห์ไปยังเซิร์ฟเวอร์
uploadAnalytics()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// การกำหนดเวลางาน WorkManager
fun scheduleBackgroundSync(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val request = OneTimeWorkRequestBuilder<DataSyncWorker>()
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueue(request)
}โค้ดแสดงสองแนวทางสำหรับการทำงานพื้นหลังบน Android SyncService — Foreground Service พร้อมการแจ้งเตือนสำหรับงานพื้นหลังทันทีและยาวนาน DataSyncWorker — WorkManager สำหรับงานที่เลื่อนออกไปพร้อมเงื่อนไข (Wi-Fi, การชาร์จ) WorkManager รับประกันการทำงานแม้หลังจากรีสตาร์ทอุปกรณ์และรองรับการถอยหลังแบบเอ็กซ์โพเนนเชียลสำหรับการลองใหม่ Foreground Service ต้องการการแจ้งเตือนถาวรในแถบสถานะ
ทั้งสองแพลตฟอร์มมือถือกำลังเข้มงวดกฎการทำงานพื้นหลังอย่างต่อเนื่อง บน iOS แต่ละรุ่นใหม่ของระบบปฏิบัติการลดเวลาเรียกใช้พื้นหลังและเพิ่มข้อจำกัดใหม่ บน Android Google กำลังแนะนำโหมดประหยัดพลังงานที่เข้มงวดมากขึ้น (Doze, App Standby) นักพัฒนาควรติดตามข้อจำกัดปัจจุบัน เพื่อป้องกันไม่ให้แอปถูกยุติก่อนเวลาอันควรโดยระบบ
บน iOS เริ่มจาก iOS 13 ระบบปิดการใช้งานงานพื้นหลังสำหรับแอปที่ใช้เวลาในพื้นหลังในทางที่ผิด แต่ละแอปได้รับขีดจำกัดตามพฤติกรรมผู้ใช้ BGTaskScheduler กำหนดเวลาการทำงานในช่วงเวลาที่เหมาะสม — ตัวอย่างเช่น เมื่ออุปกรณ์เชื่อมต่อ Wi-Fi และกำลังชาร์จ แอปที่ใช้ BGTaskScheduler อย่างถูกต้องจะได้รับเวลาพื้นหลังมากขึ้น
บน Android เริ่มจาก Android 9 (API 28) การทำงานพื้นหลังถูกจำกัดโดยโหมด Doze ซึ่งเปิดใช้งานเมื่ออุปกรณ์ไม่ได้ใช้งาน แอปใน Doze ไม่สามารถทำงานพื้นหลังได้ เครือข่ายถูกตัดการเชื่อมต่อ JobScheduler และ WorkManager เลื่อนงานออกไปจนกว่าจะออกจาก Doze Foreground Service เป็นวิธีเดียวที่จะเลี่ยง Doze แต่การใช้ในทางที่ผิดนำไปสู่การบล็อกแอปโดยผู้ใช้และการเพิกถอนสิทธิ์
| ข้อจำกัด | iOS | Android |
|---|---|---|
| หมดเวลางานพื้นหลัง | ~30 วินาที (beginBackgroundTask) | หลายนาที (JobScheduler) |
| พื้นหลังไม่จำกัด | เสียง, VoIP, นำทาง, Bluetooth | Foreground Service + การแจ้งเตือน |
| ประหยัดพลังงาน | Low Power Mode — ปิดงานพื้นหลัง | Doze, App Standby, การเพิ่มประสิทธิภาพแบตเตอรี่ |
| การกำหนดเวลา | BGTaskScheduler (iOS 13+) | WorkManager (Android Jetpack) |
| หลังจากรีสตาร์ท | เฉพาะการแจ้งเตือนแบบพุช | WorkManager รักษางานไว้ |
| เวลาทำงานสูงสุด | ~30 นาที (เสียง) | ไม่จำกัด (Foreground Service) |
กฎข้อแรก — ลดการใช้ทรัพยากรในพื้นหลัง งานพื้นหลังส่วนใหญ่สามารถเลื่อนไปเมื่ออุปกรณ์กำลังชาร์จและเชื่อมต่อ Wi-Fi ใช้ BGTaskScheduler (iOS) และ WorkManager (Android) เพื่อกำหนดเวลางานพร้อมเงื่อนไข อย่าเรียกใช้การคำนวณหนักในพื้นหลัง — สิ่งนี้ทำให้แบตเตอรี่หมดและนำไปสู่การจำกัด CPU
กฎข้อที่สอง — ระบุ expirationHandler สำหรับ beginBackgroundTask เสมอ หากแอปไม่ทำงานให้เสร็จภายในเวลาที่กำหนด ระบบจะบังคับให้เปลี่ยนเป็น Suspended หรือยุติ ExpirationHandler คือโอกาสสุดท้ายในการบันทึกข้อมูลและสิ้นสุดงานอย่างถูกต้อง บน Android ใช้ setForegroundAsync ใน WorkManager เพื่อแปลงงานปกติเป็นเบื้องหน้าหากต้องการเวลามากขึ้น
กฎข้อที่สาม — ตรวจสอบข้อจำกัดการทำงานพื้นหลังก่อนเริ่ม บน iOS ใช้ UIApplication.shared.backgroundTimeRemaining เพื่อตรวจสอบเวลาที่เหลือ บน Android ตรวจสอบ ActivityManager.isBackgroundRestricted() — หากเป็น true แอปไม่สามารถทำงานพื้นหลังได้ และคุณควรแนะนำให้ผู้ใช้ลบข้อจำกัดในการตั้งค่า สิ่งนี้สำคัญโดยเฉพาะสำหรับแอปที่มีฟังก์ชันพื้นหลังที่สำคัญ — นาฬิกาปลุก ปฏิทิน การซิงค์
กฎข้อที่สี่ — ทดสอบงานพื้นหลังบนอุปกรณ์จริง ตัวจำลองและอีมูเลเตอร์ไม่สร้างข้อจำกัดการทำงานพื้นหลังจริง บน iOS ใช้ Debug → Simulate Background Fetch ใน Xcode บน Android ใช้ adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED สำหรับทดสอบ WorkManager หลังจากรีสตาร์ท การทดสอบจริงบนอุปกรณ์ที่มีแบตเตอรี่ต่ำ เผยให้เห็นปัญหาการทำงานพื้นหลังส่วนใหญ่
import UIKit
final class BackgroundTaskManager {
static let shared = BackgroundTaskManager()
private var tasks: [String: UIBackgroundTaskIdentifier] = [:]
func startTask(name: String, expiration: @escaping () -> Void) {
let remaining = UIApplication.shared.backgroundTimeRemaining
print("เวลาที่เหลือในพื้นหลัง: \(remaining) วินาที")
let task = UIApplication.shared.beginBackgroundTask { [weak self] in
print("หมดเวลาสำหรับงาน: \(name)")
expiration()
self?.endTask(name: name)
}
tasks[name] = task
}
func endTask(name: String) {
guard let task = tasks.removeValue(forKey: name),
task != .invalid
else { return }
UIApplication.shared.endBackgroundTask(task)
}
}โค้ดแสดงตัวจัดการงานพื้นหลังที่ติดตามเวลาที่เหลือและจัดการตัวระบุ backgroundTimeRemaining ส่งคืนจำนวนวินาทีก่อนการยุติแบบบังคับ — หากค่าเป็นอนันต์ แอปกำลังทำงานโดยไม่มีข้อจำกัด (เสียง, การนำทาง) ตัวจัดการอนุญาตให้เริ่มงานพื้นหลังหลายรายการด้วยชื่อที่แตกต่างกันและสิ้นสุดแต่ละงานอย่างถูกต้อง แนวทางนี้ป้องกันการรั่วไหลของงานพื้นหลังและรับประกันว่าระบบจะไม่ยุติแอปเนื่องจากงานที่ไม่ได้ปิด
คำถามที่พบบ่อย
ได้ สำหรับหมวดหมู่ที่จำกัด: เสียง (AVAudioSession หมวด .playback), VoIP (PushKit), การนำทาง (CLLocationManager พร้อม allowsBackgroundLocationUpdates), Bluetooth (โหมดพื้นหลังกลาง), การอัปเดตพื้นหลัง (BGTaskScheduler) สำหรับอย่างอื่น — สูงสุด 30 วินาที ใน iOS 16+ Apple เข้มงวดข้อกำหนดแม้สำหรับหมวดหมู่ที่ได้รับอนุญาต
beginBackgroundTask คือ API แบบซิงโครนัสสำหรับขยายอายุแอปประมาณ 30 วินาทีหลังจากเข้าสู่พื้นหลัง เรียกใน applicationDidEnterBackground BGTaskScheduler คือ API แบบอะซิงโครนัสสำหรับกำหนดเวลางานในอนาคตผ่านตัวกระตุ้นระบบ (เวลา, ตำแหน่ง, การอัปเดตเนื้อหา) BGTaskScheduler เป็นแนวทางที่ทันสมัย แนะนำโดย Apple สำหรับ iOS 13+
เริ่มจาก Android 8 (API 26) Background Service จะถูกยุติไม่กี่นาทีหลังจากแอปเข้าสู่พื้นหลัง วิธีแก้: ใช้ Foreground Service พร้อมการแจ้งเตือนสำหรับการดำเนินการยาวนาน หรือ WorkManager สำหรับงานที่เลื่อนออกไป ตรวจสอบการเพิ่มประสิทธิภาพแบตเตอรี่สำหรับแอปของคุณในการตั้งค่า — หากได้รับการปรับให้เหมาะสม ระบบอาจเลื่อนหรือยกเลิกงานพื้นหลัง
กด Cmd+Shift+H เพื่อไปที่หน้าจอหลัก ใน Xcode ใช้ Debug → Simulate Background Fetch เพื่อตรวจสอบ beginBackgroundTask เปิดคอนโซล (Shift+Cmd+C) และเรียก e UIApplication.shared.backgroundTimeRemaining ใน Xcode 15+ มีสคริปต์ Background Execution ในแท็บ Diagnostics ของตัวจำลอง
Process Death คือการยุติกระบวนการ Android โดยระบบเมื่อทรัพยากรไม่เพียงพอหรือเมื่อไม่ได้ใช้งานในพื้นหลัง ต่างจาก iOS ตรงที่ Android ไม่มี Suspended — กระบวนการมีชีวิตอยู่ (สามารถอยู่ในพื้นหลัง) หรือตาย (Not Running) Process Death คือพฤติกรรมปกติของระบบปฏิบัติการ และแอปควรกู้คืนสถานะอย่างถูกต้องหลังจากนั้นผ่าน SavedStateHandle, onSaveInstanceState หรือ DataStore
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ