iOS10通知使用/3D-Touch使用

iOS10通知使用/3D-Touch使用

概序:

主要實現iOS10中 UserNotifications 對帶選擇控制的本地通知的使用,只要點擊了當日日的通知或者進入了app,當日的本地通知不再相應功能;使用 3D-Touch 在桌面上來快速啟動app的功能;使用后臺多任務功能;

1、本地通知:

iOS10 全新的 UserNotifications 框架將iOS系統的遠程和本地通知做了統一的管理,下面介紹一下本地通知的一些流程及注意點:

1.1 注冊通知中心: 并且實現響應的代理

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    let center = UNUserNotificationCenter.current()
    center.delegate = self
    center.requestAuthorization(options: [.alert, .badge, .sound]) { (resulet, error) in
        if resulet {
            print("register notification success")
        }
        else {
            print("register notification fail error.localizedDescription:\(error?.localizedDescription)")
        }
    }
    
    return true
}

// app在前臺運行時,收到通知會喚起該方法,但是前提是得 實現該方法 及 實現completionHandler
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Swift.Void){
    print("categoryIdentifier: \(notification.request.content.categoryIdentifier)")
    completionHandler(.alert)
}

// 用戶收到通知點擊進入app的時候喚起,
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Swift.Void) {
    let catogoryIdentifier = response.notification.request.content.categoryIdentifier
    if catogoryIdentifier == "local_notification" {
        // 根據事件的 identifier 來響應對應的通知點擊事件
        if response.actionIdentifier == "sure_action" {
            print("response.actionIdentifier: sure_action")
        }
    }
    completionHandler()
}

1.2 設置自定義的通知類型: 使用 UNNotificationCategory 來管理一組通知的自定義事件, 參數說明:

authenticationRequired: 需要解鎖顯示, 黑色文字, 點擊會被登錄攔截, 解鎖后也不會打開app

destructive: 紅色文字,點擊不會進app

foreground: 黑色文字,點擊會進app

let lockAction = UNNotificationAction(identifier: "lock_action", title: "點擊解鎖", options: .authenticationRequired)
let cancelAction = UNNotificationAction(identifier: "cancel_action", title: "點擊消失", options: .destructive)
let sureAction = UNNotificationAction(identifier: "sure_action", title: "點擊進入app", options: .foreground)

//設置一組通知類型,通過 local_notification 來標識
let category = UNNotificationCategory(identifier: "local_notification", actions: [sureAction, lockAction, cancelAction], intentIdentifiers: [], options: .customDismissAction)

//將該類型的通知加入到 通知中心
UNUserNotificationCenter.current().setNotificationCategories([category])

1.3 向通知中心加入通知: 通知觸發器有四種方式:

UNPushNotificationTrigger: 觸發APNS服務,系統自動設置(這是區分本地通知和遠程通知的標識)

UNTimeIntervalNotificationTrigger: 一段時間后觸發

UNCalendarNotificationTrigger: 指定日期觸發

UNLocationNotificationTrigger: 根據位置觸發,支持進入某地或者離開某地或者都有

具體使用方式對應的api都有詳細的說明。

需要注意的是:

通知間隔設置需要 60S 以上,更換通知聲音時,記得先卸載app然后重新運行;

向消息通知注冊多條 通知時,記得 request 的 identifier 不能用一個,如果設置了多條request,但是identifier都是一樣的,只會觸發最晚的那條通知。

LocalNotifManager.swift

// 在 dateString 之后,每一分鐘執行一次通知
// dateString:觸發通知的時間 sound:通知觸發時聲音 index:第幾次注冊通知 times:共需要注冊幾次
func addNotifi(dateString : String, sound : UNNotificationSound, index : Int, times : Int, week : Int) {
    
    if index >= times {
        return
    }
    
    let newDateString = LocalNotifManager.getRemindTimeWithString(remindTime: dateString, afterMinter: index)
    let array = newDateString.components(separatedBy: ":")
    let hour = Int(array[0]);
    let minute = Int(array[1]);
    var component = DateComponents()
    component.hour = hour
    component.minute = minute
    let trigger = UNCalendarNotificationTrigger.init(dateMatching: component, repeats: true)
    
    // 通知上下文,通過categoryIdentifier來喚起對應的 通知類型
    let content = UNMutableNotificationContent()
    content.categoryIdentifier = "local_notification"
    content.title = "通知標題-_-"
    content.body = "通知實體*_*"
    content.sound = sound
    
    let request = UNNotificationRequest(identifier: "request"+dateString+String(index), content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
        print("week:\(component.weekday) hour:\(component.hour) minute:\(component.minute) index : \(index) success")
    })
    
    // 預留一小段時間處理下一條通知的加入
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.addNotifi(dateString: dateString, sound: sound, index: index+1, times: times, week: week)
    }
}


class func getRemindTimeWithString(remindTime : String, afterMinter : Int) -> String {
    let array = remindTime.components(separatedBy: ":")
    if array.count == 2 {
        var hour = Int(array[0]);
        var minter = Int(array[1]);
        var totalMinter = hour! * 60 + minter!
        totalMinter += afterMinter
        
        hour = Int(totalMinter / 60)
        minter = Int(totalMinter % 60)
        if minter! > 9 {
            return String(hour!) + ":" + String(minter!)
        }
        else {
            return String(hour!) + ":0" + String(minter!)
        }
    }
    
    return remindTime;
}

好了,就這樣調用如下代碼即可 在每日的 12:34 - 12:44 時間段中每隔一分鐘執行一次本地通知

LocalNotifManager().setLocalNotification(with: "12:34", times: 10)

1.4 繼續完善需求咯,點擊進入app后,不再接受當日的其他通知,這個在網上確實找了好多資料,都沒有找到好的方式來解決,后來只能說是 天佑殘疾,無意中我在api中發現了兩個重要的方法:

// UNUserNotificationCenter: 獲取還未觸發的通知列表
open func getPendingNotificationRequests(completionHandler: @escaping ([UNNotificationRequest]) -> Swift.Void)
    
// UNCalendarNotificationTrigger: 獲取該通知下一個觸發的時間日期
open func nextTriggerDate() -> Date?

有了這兩個接口就好辦多了,大概的思路是在app進入前臺時,先通過 getPendingNotificationRequests 拿到通知中心的所有未觸發通知,再取消所有的通知,然后在拿到的所有通知列表中,一一找到通知的下一個觸發時間和現在時間對比,如果大于等于一天則重新加入通知中心:

func applicationWillEnterForeground(_ application: UIApplication) {
    UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (requests : [UNNotificationRequest]) in
        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
        
        let formatter = DateFormatter()
        formatter.dateFormat = "dd"
        let dateString = formatter.string(from: Date())
        let dateInt = Int(dateString)
        
        for request in requests {
            let trigger = request.trigger as! UNCalendarNotificationTrigger
            let nextTriggerDate = trigger.nextTriggerDate()
            let nextTriggerDateString = formatter.string(from: nextTriggerDate!)
            let nextTriggerDateInt = Int(nextTriggerDateString)
            
            print("dateInt:\(dateInt) nextTriggerDateInt:\(nextTriggerDateInt)")
            
            //觸發時間比現在在 0 天以后,說明是第二天的通知了,需要重新加入到通知中心
            if nextTriggerDateInt! - dateInt! > 0 {
                UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in

                })
            }
            
        }
    })
}

2、 3D-Touch 體驗

這個功能很簡單,這里只是做一下記錄吧:

<!-- info.plist添加如下代碼 -->
<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemTitle</key>
        <string>現在穿衣服吧</string>
        <key>UIApplicationShortcutItemType</key>
        <string>com.harry.HDLocalNotification.wear</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>3d_touch _wear_icon</string>
        <key>UIApplicationShortcutItemUserInfo</key>
        <dict>
            <key>key1</key>
            <string>value1</string>
        </dict>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemTitle</key>
        <string>現在脫衣服吧</string>
        <key>UIApplicationShortcutItemType</key>
        <string>com.harry.HDLocalNotification.notWear</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>3d_touch_not_wear_icon</string>
        <key>UIApplicationShortcutItemUserInfo</key>
        <dict>
            <key>key2</key>
            <string>value2</string>
        </dict>
    </dict>
</array>
// AppDelegate: 根據info.plist中的 UIApplicationShortcutItemType值 找到對應的事件即可
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
    print("shortcutItem.type: \(shortcutItem.type)")
}

3、使用后臺多任務功能

這個是在支持多個通知的時候使用,因為多個通知添加到通知中心時,我使用了隊列處理,數量多的時候有一定的耗時,這個時候可能就需要后臺多任務來跑這些任務了:

//后臺任務
var backgroundTask : UIBackgroundTaskIdentifier! = nil

//進入后臺后
func applicationDidEnterBackground(_ application: UIApplication) {
    //如果已存在后臺任務,先將其設為完成
    if self.backgroundTask != nil {
        application.endBackgroundTask(self.backgroundTask)
        self.backgroundTask = UIBackgroundTaskInvalid
    }
    
    //注冊后臺任務
    self.backgroundTask = application.beginBackgroundTask(expirationHandler: {
        () -> Void in
        //如果沒有調用endBackgroundTask,時間耗盡時應用程序將被終止
        application.endBackgroundTask(self.backgroundTask)
        self.backgroundTask = UIBackgroundTaskInvalid
    })
}

完整項目地址: HDLocalNotification

歡迎 star

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • 在iOS10上,蘋果將原來散落在UIKit中各處的用戶通知相關的代碼進行重構,剝離,打造了一個全新的通知框架-Us...
    Nemocdz閱讀 2,503評論 3 16
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,745評論 25 708
  • 介紹一下iOS10的通知新功能,用戶體驗的提升和開發者能夠發揮的地方非常多,使得iOS更具有競爭力。 1.iOS ...
    F麥子閱讀 3,863評論 3 4
  • 收聽提示: 1.點擊之后若顯示“網頁無法打開”,可繼續點右上角,選擇“在瀏覽器中打開”,即可。 2.也可下載荔枝F...
    粘粘啊閱讀 145評論 2 3
  • 孩子開學后3天時間了! 還是有些不舍,擔心兒子的集體生活是否對成長更為重要?我應該做些什么對兒子有影響作用? 看群...
    薔薇竹閱讀 152評論 0 0