Notification Extension เป็นกลไกของ iOS ที่ช่วยให้สามารถปรับเปลี่ยนเนื้อหาและลักษณะของการแจ้งเตือนแบบพุชก่อนที่จะแสดงให้ผู้ใช้เห็น ส่วนขยายทำงานบนฝั่งระบบปฏิบัติการในกระบวนการแยกต่างหาก: UNNotificationServiceExtension ประมวลผลเนื้อหาที่เข้ามา ในขณะที่ UNNotificationContentExtension จัดการอินเทอร์เฟซ ตาม Apple Developer Documentation, 2026 Service Extension มีเวลาสูงสุด 30 วินาทีในการทำงานก่อนที่จะแสดงการแจ้งเตือน ข้อจำกัดนี้มีความสำคัญเมื่อดาวน์โหลดไฟล์แนบหรือถอดรหัสข้อมูล
ประเด็นสำคัญ
Notification Extension เป็นส่วนประกอบซอฟต์แวร์ของ iOS ที่ขยายพฤติกรรมมาตรฐานของการแจ้งเตือนแบบพุชโดยเพิ่มความสามารถในการปรับเปลี่ยนเนื้อหาและปรับแต่งอินเทอร์เฟซ ซึ่งแตกต่างจากการแจ้งเตือนทั่วไปที่ระบบแสดงในรูปแบบมาตรฐาน ส่วนขยายช่วยให้นักพัฒนาสามารถมีอิทธิพลต่อเนื้อหาก่อนแสดงและสร้างอินเทอร์เฟซผู้ใช้ที่ไม่ซ้ำใคร
Apple มีส่วนขยายการแจ้งเตือนสองประเภทสำหรับวัตถุประสงค์ที่แตกต่างกัน: UNNotificationServiceExtension รับผิดชอบการประมวลผลเพย์โหลดที่เข้ามา ในขณะที่ UNNotificationContentExtension จัดการการแสดงผล Service Extension ทำงานก่อนที่จะแสดงการแจ้งเตือนและมีเวลาดำเนินการจำกัด — สูงสุด 30 วินาทีตาม Apple Developer Documentation Content Extension จะทำงานหลังจากที่ผู้ใช้โต้ตอบกับการแจ้งเตือนและแสดงมุมมองที่กำหนดเอง
การแจ้งเตือนแบบพุชมาตรฐานของ iOS จะแสดงโดยระบบโดยอัตโนมัติตามฟิลด์ alert, title และ subtitle จากเพย์โหลด JSON Notification Extension ดักจับการควบคุม: Service Extension รับเพย์โหลดดิบ ปรับเปลี่ยน และส่งต่อให้ระบบแสดงผล Content Extension แทนที่แบนเนอร์มาตรฐานด้วยอินเทอร์เฟซที่กำหนดเองพร้อมองค์ประกอบควบคุมใด ๆ
เมื่ออุปกรณ์ได้รับการแจ้งเตือนแบบพุชที่มีคีย์ mutable-content: 1 ระบบจะเริ่ม Service Extension ในกระบวนการแยกต่างหาก กระบวนการส่วนขยาย ถูกแยกออกจากแอปพลิเคชันหลักและมีแซนด์บ็อกซ์ของตัวเองด้วยขีดจำกัดหน่วยความจำ 50 MB หลังจากประมวลผลเสร็จ ส่วนขยายจะเรียก completion handler ส่ง UNNotificationContent ที่ปรับเปลี่ยนแล้วให้ระบบแสดงผล
UNNotificationServiceExtension เป็นเครื่องมือหลักสำหรับปรับเปลี่ยนการแจ้งเตือนแบบพุชโดยทางโปรแกรมก่อนที่จะแสดงให้ผู้ใช้เห็น ส่วนขยายจะทำงานโดยอัตโนมัติเมื่อได้รับการแจ้งเตือนที่มีเพย์โหลดตั้งค่าแฟล็ก mutable-content: 1 ไว้ ภายใน 30 วินาที ส่วนขยายสามารถดาวน์โหลดไฟล์แนบสื่อ เปลี่ยนข้อความ ถอดรหัสข้อมูลที่เข้ารหัส หรือเสริมสร้างเนื้อหา
ส่วนขยายimplement เมธอดสำคัญสองเมธอดจากโปรโตคอล UNNotificationServiceExtension เมธอด didReceive รับคำขอที่เข้ามาพร้อม UNNotificationRequest ดิบและอนุญาตให้ปรับเปลี่ยนผ่าน completion handler ด้วย UNNotificationContent ใหม่ เมธอด serviceExtensionTimeWillExpire ถูกเรียกโดยระบบหนึ่งวินาทีก่อนหมดเวลา — ในเมธอดนี้คุณต้องเสร็จสิ้นการประมวลผลและส่งผลลัพธ์ปัจจุบัน (อาจเป็นบางส่วน)
พิจารณาสถานการณ์ที่เซิร์ฟเวอร์ส่งพุชพร้อม URL รูปภาพในฟิลด์ที่กำหนดเอง Service Extension ดาวน์โหลดรูปภาพนี้ผ่านเครือข่าย สร้าง UNNotificationAttachment และเพิ่มลงในเนื้อหา UNNotificationAttachment รับไฟล์รูปภาพ วิดีโอ หรือเสียงในเครื่องและคัดลอกไปยังแซนด์บ็อกซ์ของส่วนขยายโดยอัตโนมัติ หลังจากสร้างไฟล์แนบ ส่วนขยายจะส่งเนื้อหาที่อัปเดตให้ระบบ
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void) {
let userInfo = request.content.userInfo
guard let imageURL = URL(string: userInfo["image-url"] as! String)
else { contentHandler(request.content); return }
let attachment = try! UNNotificationAttachment(
identifier: "image", url: imageURL,
options: [UNNotificationAttachmentOptionsTypeHintKey: "jpg"])
let modifiedContent = request.content.mutableCopy()
as! UNMutableNotificationContent
modifiedContent.attachments = [attachment]
contentHandler(modifiedContent)
}
override func serviceExtensionTimeWillExpire() {
contentHandler?(bestAttemptContent ?? request.content)
}
}
เมื่อส่งการแจ้งเตือนที่มีไฟล์แนบเดียวกันบ่อยครั้ง ควรแคชไฟล์ที่ดาวน์โหลดไว้ในอุปกรณ์ FileManager ให้การเข้าถึงไดเรกทอรีแคชของส่วนขยาย ซึ่งคงอยู่ระหว่างการเริ่มต้นใช้งาน ซึ่งช่วยลดเวลาการประมวลผลสำหรับการแจ้งเตือนครั้งต่อไปและลดภาระเครือข่าย ตาม Apple การแคชสามารถลดเวลาการประมวลผลเหลือ 2–5 วินาทีแทนการดาวน์โหลดเต็มรูปแบบ
UNNotificationContentExtension ช่วยให้แทนที่แบนเนอร์การแจ้งเตือนมาตรฐานด้วยอินเทอร์เฟซที่กำหนดเองซึ่งสร้างใน Interface Builder หรือ SwiftUI ส่วนขยายจะทำงานเมื่อผู้ใช้ดำเนินการกับการแจ้งเตือน: การแตะ การปัดลง หรือ 3D Touch Content Extension รับเนื้อหาที่ประมวลผลแล้วโดย Service Extension และแสดงในมุมมองที่กำหนดเอง
แต่ละ Content Extension เชื่อมโยงกับหมวดหมู่การแจ้งเตือนหนึ่งหมวดหมู่ขึ้นไปผ่าน Info.plist หมวดหมู่ ถูกกำหนดบนเซิร์ฟเวอร์โดยฟิลด์ category ในเพย์โหลด APNS ระบบจะเลือกส่วนขยายที่เหมาะสมโดยอัตโนมัติตามหมวดหมู่ของการแจ้งเตือนที่ได้รับ อินเทอร์เฟซสร้างผ่าน storyboard โดยใช้คอมโพเนนต์ UIKit มาตรฐานหรือ SwiftUI View
Content Extension รองรับปุ่มที่กำหนดเองและตัวจัดการการแตะที่กำหนดใน UNNotificationAction UNNotificationAction ถูกสร้างขึ้นในขั้นตอนการลงทะเบียนหมวดหมู่และสามารถรองรับการป้อนข้อความผ่าน UNTextInputNotificationAction เมื่อผู้ใช้กดปุ่ม ส่วนขยายจะได้รับ callback didReceive พร้อมตัวระบุการกระทำและสามารถดำเนินการตรรกะที่เกี่ยวข้อง — เปิด URL ส่งคำขอไปยังเซิร์ฟเวอร์ หรืออัปเดตอินเทอร์เฟซ
Content Extension ทำงานในกระบวนการที่แยกออกมาพร้อมลูปการทำงานของตัวเองและขีดจำกัดหน่วยความจำประมาณ 50 MB ประสิทธิภาพของส่วนขยาย มีความสำคัญเนื่องจาก watchdogs ของระบบจะยุติกระบวนการเมื่อเกินขีดจำกัด ควรหลีกเลี่ยงการคำนวณที่หนัก การโหลดรูปภาพขนาดใหญ่ และคำขอเครือข่ายที่ยาวนานภายใน Content Extension
UNNotificationAttachment เป็นออบเจ็กต์ที่เพิ่มไฟล์สื่อให้กับการแจ้งเตือนแบบพุช: รูปภาพ วิดีโอ เสียง หรือ GIF ไฟล์แนบถูกสร้างจาก URL ไฟล์ในเครื่องที่ต้องอยู่ในแซนด์บ็อกซ์ของส่วนขยาย ขนาดสูงสุดของไฟล์แนบต้องไม่เกิน 10 MB มิฉะนั้นระบบจะปฏิเสธไฟล์แนบเมื่อสร้าง
Apple รองรับรูปแบบที่จำกัดสำหรับไฟล์แนบสื่อ รูปภาพ — JPEG, PNG, GIF (รวมถึงแบบเคลื่อนไหว), TIFF วิดีโอ — MPEG, MP4, MOV ที่มีความยาวสูงสุด 30 วินาที เสียง — MP3, AAC, WAV, CAF สำหรับแต่ละรูปแบบสามารถระบุประเภทผ่าน UNNotificationAttachmentOptionsTypeHintKey ซึ่งช่วยให้ระบบประมวลผลไฟล์ได้อย่างถูกต้อง
เนื่องจากเพย์โหลดพุชมีเพียง URL ไม่ใช่ไฟล์เอง การดาวน์โหลดไฟล์แนบต้องทำภายใน Service Extension เวลาดาวน์โหลดสูงสุด จำกัดอยู่ที่ 30 วินาที ดังนั้นควรใช้ URLSession ด้วยการตั้งค่าน้อยที่สุดและปิดการดาวน์โหลดเมื่อสัญญาณอ่อน หากไฟล์แนบไม่โหลดทันเวลา การแจ้งเตือนจะแสดงโดยไม่มีสื่อ — นี่คือพฤติกรรมเริ่มต้นของระบบ
มาดูตัวอย่าง Notification Extension แบบสมบูรณ์ที่ดาวน์โหลดรูปภาพ บันทึก และเพิ่มในการแจ้งเตือน NotificationService สืบทอดจาก UNNotificationServiceExtension และแทนที่เมธอด didReceive ตัวอย่างแสดงการจัดการฟิลด์ที่เป็นทางเลือก การสร้างไฟล์แนบ และการเรียก completion handler ด้วยเนื้อหาที่ปรับเปลี่ยน
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
self.bestAttemptContent =
(request.content.mutableCopy()
as! UNMutableNotificationContent)
guard let attachmentURLString =
bestAttemptContent?.userInfo["attachment-url"] as? String,
let url = URL(string: attachmentURLString)
else {
contentHandler(request.content)
return
}
URLSession.shared.downloadTask(with: url) {
[weak self] localURL, _, error in
guard let localURL = localURL, error == nil
else {
contentHandler(request.content)
return
}
let attachment = try! UNNotificationAttachment(
identifier: "media", url: localURL)
self?.bestAttemptContent?.attachments = [attachment]
contentHandler(self?.bestAttemptContent
?? request.content)
}.resume()
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}
เพื่อให้ส่วนขยายทำงานได้อย่างถูกต้อง จำเป็นต้องลงทะเบียนหมวดหมู่การแจ้งเตือนใน Info.plist คีย์ NSExtensionPointIdentifier ถูกตั้งค่าเป็น com.apple.usernotifications.service สำหรับ Service Extension หรือ com.apple.usernotifications.content สำหรับ Content Extension หมวดหมู่ถูกกำหนดใน AppDelegate เมื่อเริ่มต้นแอปพลิเคชันผ่าน UNUserNotificationCenter และส่วนขยายจะทำงานเฉพาะสำหรับการแจ้งเตือนที่มีหมวดหมู่ตรงกันในเพย์โหลด
คำถามที่พบบ่อย
Service Extension ปรับเปลี่ยนเนื้อหาก่อนแสดงการแจ้งเตือน — เพิ่มสื่อ เปลี่ยนข้อความ ถอดรหัสข้อมูล Content Extension แทนที่อินเทอร์เฟซการแจ้งเตือนด้วยอินเทอร์เฟซที่กำหนดเองหลังจากผู้ใช้โต้ตอบ Service Extension ทำงานก่อนแสดง Content Extension ทำงานหลังจากนั้น
ระบบจัดสรร 30 วินาที สำหรับการดำเนินการโค้ดใน didReceive หากการประมวลผลไม่เสร็จภายในเวลานี้ จะเรียก serviceExtensionTimeWillExpire ซึ่งคุณต้องส่งผลลัพธ์ปัจจุบัน ควรอยู่ใน 10–15 วินาทีโดยคำนึงถึงการดาวน์โหลดไฟล์แนบ
ได้ SwiftUI รองรับใน Content Extension ตั้งแต่ iOS 16 เป็นต้นไป View จะถูกห่อใน UIHostingController และเพิ่มใน storyboard อย่างไรก็ตาม เนื่องจากข้อจำกัดด้านหน่วยความจำ ควรใช้ SwiftUI สำหรับอินเทอร์เฟซที่เรียบง่ายที่มีองค์ประกอบน้อยที่สุดเท่านั้น
ในกรณีที่เกิดข้อผิดพลาดในการดาวน์โหลดหรือหมดเวลา เพียงเรียก completion handler ด้วยเนื้อหาต้นฉบับโดยไม่มีไฟล์แนบ ระบบจะแสดงการแจ้งเตือน ในรูปแบบมาตรฐานโดยไม่มีสื่อ บันทึกข้อผิดพลาดผ่าน OSLog เพื่อการวินิจฉัย แต่อย่าปิดกั้นการแสดงการแจ้งเตือน
ส่วนขยายทำงานในกระบวนการที่แยกออกมาด้วยขีดจำกัดประมาณ 50 MB เมื่อเกิน ระบบจะยุติกระบวนการผ่าน watchdogs หลีกเลี่ยงการโหลดไฟล์ขนาดใหญ่ การเก็บรูปภาพในหน่วยความจำ และการรั่วไหลเมื่อทำงานกับ URLSession
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม