iOS 10 來點不一樣的推送

劉小蠻發表於2017-05-20

簡介

iOS 10 中新增的通知服務擴充套件功能,在推送通知展示到介面之前提供開發者可以在後臺對推送的內容進行修改
通過這個修改主要可以實現以下的幾個需求:

  • 如果推送的內容加密的,可以在客戶端進行解密。
  • 可以下載圖片,音樂,視訊,實現多媒體推送的效果。
  • 可以修改推送的內容,body ,titile ,subtitle 等。(這裡可以用來實現一些定製化的需求,服務端統一推送,各自修改)
  • 可以修改自己增加的 userinfo 的 dictionary。

說白了就是在收到蘋果推送的時候,會觸發你的
這是官方給出的注意點:

  • 1.Include the mutable-content key with a value of 1.
    一定要有 mutable-content 這個欄位並且值為 1,不然是不會執行你的 extsion 的。

    我測試了改為0,或者不加這個欄位並不會執行本地的修改

  • 2.Include an alert dictionary with subkeys for the title and body of the alert.
    要有一個 alert 的 dictionary 包含 title 和 body 的鍵值。

    如果沒有 alert 的話,預設會當做一個 slient notification

Let's Start !

這裡主要分為兩種實現方式:本地和遠端。其實不管本地推送還是遠端推送,對 app 本身其實是一致的。
主要講一下遠端的實現方式,因為這個的實際運用性更強一點,不過由於涉及到推送證照的緣故在 demo 中可能不好體現,最後我會給出本地推送的 demo 供大家測試。

基礎推送實現

這裡我就不展開了,要運用修改推送的功能前提是你的 app 要已經有了推送能力。
主要以下幾個注意點:

  • 在 developer center 申請證照
  • 在 application 中申請推送的許可權
  • 拿到 device Token 交給伺服器的兄弟

這裡推薦用 SmartPush 來本地測試本地推送,文章最後會介紹。
當服務端已經能愉快的給你推送的訊息的時候,我們開始下一步。

新建 extison

對 notification 的修改是作為一個 extison 的存在,並不是在你的 app 的 target 中增加一個 class 的事情,而是新建了一個 target。

  • 選中 File -> New -> Target
  • 選擇 Notification Service Extension
  • 選擇名字和相關資訊
    iOS 10 來點不一樣的推送

Xcode 會自動幫你配置好一切,然後會生成一個

NotificationService 的類
會幫你實現兩個方法

  • (void)didReceiveNotificationRequest:(UNNotificationRequest )request withContentHandler:(void (^)(UNNotificationContent _Nonnull))contentHandler

    收到推送時會觸發的方法,給你一個 block 用來回撥最終修改後的 Notification

  • (void)serviceExtensionTimeWillExpire

    這個是這次 Service 執行時間到期時候的給你最後的通知(基礎 後臺拉取服務,通常的時間上限是 30s),相當是最後通牒,若你上面的下載操作還沒完成,系統會最後詢問你一次是不是要對內容修改,這裡是你超時情況下最後的處理機會。

程式碼實現

這裡就直接貼程式碼吧,其實內容很簡單,具體的流程會在註釋中說明:
這裡用了簡單的一個 DownloadTask 來實現下載,其實如果是大檔案或者多資源的話可以好好利用這個 30 秒進行下載。

#import "NotificationService.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic,strong) NSURLSessionDownloadTask *downLoadTask;//下載的task 用於取消

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {

    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    // Modify the notification content here...
    // self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];

    //以上程式碼均有系統自動生成

    //獲取下載的資源地址 這裡和服務端約定好即可
    NSString *url = request.content.userInfo[@"attach"];
    NSURL *nsurl = [NSURL URLWithString:url];

    //開始下載
    self.downLoadTask = [[NSURLSession sharedSession] downloadTaskWithURL:nsurl completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        if (!error) {

        //將下載後的檔案進行 移動到沙盒 切記這裡的檔案要及時清理    
            NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
            [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];

        //為 Notification 增加 attachment
            UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"attachment" URL:[NSURL fileURLWithPath:path] options:nil error:nil];


            self.bestAttemptContent.attachments = @[attachment];
        }

        //不管成功失敗 返回結果
        self.contentHandler(self.bestAttemptContent);

    }];

    [self.downLoadTask resume];
}

- (void)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.
    NSLog(@"cancel ");
    //取消下載
    [self.downLoadTask cancel];
    self.contentHandler(self.bestAttemptContent);
}

@end複製程式碼

Debug

我自己測試的時候,發現直接執行時沒法 debug ,根本進不了 service 的斷點,研究了一下才發現了他的 debug 方式。

首先選中目標 service 的 target,強調一下是 service 的 target

iOS 10 來點不一樣的推送

然後 build ,XCode 會提示讓你選擇對應的應用
iOS 10 來點不一樣的推送

然後就退到後臺進行推送,這時候就能進到這個斷點中了。

這裡要強烈介紹一下這個 Mac 端的工具 !!!炒雞好用!!
Push 的工具推薦用 SmartPush 一個開源的 Mac 端push工具
github.com/shaojiankui…
這個東西是神器!從此不用在和後端糾結證照的問題,我自己測試傳送訊息沒問題之後就可以交給後臺了,我的鍋?不存在的!
具體介面是這樣的,能夠自動讀取你本地的證照,填個 device token 就能推送了。

iOS 10 來點不一樣的推送

Fire!

下面是我所測試的各種型別的效果圖和對應的 payload 大家可以參考一下

圖片推送

{
    "aps": {
        "alert": {
            "body": "多媒體推送", 
            "title": "我是圖片", 
            "subtitle": "子標題"
        }, 
        "badge": 6, 
        "sound": "default", 
        "category": "Helllo", 
        "mutable-content": 1
    }, 
    "attach": "https://raw.githubusercontent.com/Danny1451/BlogPic/master/face/8.jpg"
}複製程式碼

效果大概是這樣

iOS 10 來點不一樣的推送

點選之後是這樣 一個耿直的微笑
iOS 10 來點不一樣的推送

mp3 檔案

{
    "aps": {
        "alert": {
            "body": "多媒體推送", 
            "title": "我是音樂", 
            "subtitle": "子標題"
        }, 
        "badge": 6, 
        "sound": "default", 
        "category": "Helllo", 
        "mutable-content": 1
    }, 
    "attach": "https://raw.githubusercontent.com/Danny1451/BlogPic/master/pushtest/a.mp3"
}複製程式碼

iOS 10 來點不一樣的推送

點選之後是這樣:

iOS 10 來點不一樣的推送

MP4 檔案

{
    "aps": {
        "alert": {
            "body": "多媒體推送", 
            "title": "我是視訊", 
            "subtitle": "子標題"
        }, 
        "badge": 6, 
        "sound": "default", 
        "category": "Helllo", 
        "mutable-content": 1
    }, 
    "attach": "https://raw.githubusercontent.com/Danny1451/BlogPic/master/pushtest/video.mp4"
}複製程式碼

點選之前就和音樂訊息是一樣的
之後是這樣的

iOS 10 來點不一樣的推送

最後

注意點

  • 注意檔案下載的位置的儲存管理,及時的清空。
  • 注意如果要用第三方的庫的話,extison 要單獨引用和編譯一份,因為和 app 一樣他們其實是獨立程式的。
  • 注意戶的網路情況,進行判斷是否要下載資源,不然使用者的流量就給你這麼咔咔咔全耗完了。

Demo地址:
實現了 Local 的推送方式,將 extison 也加進去了,但是由於需要證照的緣故沒有加到 target 中,程式碼可以參考。

github.com/Danny1451/P… (如果感到有用的加個✨吧 溜了 溜了)

如果想要我手機桌布的話 請留言 哈哈哈哈 (跑

相關文章