Background Task เป็นกลไกของ iOS ที่ช่วยให้แอปพลิเคชันทำงานให้เสร็จสมบูรณ์หลังจากเปลี่ยนไปอยู่ในพื้นหลัง ระบบจะจัดสรรเวลาจำกัด (สูงสุด 30 วินาที) สำหรับการทำงาน เมื่อหมดเวลาแอปพลิเคชันจะถูกพักการทำงานโดยอัตโนมัติ ตามข้อมูลของ Apple, 2026 การใช้ expiration handler เป็นข้อกำหนดบังคับสำหรับการทำงานพื้นหลังให้เสร็จสมบูรณ์อย่างถูกต้อง
ประเด็นสำคัญ
Background Task เป็นกลไกการเขียนโปรแกรม iOS ที่ช่วยให้แอปพลิเคชันขยายเวลาการทำงานหลังจากเปลี่ยนไปสู่พื้นหลัง เมื่อผู้ใช้ย่อแอปพลิเคชัน ระบบจะเรียก UIApplicationDelegate.applicationDidEnterBackground หากมีการดำเนินการที่สำคัญกำลังทำงานอยู่ในขณะนั้น (การบันทึกข้อมูล การส่งคำขอ) แอปพลิเคชันสามารถขอเวลาเพิ่มเติมผ่าน beginBackgroundTask
หากไม่ใช้ Background Task แอปพลิเคชันจะถูกพักการทำงานโดยอัตโนมัติภายใน 3–5 วินาทีหลังจากเข้าสู่พื้นหลัง การดำเนินการที่ยังไม่เสร็จทั้งหมดจะถูกขัดจังหวะ: ข้อมูลไม่ถูกบันทึก คำขอเครือข่ายถูกยกเลิก สถานะสูญหาย Background Task ให้เวลาแอปพลิเคชันสูงสุด 30 วินาทีเพื่อดำเนินการเหล่านี้ให้เสร็จอย่างถูกต้อง
beginBackgroundTask ปรากฏใน iOS 4.0 — รุ่นแรกที่รองรับการทำงานหลายอย่างพร้อมกัน ก่อน iOS 4 แอปพลิเคชันจะถูกยุติอย่างสมบูรณ์เมื่อกดปุ่ม Home iOS 7 นำเสนอ Background Fetch และการกำหนดค่าพื้นหลังของ URLSession ตั้งแต่ iOS 13 เป็นต้นไป Apple แนะนำ BGTaskScheduler สำหรับโปรเจกต์ใหม่ แต่ beginBackgroundTask ยังคงมีความเกี่ยวข้องสำหรับการดำเนินการระยะสั้น
beginBackgroundTask เป็นเมธอดของ UIApplication ที่ลงทะเบียนงานและส่งคืน UIBackgroundTaskIdentifier เฉพาะ ระบบจะเพิ่มตัวจับเวลาการทำงานพื้นหลัง เมื่อเวลาหมด expiration handler จะถูกเรียก หลังจากนั้นแอปพลิเคชันต้องเรียก endBackgroundTask(identifier:) เพื่อทำงานให้เสร็จอย่างถูกต้อง
ขั้นตอนที่ 1 — แอปพลิเคชันได้รับการแจ้งเตือน didEnterBackground ขั้นตอนที่ 2 — เรียก beginBackgroundTask(expirationHandler:) ขั้นตอนที่ 3 — ดำเนินการที่สำคัญ (บันทึก, คำขอเครือข่าย) ขั้นตอนที่ 4 — เมื่อเสร็จสิ้น เรียก endBackgroundTask(identifier:) หากการดำเนินการไม่เสร็จภายใน 30 วินาที — ระบบจะเรียก expiration handler และแอปพลิเคชันต้องยุติงานทันที
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Expiration handler
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
func finishBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
คุณสมบัติ backgroundTimeRemaining ส่งคืนจำนวนวินาทีที่เหลือก่อนที่งานพื้นหลังจะถูกยุติโดยอัตโนมัติ ค่าจะลดลงตามเวลาจริง หากแอปพลิเคชันไม่อยู่ในพื้นหลัง — จะส่งคืน DBL_MAX ใช้คุณสมบัตินี้เพื่อปรับพฤติกรรม: เมื่อเหลือน้อยกว่า 5 วินาที ให้ขัดจังหวะการดำเนินการที่ยาวนานและบันทึกความคืบหน้า
แอปพลิเคชันสามารถลงทะเบียน Background Tasks หลายรายการพร้อมกันได้ งานแต่ละงานจะได้รับตัวระบุของตนเอง เวลาทำงานทั้งหมดจะสะสม — หากลงทะเบียน 3 งาน แอปพลิเคชันจะได้รับเวลาสูงสุด 90 วินาที อย่างไรก็ตาม ระบบอาจยุติแอปพลิเคชันก่อนเวลาหากทรัพยากรหมดหรือเกินขีดจำกัดแบตเตอรี่
Expiration handler เป็นบล็อกโค้ดที่ระบบเรียกเมื่อเวลาที่จัดสรรสำหรับงานพื้นหลังหมดลง การมี expiration handler เป็นข้อกำหนดบังคับของ Apple หากไม่มี แอปพลิเคชันอาจถูกยุติโดยอัตโนมัติโดยระบบและข้อมูลอาจสูญหาย
Expiration handler ต้องดำเนินการขั้นต่ำเพื่อบันทึกสถานะแอปพลิเคชัน: บันทึกข้อมูลปัจจุบันไปยังพื้นที่จัดเก็บถาวร เรียก endBackgroundTask พร้อมตัวระบุที่เกี่ยวข้อง และตั้งค่าตัวระบุเป็น .invalid ภายใน expiration handler ห้ามเริ่มดำเนินการที่ยาวนานใหม่ — เวลาดำเนินการจำกัดอยู่ที่ 1–2 วินาที
func handleExpiration() {
// กำลังบันทึกความคืบหน้าของการทำงาน
saveProgressToUserDefaults()
// กำลังยกเลิกคำขอเครือข่ายที่กำลังทำงานอยู่
currentTask?.cancel()
// กำลังยุติ Background Task
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// การลงทะเบียนกับ expiration handler
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
ข้อผิดพลาดที่พบบ่อยที่สุดคือไม่เรียก endBackgroundTask ภายใน expiration handler ในกรณีนี้ ระบบจะยังคงถือว่างานกำลังทำงานอยู่ แอปพลิเคชันจะไม่เปลี่ยนไปสู่สถานะพักการทำงาน และแบตเตอรี่จะหมด ข้อผิดพลาดที่สองคือการเริ่มดำเนินการที่ยาวนานภายใน expiration handler ระบบอาจยุติแอปพลิเคชันก่อนที่งานจะเสร็จและข้อมูลจะสูญหาย
ใน expiration handler เวลาดำเนินการมีจำกัดอย่างยิ่ง — โดยทั่วไป น้อยกว่า 1 วินาที ดังนั้น ภายใน handler คุณไม่สามารถดำเนินการ: การคำนวณซับซ้อน คำขอเครือข่าย การเขียนข้อมูลปริมาณมากไปยัง CoreData ได้เฉพาะการดำเนินการอะตอมมิก: การเขียนคีย์เดียวไปยัง UserDefaults การตั้งค่าแฟลกสถานะ การเรียก endBackgroundTask
มาดูการใช้งาน Background Task ที่สมบูรณ์สำหรับการบันทึกเอกสารเมื่อแอปเข้าสู่พื้นหลัง ตัวอย่างรวมถึงการลงทะเบียนงาน การดำเนินการพร้อมตรวจสอบเวลาที่เหลือ และการเสร็จสิ้นอย่างถูกต้องผ่าน endBackgroundTask
เมื่อเข้าสู่พื้นหลัง แอปพลิเคชันจะเริ่มบันทึกเอกสารขนาดใหญ่ Background Task ให้เวลาสูงสุด 30 วินาทีสำหรับการดำเนินการ หากเวลาหมด — expiration handler จะบันทึกผลลัพธ์กลาง หลังจากการบันทึกเสร็จสมบูรณ์ จะเรียก endBackgroundTask เพื่อปล่อยทรัพยากร
class DocumentManager {
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func saveDocumentInBackground(document: Document) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
self.saveProgress(document)
self.endBackgroundTask()
}
DispatchQueue.global().async {
document.save()
self.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
คำขอเครือข่าย ในพื้นหลังต้องการความสนใจเป็นพิเศษ — expiration handler อาจขัดจังหวะคำขอก่อนที่จะได้รับการตอบกลับ ใช้ URLSession กับ dataTask และตรวจสอบ backgroundTimeRemaining ก่อนส่ง หากเหลือน้อยกว่า 5 วินาที — ให้เลื่อนการส่งออกไปจนกว่าแอปจะถูกปลุกครั้งถัดไป
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// กำลังบันทึกข้อมูลสำหรับการส่งซ้ำ
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
สำหรับการดำเนินการที่ยาวนาน ให้ตรวจสอบ UIApplication.shared.backgroundTimeRemaining หากค่าลดลงต่ำกว่าเกณฑ์ (10 วินาที) ให้ขัดจังหวะการดำเนินการปัจจุบันและเริ่มบันทึกผลลัพธ์กลาง วิธีนี้ช่วยให้เสร็จสมบูรณ์อย่างถูกต้องก่อนที่ expiration handler จะถูกเรียกโดยอัตโนมัติ
Background Task เป็นกลไกที่ทรงพลัง แต่การใช้ไม่เหมาะสมนำไปสู่ปัญหาแบตเตอรี่และประสิทธิภาพ การปฏิบัติตามคำแนะนำของ Apple และแนวทางปฏิบัติที่พิสูจน์แล้วของชุมชนจะช่วยหลีกเลี่ยงข้อผิดพลาดทั่วไปและรับประกันการทำงานของแอปพลิเคชันที่เสถียร
ดำเนินการ Background Task ให้เสร็จโดยเร็วที่สุด ทุกวินาทีของการทำงานในพื้นหลังจะใช้พลังงานแบตเตอรี่ เวลาที่เหมาะสมที่สุด — น้อยกว่า 5 วินาที หากการดำเนินการใช้เวลานานกว่านั้น — พิจารณาใช้ BGTaskScheduler หรือ Background Modes อย่าขยายงานโดยไม่จำเป็นผ่านการเรียก beginBackgroundTask โดยไม่มีเหตุผลอันสมควร
จัดเก็บ UIBackgroundTaskIdentifier เป็นคุณสมบัติของคลาสหรือโครงสร้าง อย่าส่งผ่านเป็นตัวแปรส่วนกลาง — สิ่งนี้จะนำไปสู่ความขัดแย้งกับงานหลายรายการ ตั้งค่าตัวระบุเป็น .invalid หลังจากเรียก endBackgroundTask เพื่อป้องกันการเสร็จสิ้นซ้ำ
ใน Xcode Simulator ให้เปลี่ยนแอปพลิเคชันไปยังพื้นหลังผ่านปุ่ม Home (Command + Shift + H) ใช้ Debug — Simulate Background Fetch สำหรับทดสอบการปลุกในพื้นหลัง เพื่อจำลองการหมดเวลา ให้ตั้งค่าตัวแปรสภาพแวดล้อม BACKGROUND_TASK_SIMULATE_EXPIRATION = YES — expiration handler จะถูกเรียกภายใน 5 วินาที
// กำลังตรวจสอบเวลาที่เหลือก่อนเริ่มการดำเนินการ
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// เวลาไม่เพียงพอ — เลื่อนงานออกไป
scheduleForNextLaunch()
return
}
// กำลังดำเนินการพร้อมควบคุมเวลา
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
Expiration handler จับ self — สิ่งนี้สามารถสร้าง retain cycle หาก backgroundTaskID ถูกจัดเก็บเป็นคุณสมบัติของออบเจกต์เดียวกัน ใช้ [weak self] ในคลอเชอร์หรือจัดเก็บตัวระบุแยกต่างหาก Retain cycle ทำให้เกิดหน่วยความจำรั่ว — ออบเจกต์จะไม่ถูกปล่อยจนกว่าแอปพลิเคชันจะยุติ
ด้วยการเปิดตัว iOS 13 Apple ได้นำเสนอ BGTaskScheduler — ตัวแทนที่ทันสมัยของ API Background Task เดิม ทั้งสองกลไกแก้ปัญหางานที่คล้ายกัน แต่ BGTaskScheduler ให้การควบคุมและความยืดหยุ่นมากกว่า การเข้าใจความแตกต่างจะช่วยเลือกเครื่องมือที่เหมาะสมสำหรับสถานการณ์เฉพาะ
| คุณลักษณะ | Background Task | BGTaskScheduler |
|---|---|---|
| เวอร์ชัน iOS | 4.0+ | 13.0+ |
| เวลาสูงสุด | 30 วินาที | 30 วินาที / 10 นาที (processing) |
| การเริ่มต้น | didEnterBackground | การกำหนดเวลา + ระบบ |
| การรับประกันการทำงาน | เฉพาะเมื่อเข้าสู่พื้นหลัง | ทุกเวลาที่ระบบสะดวก |
| Expiration handler | ใช่, จำเป็น | ใช่, ผ่าน task.expirationHandler |
| อินเทอร์เน็ต | จำเป็นเมื่อเริ่มต้น | พร้อมใช้งานผ่าน requiresNetworkConnectivity |
| การชาร์จ | ไม่จำเป็น | ไม่บังคับสำหรับ processing |
beginBackgroundTask เหมาะสำหรับการดำเนินการระยะสั้นที่ต้องดำเนินการทันทีเมื่อเข้าสู่พื้นหลัง: การบันทึกสถานะ การทำคำขอเครือข่ายให้เสร็จ การแคชข้อมูล API เรียบง่ายและไม่ต้องการการกำหนดค่า Info.plist หรือการลงทะเบียนตัวระบุ เหมาะสำหรับการดำเนินการที่ใช้เวลาน้อยกว่า 10 วินาที
BGTaskScheduler เหมาะสำหรับงานที่สามารถดำเนินการได้ทุกเวลาที่สะดวก: การซิงค์เป็นระยะ การทำความสะอาดแคช การอัปเดตวิดเจ็ต ระบบจะเลือกเวลาที่เหมาะสมที่สุดโดยพิจารณาจากพฤติกรรมผู้ใช้และสถานะแบตเตอรี่ สำหรับการดำเนินการที่ยาวนาน (สูงสุด 10 นาที) ให้ใช้ BGProcessingTask
ทั้งสอง API สามารถใช้ในแอปพลิเคชันเดียวกันได้ Background Task — สำหรับการดำเนินการทันทีเมื่อเข้าสู่พื้นหลัง (การบันทึกแบบร่าง) BGTaskScheduler — สำหรับการอัปเดตตามกำหนดเวลา (การซิงค์ทุก 6 ชั่วโมง) การแยกความรับผิดชอบช่วยให้มั่นใจในการเก็บรักษาข้อมูลที่ถูกต้องและการบำรุงรักษาพื้นหลังที่ประหยัดพลังงาน
คำถามที่พบบ่อย
ได้ beginBackgroundTask สามารถเรียกได้ทุกจุดระหว่างการทำงานของแอปพลิเคชัน อย่างไรก็ตาม การจัดสรรเวลาของระบบจะเริ่มหลังจากเปลี่ยนไปสู่พื้นหลังเท่านั้น หากแอปพลิเคชันอยู่ในเบื้องหน้า การเรียก beginBackgroundTask ไม่มีผล — backgroundTimeRemaining ส่งคืน DBL_MAX และงานจะถูกเปิดใช้งานเมื่อเข้าสู่พื้นหลัง
หากไม่เรียก endBackgroundTask ระบบจะยังคงถือว่าแอปพลิเคชันทำงานอยู่ในพื้นหลัง หลังจาก 30 วินาที expiration handler จะถูกเรียก แต่หากไม่มี endBackgroundTask เช่นกัน — แอปพลิเคชันจะยังคงอยู่ในหน่วยความจำ ทำให้แบตเตอรี่หมด ใน iOS 13+ ระบบจะยุติแอปพลิเคชันดังกล่าวโดยอัตโนมัติหลังจาก 3 นาที
เวลามาตรฐานคือ 30 วินาที สามารถขยายได้ผ่าน Background Modes: เสียง (การเล่น), ตำแหน่ง (พิกัดทางภูมิศาสตร์), Bluetooth (BLE) หรือผ่าน BGProcessingTask (iOS 13+) — สูงสุด 10 นาทีพร้อมการชาร์จและ Wi-Fi beginBackgroundTask เองไม่มีวิธีการเพิ่มขีดจำกัด
ได้ iPadOS รองรับ beginBackgroundTask อย่างสมบูรณ์ด้วยข้อจำกัดเดียวกันกับ iOS บน iPad ที่มี Stage Manager แอปพลิเคชันอาจอยู่ในหน่วยความจำนานขึ้น — ระบบพักการทำงานของแอปพลิเคชันน้อยลงเนื่องจาก RAM ที่มากขึ้น แต่ขีดจำกัด 30 วินาทีสำหรับงานพื้นหลังยังคงอยู่
เชื่อมต่ออุปกรณ์กับ Xcode เปิดแอปพลิเคชัน ย่อขนาด — บันทึกของระบบจะปรากฏในคอนโซล ใช้ sysdiagnose เพื่อรวบรวมบันทึกโดยละเอียด: เรียก sysdiagnose จากอุปกรณ์โดยตรง (เพิ่มระดับเสียง + ลดระดับเสียง + เปิด/ปิด) ใน Xcode Debug Navigator ให้ตรวจสอบกิจกรรมของงานพื้นหลัง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม