MarketingCloudSDK iOSでリッチPush通知を送信する

#環境
・xcode Version 11.3.1 (11C504)
・swift Version 5.1.3
・MarketingCloudSDK iOS (v7.2.1)
・Mac OS 10.14.6(Mojave)
#準備
[MarketingCloudSDK iOSでシンプルなpush通知を送信する](https://qiita.com/techman/items/a136c903ea74f065b92c)
の続きとなります。
#リッチPushとは
push通知を開くと遷移したいurlに飛べたり、push通知に画像、動画などを表示することができる。
#リッチPush通知の実装
1.opendirect機能（ディープリンクとも呼ばれる）

```AppDelegate.swift
MarketingCloudSDK.sharedInstance().sfmc_setURLHandlingDelegate(self)
```
上記コードをSDKの初期設定記述の後に、AppDelegate.swift内に記述する。
その後、
`MarketingCloudSDKURLHandlingDelegate`プロトコルメソッドを追加

```AppDelegate.swift
extension AppDelegate: MarketingCloudSDKURLHandlingDelegate {
    func sfmc_handle(_ url: URL, type: String) {
        print(url)
        if UIApplication.shared.canOpenURL(url) == true {
            // ios 10.0以上
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: { success in
                    if success {
                        print("url \(url) opened successfully")
                    } else {
                        print("url \(url) could not be opened")
                    }
                })
            } else {
                if UIApplication.shared.openURL(url) == true {
                    print("url \(url) opened successfully")
                } else {
                    print("url \(url) could not be opened")
                }
            }
        }
    }
}
```
**※指定できるのは「:」を含むURL形式の値のみ**

2.push通知に画像、動画などを表示する

**xcode上でNotification Service Extensionを作成する**

File → New → target...を選択する
![スクリーンショット 2020-08-05 11.43.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246356/311a7421-a7c5-a8f9-3dc1-f8cf763a486c.png)
Notification Service Extensionを選択してNextをクリックする
![スクリーンショット_2020_08_05_11_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246356/8a1f3509-042b-cf2c-b6eb-a266023c6cc0.png)
productnameを入力してfinishボタンをクリックする
![スクリーンショット 2020-08-05 11.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246356/bc3714f9-7a95-34eb-00b7-9b8eaa853ce1.png)
上記のようなポップアップがでてきたら`Activate`をクリックする

**Notification Service Extensionの実装**
Notification Service Extensionのフォルダができるので、その中の`NotificationService.swift`に実装をしていく

実装イメージは下記となります

```AppDelegate.swift
/*
 * Copyright (c) 2017, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root  or https://opensource.org/licenses/BSD-3-Clause
 */

import CoreGraphics
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((_ contentToDeliver: UNNotificationContent) -> Void)? = nil
    var modifiedNotificationContent: UNMutableNotificationContent?

    func createMediaAttachment(_ localMediaUrl: URL) -> UNNotificationAttachment {
        // options: specify what cropping rectangle of the media to use for a thumbnail
        //          whether the thumbnail is hidden or not
        let clippingRect = CGRect.zero
        let mediaAttachment = try? UNNotificationAttachment(identifier: "attachmentIdentifier", url: localMediaUrl, options: [UNNotificationAttachmentOptionsThumbnailClippingRectKey: clippingRect.dictionaryRepresentation, UNNotificationAttachmentOptionsThumbnailHiddenKey: false])
        return mediaAttachment!
    }

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {

        // save the completion handler we will call back later
        self.contentHandler = contentHandler

        // make a copy of the notification so we can change it
        modifiedNotificationContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        // does the payload contains a remote URL to download or a local URL?
        if let mediaUrlString = request.content.userInfo["_mediaUrl"] as? String {
            // see if the media URL is for a local file  (i.e., file://movie.mp4)
            guard let mediaUrl = URL(string: mediaUrlString) else {
                // attempt to create a URL to a file in local storage
                var useAlternateText: Bool = true
                if mediaUrlString.isEmpty == false {
                    let mediaUrlFilename:NSString = mediaUrlString as NSString
                    let fileName = (mediaUrlFilename.lastPathComponent as NSString).deletingPathExtension
                    let fileExtension = (mediaUrlFilename.lastPathComponent as NSString).pathExtension

                    // is it in the bundle?
                    if let localMediaUrlPath = Bundle.main.path(forResource: fileName, ofType: fileExtension) {
                        // is the URL a local file URL?
                        let localMediaUrl = URL.init(fileURLWithPath: localMediaUrlPath)
                        if localMediaUrl.isFileURL == true {
                            // create an attachment with the local media
                            let mediaAttachment: UNNotificationAttachment? = createMediaAttachment(localMediaUrl)

                            // if no problems creating the attachment, we can use it
                            if mediaAttachment != nil {
                                // set the media to display in the notification
                                modifiedNotificationContent?.attachments = [mediaAttachment!]

                                // everything is ok
                                useAlternateText = false
                            }
                        }
                    }
                }

                // if any problems creating the attachment, use the alternate text if provided
                if (useAlternateText == true) {
                    if let mediaAltText = request.content.userInfo["_mediaAlt"] as? String {
                        if mediaAltText.isEmpty == false {
                            modifiedNotificationContent?.body = mediaAltText
                        }
                    }
                }

                // tell the OS we are done and here is the new content
                contentHandler(modifiedNotificationContent!)
                return
            }

            // if we have a URL, try to download media (i.e., https://media.giphy.com/media/3oz8xJBbCpzG9byZmU/giphy.gif)
            if mediaUrl.isFileURL == false {
                // create a session to handle downloading of the URL
                let session = URLSession(configuration: URLSessionConfiguration.default)

                // start a download task to handle the download of the media
                weak var weakSelf: NotificationService? = self
                session.downloadTask(with: mediaUrl, completionHandler: {(_ location: URL?, _ response: URLResponse?, _ error: Error?) -> Void in
                    var useAlternateText: Bool = true
                    // if the download succeeded, save it locally and then make an attachment
                    if error == nil {
                        let downloadResponse = response as! HTTPURLResponse
                        if (downloadResponse.statusCode >= 200 && downloadResponse.statusCode <= 299) {
                            // download was successful, attempt save the media file
                            let localMediaUrl = URL.init(fileURLWithPath: location!.path + mediaUrl.lastPathComponent)

                            // remove any existing file with the same name
                            try? FileManager.default.removeItem(at: localMediaUrl)

                            // move the downloaded file from the temporary location to a new file
                            if ((try? FileManager.default.moveItem(at: location!, to: localMediaUrl)) != nil) {
                                // create an attachment with the new file
                                let mediaAttachment: UNNotificationAttachment? = weakSelf?.createMediaAttachment(localMediaUrl)

                                // if no problems creating the attachment, we can use it
                                if mediaAttachment != nil {
                                    // set the media to display in the notification
                                    weakSelf?.modifiedNotificationContent?.attachments = [mediaAttachment!]

                                    // everything is ok
                                    useAlternateText = false
                                }
                            }
                        }
                    }

                    // なにか問題が起こり、代替テキストを設定している場合は代替テキストを表示
                    if (useAlternateText == true) {
                        if let mediaAltText = request.content.userInfo["_mediaAlt"] as? String {
                            if mediaAltText.isEmpty == false {
                                weakSelf?.modifiedNotificationContent?.body = mediaAltText
                            }
                        }
                    }

                    // tell the OS we are done and here is the new content
                    weakSelf?.contentHandler!((weakSelf?.modifiedNotificationContent)!)
                }).resume()
            }
        }
        else {
            // no media URL found in the payload, just pass on the orginal payload
            contentHandler(request.content)
            return
        }
    }

    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.
        // we took too long to download the media URL, use the alternate text if provided
        if let mediaAltText = modifiedNotificationContent?.userInfo["_mediaAlt"] as? String {
            // alternative text to display if there are any issues loading the media URL
            if mediaAltText.isEmpty == false {
                modifiedNotificationContent?.body = mediaAltText
            }
        }

        // 取得に失敗したときの処理
        contentHandler!(modifiedNotificationContent!)
    }
}

```
**※動画はmp4に対応**
#SMCからリッチPush通知を送信する
無事とどけばOK
#参考リンク（公式）
https://salesforce-marketingcloud.github.io/MarketingCloudSDK-iOS/sdk-implementation/implementation-urlhandling.html
https://salesforce-marketingcloud.github.io/MarketingCloudSDK-iOS/push-notifications/rich-notifications.html