12/08/2018, 16:54

Tạo Local & Remote Notification có Media Attachments với UserNotifications.

Từ iOS 10 Apple đã giới thiệu framework mới để giành cho việc xử lý cho notification đó là UserNotifications. Bài viết này sẽ tập trung vào làm thế nào để gửi Local & Remote Notification có Media Attachments. 1. Overview UNNotificationAttachment Là đối tượng chứa nội dung audio, image, và ...

Từ iOS 10 Apple đã giới thiệu framework mới để giành cho việc xử lý cho notification đó là UserNotifications. Bài viết này sẽ tập trung vào làm thế nào để gửi Local & Remote Notification có Media Attachments.

1. Overview UNNotificationAttachment

Là đối tượng chứa nội dung audio, image, và video để hiển thị bên cạnh nội dung thông báo. Được thêm vào UNMutableNotificationContent khi tạo notification. Hình ảnh bên dưới là những loại Media Attachments được hỗ trợ:

2. Local Notification

Sử dụng đoạn code sau để thêm UNNotificationAttachment vào notification của bạn:

        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = "framgia"
        notificationContent.body = "test notification"
        notificationContent.badge = 1
        notificationContent.subtitle = "div1"
        notificationContent.categoryIdentifier = "comment"
        if let path = Bundle.main.path(forResource: "test2", ofType: "jpg") {
            let url = URL(fileURLWithPath: path)
            do {
                let attachment = try UNNotificationAttachment(identifier: "logo", url: url, options: nil)
                notificationContent.attachments = [attachment]
            } catch {
                print("The attachment was not loaded.")
            }
        }
        notificationContent.sound = UNNotificationSound.default()
        let timeIntervalNotificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)

        let request = UNNotificationRequest(identifier: "test", content: notificationContent, trigger: timeIntervalNotificationTrigger)
        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)

Sau đây là kết quả:

2.Remote Notification

Với Local Notification thì việc thêm UNNotificationAttachment vào UNMutableNotificationContent khá đơn giản. Đối với Remote Notification làm thế nào để gửi notification có Media Attachments trong khi Remote Notification Payload maximum size chỉ là 4KB. Khi Apple giới thiệu framework UserNotifications đã sinh 2 Extension dùng để custom notification đó là:

  • Notification Content Extension: Dùng để custom UI của notification
  • Notification Service Extension: Dùng để custom nội dung của remote notification trước khi hiển thị cho user thấy.

Bài viết này sẽ sử dụng Notification Service Extension để gửi remote notification có Media Attachments. Đầu tiên vào File -> New ->Target rồi chọn Notification Service Extension như hình bên dưới:

Xem hình sau đây để thấy rõ hơn cách hoạt động của Notification Service Extension:

Để cho phép app sử dụng Notification Service Extension custom content thì bắt buộc thêm key "mutable-content : 1" vào payload như sau:

{
	"aps": {
		"alert": {
			"title": "title",
			"subtitle": "subtitle",
			"body": "Your message Here"
		},
		"mutable-content": 1
	},
	"video-url": "https://www.example.com/media/myvideo.m4a",
	"audio-url": "https://www.example.com/media/audio.mp3",
	"image-url": "https://www.example.com/media/image.jpg"
}

Trong Notification Service Extension cung cấp 2 func để xử lý việc nhận notification đó là:

  • didReceive(_:withContentHandler:): Được gọi khi đã nhận notification
  • serviceExtensionTimeWillExpire(): Được gọi khi việc xử lý notification không hoàn thành, nếu bạn không update notification content trước khi hết hạn thì hệ thống sẽ hiển thỉ nội dung ban đầu

Đoạn code sau đây parse data payload và download Media Attachments trong didReceive(_:withContentHandler::

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        bestAttemptContent?.categoryIdentifier = "like"
//        bestAttemptContent?.sound = UNNotificationSound.default()
//        print(bestAttemptContent)
//        print(bestAttemptContent?.userInfo)

        if let bestAttemptContent = bestAttemptContent {
            // Modify the notification content here...
            if let attachmentURL = bestAttemptContent.userInfo["image-url"] as? String, let url = URL(string: attachmentURL)  {
                //Download image
                downloadWithURL(url: url, completion: { (complete) in
                    contentHandler(bestAttemptContent)
                })
            } else {
                contentHandler(bestAttemptContent)
            }
        }
    }

Đoạn code sau đây để thực hiện việc download Media Attachments:

 private func downloadWithURL(url: URL, completion: @escaping (Bool) -> Void) {
        currentDownloadTask = URLSession.shared.downloadTask(with: url) { (downloadedUrl, _, error) in
            guard let downloadedUrl = downloadedUrl else {
                completion(false)
                return
            }
            
            let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
            let pathExtension = url.pathExtension
            var attachmentUrl = URL(fileURLWithPath: path)
                attachmentUrl = attachmentUrl.appendingPathComponent("test.(pathExtension)")

            try? FileManager.default.moveItem(at: downloadedUrl, to: attachmentUrl)
            
            do {
                let attachment = try UNNotificationAttachment(identifier: "image", url: attachmentUrl, options: nil)
                defer {
                    self.bestAttemptContent?.attachments = [attachment]
                    completion(true)
                }
            }
            catch {
                completion(true)
            }
        }
        currentDownloadTask?.resume()
    }

Đoạn code sau xử lý việc không hoàn thành download trước khi hết hạn:

override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
        currentDownloadTask?.cancel()
    }
0