Notification Service Extension เป็นส่วนขยายของ iOS ที่สกัดกั้นการแจ้งเตือนแบบพุชทันทีหลังจากได้รับ แต่ก่อนที่จะแสดงให้ผู้ใช้เห็น ส่วนขยายสามารถถอดรหัสเพย์โหลดที่เข้ารหัส ดาวน์โหลดและแนบไฟล์สื่อ และเปลี่ยนแปลงข้อความหรือหัวเรื่องการแจ้งเตือนแบบเรียลไทม์ ตามเอกสารสำหรับนักพัฒนาของ Apple (2025) ในการเปิดใช้งานส่วนขยาย เซิร์ฟเวอร์ต้องส่งคีย์ mutable-content:1 ในคุณสมบัติการแจ้งเตือน — นี่เป็นเงื่อนไขเดียวในการเริ่มต้น UNNotificationServiceExtension
ประเด็นสำคัญ
Notification Service Extension เป็นส่วนขยายของแอปใน iOS ที่สกัดกั้นการแจ้งเตือนแบบพุชที่ขาเข้าฝั่งอุปกรณ์และอนุญาตให้ปรับเปลี่ยนเนื้อหาก่อนที่ผู้ใช้จะเห็น นี่เป็นส่วนขยายการแจ้งเตือนประเภทเดียวที่ทำงานกับเนื้อหาแทนที่จะเป็นการแสดงผล
ความแตกต่างหลักจาก Notification Content Extension: Service Extension ทำงาน ก่อน การแสดงการแจ้งเตือนและสามารถเปลี่ยนหัวเรื่อง เนื้อหา ไฟล์เสียง และไฟล์แนบได้ Content Extension ทำงาน หลังจาก การแสดงและจัดการเฉพาะการนำเสนอด้วยภาพของการแจ้งเตือนที่เสร็จสมบูรณ์เท่านั้น ส่วนขยายทั้งสองนี้สามารถทำงานร่วมกันได้: Service Extension ดาวน์โหลดรูปภาพ และ Content Extension แสดงในอินเทอร์เฟซที่กำหนดเอง
ส่วนขยายจะเปิดใช้งานโดยอัตโนมัติเมื่อได้รับการแจ้งเตือนแบบพุชที่มีคุณสมบัติ mutable-content:1 ในพจนานุกรม aps iOS เริ่มต้นส่วนขยายในพื้นหลัง ส่ง UNNotificationRequest ดั้งเดิมให้ และรอเวอร์ชันที่ปรับเปลี่ยนแล้วเพื่อแสดง
UNNotificationServiceExtension ได้รับ UNNotificationRequest เต็มรูปแบบพร้อมเนื้อหาดั้งเดิม ส่วนขยายสามารถปรับเปลี่ยนฟิลด์ใด ๆ ของ UNNotificationContent: title, subtitle, body, userInfo, attachments และ sound การเปลี่ยนแปลงจะถูกนำไปใช้ก่อนที่จะแสดงการแจ้งเตือน
การถอดรหัสเนื้อหา — หากการแจ้งเตือนแบบพุชมีเพย์โหลดที่เข้ารหัส ส่วนขยายจะถอดรหัสก่อนแสดง การดาวน์โหลดสื่อ — การแนบรูปภาพหรือวิดีโอไปกับการแจ้งเตือน การแปลภาษา — การปรับข้อความการแจ้งเตือนให้เข้ากับการตั้งค่าภูมิภาคของอุปกรณ์ การเสริมข้อมูล — การเพิ่มข้อมูลเพิ่มเติมจากพื้นที่จัดเก็บในเครื่องหรือแคช
ตามข้อมูลของ Apple สถานการณ์ที่พบบ่อยที่สุดในแอปคือ การดาวน์โหลดรูปภาพ สำหรับการแจ้งเตือนสื่อสมบูรณ์ เซิร์ฟเวอร์ส่ง URL รูปภาพในเพย์โหลด ส่วนขยายดาวน์โหลดไปยังไดเรกทอรีชั่วคราวและสร้าง UNNotificationAttachment ซึ่งระบบจะแสดงในอินเทอร์เฟซมาตรฐานหรือกำหนดเอง
ส่วนขยายสามารถเขียนข้อความการแจ้งเตือนใหม่ทั้งหมด เปลี่ยนหัวเรื่อง หรือเพิ่มหัวเรื่องย่อย ตัวอย่างเช่น แอปส่งข้อความสามารถรับการแจ้งเตือนที่เข้ารหัส ถอดรหัสในส่วนขยาย และแสดงข้อความที่อ่านได้ หรือแอปข่าวสามารถเพิ่มหมวดหมู่ข่าวลงในหัวเรื่องย่อยก่อนแสดง
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
let content = request.content.mutableCopy()
as! UNMutableNotificationContent
if let imageURL = content.userInfo["media-url"]
as? String {
downloadAndAttach(imageURL: imageURL,
content: content,
handler: contentHandler)
}
}
UNNotificationServiceExtension เป็นคลาสพื้นฐานที่ Service Extension สืบทอด คลาสกำหนดเมธอดวงจรชีวิตสองแบบ: didReceive(_:withContentHandler:) — เมธอดการประมวลผลหลัก และ serviceExtensionTimeWillExpire() — ตัวจัดการการหมดเวลา
didReceive(_:withContentHandler:) ถูกเรียกเมื่อได้รับการแจ้งเตือน ส่วนขยายได้รับ UNNotificationRequest และคลอเชอร์ contentHandler ซึ่งต้องเรียกด้วย UNMutableNotificationContent ที่ปรับเปลี่ยนแล้ว ส่วนขยายมีหน้าที่เรียก contentHandler — หากไม่เรียก iOS จะแสดงการแจ้งเตือนดั้งเดิมหลังจากหมดเวลา
สำคัญ: ส่วนขยายสามารถประมวลผลได้เพียงหนึ่งการแจ้งเตือนในแต่ละครั้ง หากมีการแจ้งเตือนหลายรายการมาพร้อมกัน iOS จะสร้างอินสแตนซ์ส่วนขยายแยกต่างหากสำหรับแต่ละรายการ ไม่สามารถใช้สถานะส่วนกลางสำหรับการประมวลผลตามลำดับได้
serviceExtensionTimeWillExpire() ถูกเรียกโดยระบบเมื่อเวลาดำเนินการที่เหลืออยู่ใกล้จะหมด ในเมธอดนี้ คุณต้องเรียก contentHandler ทันทีด้วยเนื้อหาใด ๆ ที่พร้อมในขณะนั้น — แม้ว่าไฟล์สื่อจะยังดาวน์โหลดไม่เสร็จก็ตาม หากคุณไม่เรียก contentHandler ในเมธอดนี้ iOS จะแสดงการแจ้งเตือนดั้งเดิม
แนะนำให้บันทึกเนื้อหาที่ยอมรับได้น้อยที่สุดในเมธอดนี้ — ตัวอย่างเช่น การแจ้งเตือนที่มีข้อความและหัวเรื่อง แต่ไม่มีรูปภาพที่การดาวน์โหลดไม่เสร็จทันเวลา
UNNotificationAttachment เป็นออบเจ็กต์ที่สร้างโดยส่วนขยายเพื่อแนบไฟล์สื่อไปกับการแจ้งเตือน ส่วนขยายดาวน์โหลดไฟล์จากเครือข่าย บันทึกลงในไดเรกทอรีชั่วคราว และสร้าง UNNotificationAttachment พร้อมระบุประเภทเนื้อหา
UNNotificationAttachment ถูกสร้างโดยใช้ตัวเริ่มต้น init(identifier:url:options:) URL ต้องชี้ไปยังไฟล์ภายในเครื่องในไดเรกทอรีชั่วคราวที่ส่วนขยายสามารถเข้าถึงได้ หลังจากสร้าง ไฟล์แนบจะถูกเพิ่มไปยังอาร์เรย์ attachments ของ UNMutableNotificationContent
Apple แนะนำให้ใช้ URLSession พร้อมการกำหนดค่าพื้นหลังสำหรับการดาวน์โหลด — เมื่อใช้ URLSession มาตรฐาน การดาวน์โหลดจะบล็อกเธรดและใช้เวลาจากขีดจำกัด 30 วินาที URLSession พื้นหลังจะดาวน์โหลดต่อแม้เมื่อส่วนขยายสิ้นสุดลง และผลลัพธ์สามารถใช้ได้ในการเริ่มต้นครั้งต่อไป
หากเซิร์ฟเวอร์ส่งการแจ้งเตือนที่เข้ารหัส ส่วนขยายต้องถอดรหัสเพย์โหลดก่อนเรียก contentHandler การถอดรหัสมักเกี่ยวข้องกับการขอคีย์จาก Keychain หรือ App Group การถอดรหัสผ่าน CommonCrypto และการแทนที่ body หรือ userInfo ของการแจ้งเตือน ในกรณีที่เกิดข้อผิดพลาดในการถอดรหัส คุณควรเรียก contentHandler ด้วยเนื้อหาดั้งเดิม — เพื่อให้ผู้ใช้อย่างน้อยเห็นว่ามีการแจ้งเตือนมา แม้จะอ่านไม่ได้
func downloadAndAttach(
imageURL: String,
content: UNMutableNotificationContent,
handler: @escaping (UNNotificationContent) -> Void
) {
let task = URLSession.shared.dataTask(with:
URL(string: imageURL)!) { data, _, _ in
let url = FileManager.default
.temporaryDirectory
.appendingPathComponent("image.jpg")
try? data?.write(to: url)
let attachment = try? UNNotificationAttachment(
identifier: "image", url: url)
content.attachments = [attachment].compactMap { $0 }
handler(content)
}
task.resume()
}
Notification Service Extension ทำงานภายใต้กรอบเวลาที่เข้มงวด iOS จัดสรรเวลาดำเนินการคงที่ — ประมาณ 30 วินาที นับจากการเปิดใช้งาน หากส่วนขยายไม่ได้เรียก contentHandler ภายในเวลานี้ ระบบจะบังคับสิ้นสุดกระบวนการและแสดงการแจ้งเตือนดั้งเดิมโดยไม่เปลี่ยนแปลง
แนะนำให้ใช้กลไกสำรองหลายระดับ: ก่อนอื่นลองดาวน์โหลดสื่อ หากสำเร็จให้เรียก contentHandler ด้วยเนื้อหาเต็ม หากล้มเหลวให้เรียก contentHandler ด้วยข้อความแต่ไม่มีสื่อ หากเกิดข้อผิดพลาดร้ายแรงให้ส่งเนื้อหาดั้งเดิม วิธีการนี้รับประกันว่าผู้ใช้จะเห็นการแจ้งเตือนเสมอ ไม่ใช่หน้าจอว่างเปล่า
ตามข้อมูลของ Apple สาเหตุที่พบบ่อยที่สุดของการหมดเวลาคือ การดาวน์โหลดไฟล์สื่อขนาดใหญ่ ผ่านการเชื่อมต่อที่ช้า เพื่อลดความเสี่ยง แนะนำให้ปรับขนาดรูปภาพบนเซิร์ฟเวอร์ให้เหมาะสม — ส่งตัวอย่างสูงสุด 300 KB แทนความละเอียดเต็ม รูปภาพขนาดเต็มควรดาวน์โหลดเมื่อเปิดแอป
เพื่อติดตามการหมดเวลาและข้อผิดพลาดของส่วนขยาย คุณสามารถใช้ os_log เพื่อบันทึกข้อความวินิจฉัยในระบบบันทึกแบบรวม แม้ว่าการบันทึกไฟล์โดยตรงในส่วนขยายจะทำได้ยาก แต่ os_log ช่วยให้วิเคราะห์ประสิทธิภาพผ่าน Console.app บนอุปกรณ์ของนักพัฒนา Apple แนะนำให้เพิ่มเมตริกในทุกการเรียก didReceive — เวลาดาวน์โหลด ขนาดไฟล์ ผลลัพธ์การดำเนินการ
override func serviceExtensionTimeWillExpire() {
let fallback = bestEffortContent as?
UNMutableNotificationContent
?? request.content.mutableCopy()
as! UNMutableNotificationContent
contentHandler(fallback)
}
คำถามที่พบบ่อย
เซิร์ฟเวอร์เพิ่มคีย์ mutable-content:1 ลงในพจนานุกรม aps ของการแจ้งเตือนแบบพุช หากไม่มีพารามิเตอร์นี้ ระบบจะละเว้นส่วนขยายและแสดงการแจ้งเตือนมาตรฐาน
ไม่ได้ mutable-content:1 เป็นเงื่อนไขบังคับสำหรับการเปิดใช้งาน Service Extension หากคีย์หายไปหรือตั้งค่าเป็น 0 การแจ้งเตือนจะแสดงโดยไม่เรียกส่วนขยาย
iOS บังคับสิ้นสุดส่วนขยายและแสดง การแจ้งเตือนดั้งเดิม โดยไม่เปลี่ยนแปลง เพื่อหลีกเลี่ยงนี้ ให้ใช้ serviceExtensionTimeWillExpire() ด้วยเนื้อหาที่ยอมรับได้น้อยที่สุด
ผ่าน App Group (UserDefaults หรือไฟล์ที่ใช้ร่วมกัน) หรือ Keychain ที่มีการเข้าถึงร่วมกันระหว่างแอปและส่วนขยาย การส่งคีย์โดยตรงในเพย์โหลดการแจ้งเตือนไม่ปลอดภัย
สูงสุด 4 ไฟล์แนบ ต่อการแจ้งเตือน แต่ละไฟล์สูงสุด 50 MB ขนาดรวมของไฟล์แนบส่งผลต่อเวลาดาวน์โหลด — ยิ่งมีไฟล์มาก ความเสี่ยงในการหมดเวลาก็ยิ่งสูงขึ้น
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม