Notification Service Extension เป็นส่วนขยายของ iOS ที่สกัดกั้นการแจ้งเตือนแบบ push ก่อนที่จะแสดงให้ผู้ใช้เห็น และอนุญาตให้ปรับเปลี่ยนเนื้อหา ส่วนขยายสามารถถอดรหัสข้อมูลที่เข้ารหัส ดาวน์โหลดไฟล์แนบสื่อ เปลี่ยนข้อความ หรือเพิ่มฟิลด์ที่กำหนดเอง ตาม Apple Developer, 2025 Notification Service Extension มีเวลาสูงสุด 30 วินาทีในการทำงานเบื้องหลังให้เสร็จ
ประเด็นสำคัญ
Notification Service Extension เป็นส่วนขยายแอปใน iOS ที่ทำงานก่อนการแสดงการแจ้งเตือนแบบ push ช่วยให้เซิร์ฟเวอร์ส่ง payload ขั้นต่ำในขณะที่ส่วนขยายเพิ่มเนื้อหาให้สมบูรณ์: ดาวน์โหลดรูปภาพ ถอดรหัสข้อมูล เปลี่ยนข้อความ ผู้ใช้เห็นการแจ้งเตือนที่ประมวลผลแล้ว
เมื่อ iOS ได้รับการแจ้งเตือนแบบ push ระบบจะตรวจสอบว่ามีส่วนขยายสำหรับแอปหรือไม่ หากส่วนขยายถูกลงทะเบียน iOS จะเริ่มทำงานในกระบวนการเบื้องหลังและส่งเนื้อหาการแจ้งเตือนผ่านเมธอด didReceive(_:withContentHandler:) ส่วนขยายประมวลผลเนื้อหาและเรียก contentHandler ด้วยเนื้อหาที่ปรับเปลี่ยนแล้ว หากส่วนขยายไม่เสร็จภายใน 30 วินาที ระบบจะแสดงการแจ้งเตือนต้นฉบับ
Service Extension จำเป็นในสถานการณ์ที่เนื้อหาการแจ้งเตือนต้องการการประมวลผลบนอุปกรณ์ การสื่อสารที่ปลอดภัย: เซิร์ฟเวอร์ส่ง payload ที่เข้ารหัส ส่วนขยายถอดรหัสในเครื่อง การแจ้งเตือนสื่อสมบูรณ์: เซิร์ฟเวอร์ส่ง URL รูปภาพ ส่วนขยายดาวน์โหลดและแนบ การแปลภาษาแบบไดนามิก: ส่วนขยายแทนที่ข้อความด้วยภาษาของอุปกรณ์
| สถานการณ์ | ไม่มีส่วนขยาย | มีส่วนขยาย |
|---|---|---|
| รูปภาพ | ไม่รองรับ | ดาวน์โหลดและแสดง |
| การเข้ารหัส | เซิร์ฟเวอร์เก็บคีย์ | ถอดรหัสบนอุปกรณ์ |
| ข้อความ | กำหนดตายตัวบนเซิร์ฟเวอร์ | แทนที่แบบไดนามิก |
| การตรวจสอบ | ไม่ตรวจสอบ | ยกเลิกการแจ้งเตือนที่เป็นอันตราย |
Notification Service Extension ทำงานในสภาพแวดล้อมที่จำกัด เวลาทำงานสูงสุดคือ 30 วินาที ส่วนขยายไม่สามารถเข้าถึงพื้นที่เก็บข้อมูลหลักของแอป (ยกเว้น App Group) ขนาดของส่วนขยายจำกัดที่ 50 MB เมื่อเกินเวลา ระบบจะเรียก contentHandler ด้วยเนื้อหาต้นฉบับและการเปลี่ยนแปลงทั้งหมดจะสูญหาย
ใน Xcode การเพิ่ม Notification Service Extension ทำได้โดยสร้าง target ใหม่ชนิด Notification Service Extension Xcode สร้างคลาสเทมเพลต NotificationService ที่สืบทอดจาก UNNotificationServiceExtension พร้อมสองเมธอด: didReceive และ serviceExtensionTimeWillExpire
ใน Xcode เลือก File → New → Target → Notification Service Extension ระบุชื่อ (เช่น PushNotificationService) และเลือกภาษา Swift ตรวจสอบว่า target ถูกเพิ่มในแอปหลักและมีลายเซ็นที่ถูกต้อง หลังจากสร้าง คลาส NotificationService.swift จะถูกสร้างพร้อมการใช้งานพื้นฐาน
Info.plist ของส่วนขยายประกอบด้วยคีย์ NSExtension พร้อมคีย์ย่อย NSExtensionPointIdentifier (com.apple.usernotifications.service) และ NSExtensionPrincipalClass (ชื่อคอนโทรลเลอร์ของคุณ) นอกจากนี้สามารถระบุ NSExtensionAttributes พร้อมกฎการเปิดใช้งานส่วนขยาย Xcode สร้างการตั้งค่าเหล่านี้โดยอัตโนมัติ
การใช้งานพื้นฐานเขียนทับ didReceive ปรับเปลี่ยนเนื้อหาการแจ้งเตือนและเรียก contentHandler หากการประมวลผลใช้เวลานานเกินไป serviceExtensionTimeWillExpire จะถูกเรียก ซึ่งคุณต้องทำงานให้เสร็จด้วยสถานะปัจจุบัน
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
contentHandler = handler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "[ประมวลผลแล้ว] \(bestAttemptContent.title)"
contentHandler?(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
หนึ่งในการใช้งานหลักของ Service Extension คือการ ถอดรหัส เนื้อหาการแจ้งเตือนบนอุปกรณ์ เซิร์ฟเวอร์ส่ง payload ที่เข้ารหัสและส่วนขยายถอดรหัสโดยใช้คีย์ที่เก็บใน Keychain หรือ App Group ซึ่งรับประกันว่าเนื้อหาจะไม่ถูกสกัดกั้นระหว่างการส่ง
เซิร์ฟเวอร์เข้ารหัสเนื้อหาการแจ้งเตือนโดยใช้คีย์สมมาตร (AES-256) คีย์การเข้ารหัสถูกตกลงล่วงหน้าระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ ส่วนขยายรับสตริงที่เข้ารหัสในฟิลด์ data ของpayload ถอดรหัสและแทนที่ในฟิลด์การแจ้งเตือน คีย์ผู้ใช้ สามารถรับได้จาก Keychain หลังจากการยืนยันตัวตน
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
guard let content = request.content.mutableCopy()
as? UNMutableNotificationContent else {
handler(request.content)
return
}
guard let encryptedData = content.userInfo["encrypted_data"]
as? String else {
handler(content)
return
}
let decrypted = CryptoService.decrypt(encryptedData)
content.body = decrypted.body
content.title = decrypted.title
handler(content)
}
ไม่ควรเก็บคีย์ถอดรหัสในโค้ดส่วนขยายหรือ NSUserDefaults ใช้ iOS Keychain ที่สามารถเข้าถึงผ่าน App Group เพื่อให้ทั้งแอปและส่วนขยายสามารถอ่านคีย์ได้ ใช้ Security.framework กับอัลกอริทึม AES-256-GCM สำหรับการสร้างคีย์บนไคลเอ็นต์
การใช้งานที่พบบ่อยที่สุดของ Notification Service Extension คือการดาวน์โหลดรูปภาพ GIF และวิดีโอเพื่อแสดงในการแจ้งเตือน เซิร์ฟเวอร์ส่ง URL ไฟล์สื่อและส่วนขยายดาวน์โหลด บันทึกในไดเรกทอรีชั่วคราว และสร้าง UNNotificationAttachment
ส่วนขยายรับ URL รูปภาพจากฟิลด์ payload ของการแจ้งเตือน ใช้ URLSession ส่วนขยายดาวน์โหลดไฟล์ไปยังไดเรกทอรีชั่วคราว เมื่อดาวน์โหลดเสร็จ จะสร้าง UNNotificationAttachment พร้อม URL ในเครื่อง ไฟล์แนบจะถูกส่งไปยังเนื้อหาที่ปรับเปลี่ยนแล้ว iOS จะแสดง รูปภาพในอินเทอร์เฟซมาตรฐานหรือใน Notification Content Extension โดยอัตโนมัติ
private func downloadAndAttachMedia(
content: UNMutableNotificationContent,
mediaUrl: String,
handler: @escaping (UNNotificationContent) -> Void
) {
guard let url = URL(string: mediaUrl) else {
handler(content)
return
}
let task = URLSession.shared.downloadTask(with: url) { localUrl, _, error in
guard let localUrl = localUrl, error == nil else {
handler(content)
return
}
let attachment = try? UNNotificationAttachment(
identifier: "media",
url: localUrl,
options: nil
)
if let attachment = attachment {
content.attachments = [attachment]
}
handler(content)
}
task.resume()
}
iOS รองรับรูปแบบต่อไปนี้สำหรับแสดงในการแจ้งเตือน: JPEG, PNG, GIF (นิ่ง), วิดีโอ MPEG-4 สูงสุด 50 MB สำหรับไฟล์เสียง รองรับ MP3, AAC และ ALAC สำคัญ: ไฟล์สื่อทั้งหมดต้องดาวน์โหลดภายใน 30 วินาที สำหรับไฟล์ขนาดใหญ่ แนะนำให้ตัดฝั่งเซิร์ฟเวอร์หรือโหลดแบบก้าวหน้า
การจัดการขีดจำกัด 30 วินาที เป็นงานสำคัญเมื่อพัฒนา Notification Service Extension หากส่วนขยายไม่ประมวลผลเสร็จทันเวลา ระบบจะเรียก serviceExtensionTimeWillExpire และแสดงเนื้อหาต้นฉบับ ต้องเตรียมสถานการณ์สำรองสำหรับการประมวลผลแต่ละประเภท
แบ่งงานตามลำดับความสำคัญ ดำเนินการปรับเปลี่ยนที่สำคัญก่อน (ถอดรหัส การแปลพื้นฐาน) การปรับปรุงเพิ่มเติม (ดาวน์โหลดรูปภาพ เพิ่มข้อความ) ทำทีหลัง ใช้ URLSession กับหมดเวลา สำหรับคำขอเครือข่ายเพื่อไม่ให้ใช้ขีดจำกัดทั้งหมดกับการดำเนินการเดียว
หากดาวน์โหลดรูปภาพล้มเหลวหรือถอดรหัส payload คืนค่าข้อผิดพลาด ส่วนขยายควรเรียก contentHandler ด้วยเนื้อหาต้นฉบับ อย่ายุติส่วนขยายโดยไม่เรียก contentHandler — จะทำให้สูญเสียการแจ้งเตือน การสำรองที่ปลอดภัย ควรรวมอยู่ในโค้ดส่วนขยายเสมอ
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
let content = (request.content.mutableCopy()
as? UNMutableNotificationContent) ?? request.content
// งานสำคัญ: ถอดรหัส
var decryptedContent = tryDecryptPayload(content)
// งานเสริม: สื่อ
guard let mediaUrl = decryptedContent.userInfo["media_url"]
as? String else {
handler(decryptedContent)
return
}
downloadAndAttachMedia(
content: decryptedContent,
mediaUrl: mediaUrl,
handler: handler
)
}
ในการทดสอบ Notification Service Extension ให้ใช้ Xcode: เลือก target ส่วนขยาย เรียกใช้บนซิมูเลเตอร์ และส่งการแจ้งเตือนแบบ push ผ่านเทอร์มินัลหรือ Firebase Console บันทึก แต่ละขั้นตอนการประมวลผลโดยใช้ os_log — ซึ่งช่วยวินิจฉัยปัญหาด้านเวลาและการดาวน์โหลด
คำถามที่พบบ่อย
ระบบจะเรียก serviceExtensionTimeWillExpire จากนั้นแสดงการแจ้งเตือนต้นฉบับโดยไม่เปลี่ยนแปลง ไฟล์ที่ดาวน์โหลดและการปรับเปลี่ยนทั้งหมดจะถูกยกเลิก
ได้ หากคุณเรียก contentHandler ด้วยเนื้อหาว่าง (UNNotificationContent ที่มีฟิลด์ว่าง) การแจ้งเตือนจะไม่ถูกแสดง ใช้สำหรับกรอง การแจ้งเตือนสแปม หรือข้อมูลที่ไม่ถูกต้อง
โทเคนสามารถส่งใน userInfo ของ payload การแจ้งเตือนหรือรับจาก Keychain ผ่าน App Group ไม่แนะนำให้เก็บโทเคนใน UserDefaults ของส่วนขยาย
ส่วนขยายต้องลงนามด้วยใบรับรองนักพัฒนาชุดเดียวกับแอปหลัก สำหรับการผลิต ต้องใช้ ใบรับรองการผลิต ที่เปิดใช้งานความสามารถ Push Notifications
เชื่อมต่ออุปกรณ์กับ Xcode เลือก target ส่วนขยายในสคีมาการทำงาน และส่งการแจ้งเตือนแบบ push ผ่าน Firebase Console จุดเบรก ในส่วนขยายทำงานเหมือนกับในแอปหลัก
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม