SwiftUI - iOS10本地推送通知教程UserNotifications在Swift中的實現方式

来源:https://www.cnblogs.com/GarveyCalvin/archive/2020/06/09/swiftui-usernotifications.html
-Advertisement-
Play Games

簡介 消息推送相信在很多人的眼裡都不陌生了吧?像即時聊天微信,好友發信息給你時會在頂部彈下小視窗提醒你。也像是在影院APP預訂了電影票,在開場前一小時你也會收到提醒。這類推送是需要經過後端發送請求的,需要伺服器發送推送請求,又或者使用如極光推送等第三方渠道。 那麼如果我們的APP不需要連網呢?這是不 ...


簡介

消息推送相信在很多人的眼裡都不陌生了吧?像即時聊天微信,好友發信息給你時會在頂部彈下小視窗提醒你。也像是在影院APP預訂了電影票,在開場前一小時你也會收到提醒。這類推送是需要經過後端發送請求的,需要伺服器發送推送請求,又或者使用如極光推送等第三方渠道。

那麼如果我們的APP不需要連網呢?這是不是就不能使用消息推送了?不是的,蘋果還提供給我們本地消息通知服務,即便APP不連網也能使用,功能也很強大可靠。本地時鐘的應用場景很廣泛,例如手機上的時鐘、日曆等。

那麼你知道如何去實現它嗎?這篇文章將告知你答案,同時以兩個小案例作為例子,以便更好地去理解它。

筆者環境

Xcode - Version 11.5 (11E608c)

Swift - version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53).

許可權獲取

UserNotifications 是 iOS10 推出來的框架,因此你只能在 10 或以上的版本使用它。推送服務和以往一樣,也是需要用戶授權的,當用戶同意後才能正常註冊消息通知,當用戶拒絕時應該引導用戶去打開APP的通知許可權。利用requestAuthorization方法彈出並獲取通知許可權,接收的參數options是具體的授權選項,一般有彈窗、未讀數量圖標和聲音即可,併在回調閉包中可以獲取授權結果和錯誤。

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (status, err) in
    if !status {
    		print("用戶不同意授權通知許可權")
        return
    }
}

status 為布爾類型,true 表示用戶同意,false 即拒絕。在此種情況下,我們可以使用彈窗去引導用戶去打開通知許可權,需要明確告知用戶打開後有什麼好處,如果關閉會造成什麼影響等等。如果讓用戶手動打開設置,找到APP,為APP開啟許可權,這樣未免太過複雜,所幸的是可以通過以下代碼為用戶直接跳轉至該應用的許可權設置中心。

guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
if UIApplication.shared.canOpenURL(url) {
    UIApplication.shared.open(url, completionHandler: nil)
}

應彈窗提示用戶,待用戶同意後才跳轉至設置,不然容易引起用戶的不滿心理。

觸發器

本地消息通知一般有以下三種類型的觸發器,它們都是繼承於類UNNotificationTrigger

  1. UNTimeIntervalNotificationTrigger - 在經過特定的時間後觸發本地消息推送;
  2. UNCalendarNotificationTrigger - 在特定的時間點觸發本地消息推送;
  3. UNLocationNotificationTrigger - 在進入或離開特定的地理位置時觸發本地消息推送。

UNTimeIntervalNotificationTrigger

手機上的時鐘用過吧,裡面的計時器功能就可以用UNTimeIntervalNotificationTrigger實現,比如開始計時30分鐘,那麼在計時器完成的時候就是使用通知提醒。

那麼設置在經過特定的時間後觸發本地消息推送,一般都經由以下幾個步驟:

  1. 首先創建UNMutableNotificationContent類,設定標題和內容,如果你有子標題還可以設置子標題,一般很少見到會設置子標題的應用。
  2. 創建觸發器,這裡就是UNTimeIntervalNotificationTrigger,設定執行秒數和是否迴圈通知。
  3. 創建通知請求UNNotificationRequest,這裡需要指定通知的identifier,內容和觸發器,至於identifier,你可以隨意定義。
  4. 最後將通知請求添加到系統的通知中心UNUserNotificationCenter即可。

例子,創建一個通知,在5秒後執行消息推送。實例代碼展示如下:

let content = UNMutableNotificationContent()
content.title = "添加朋友 對著月亮敲代碼"
//content.subtitle = "子標題"
content.body = "公眾號 gh_6a83a7c19315"
content.badge = 1

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "Notification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { err in
    err != nil ? print("添加本地通知錯誤", err!.localizedDescription) : print("添加本地通知成功")
}

有一處小 Tips,UNTimeIntervalNotificationTrigger創建時的repeats選項,如果你設定為迴圈通知時,即需要每隔N秒觸發一次通知,那麼你必須至少設置為60秒的時間間隔,如若低於60秒,你將會得到這樣一條錯誤。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'time interval must be at least 60 if repeating'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff23c7127e __exceptionPreprocess + 350
	1   libobjc.A.dylib                     0x00007fff513fbb20 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff23c70ff8 +[NSException raise:format:arguments:] + 88
	3   Foundation                          0x00007fff256e9b51 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
	4   UserNotifications                   0x00007fff2c7dfc7c -[UNTimeIntervalNotificationTrigger _initWithTimeInterval:repeats:] + 277

UNCalendarNotificationTrigger

手機上的日曆用過吧,在新建日程的時候,你可以選擇一個提醒時間,這樣它就會在你設定的提醒時間提醒你,這種情況就很適合用UNCalendarNotificationTrigger去實現。

舉個例子,我們要在每晚7點提醒用戶看公眾號。

let content = UNMutableNotificationContent()
content.title = "添加朋友 對著月亮敲代碼"
//content.subtitle = "子標題"
content.body = "公眾號 gh_6a83a7c19315"
content.badge = 1

let dateComponents = DateComponents(hour: 19) // 1
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) // 2
let request = UNNotificationRequest(identifier: "Notification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { err in
    err != nil ? print("添加本地通知錯誤", err!.localizedDescription) : print("添加本地通知成功")
}

1 - 創建時間元件,19點即為晚上7點

2 - 創建UNCalendarNotificationTrigger對象,並將dateComponents賦值到dateMatching,repeats為true,重覆在每天19點收到通知提醒。

UNLocationNotificationTrigger

這個觸發器不在此篇文章講述,留給你們自己去實現和測試結果。

圖標

還記得剛剛設置的屬性badge嗎,我們設置值為1,這意味著在iPhone桌面上的應用圖標在收到通知時,右上角圓點內所展示的數字就是badge的值。

這個屬性值是applicationIconBadgeNumber,它是UIApplication的屬性,設置為0即為隱藏,預設也是0。

UIApplication.shared.applicationIconBadgeNumber = 0

消息推送回調代理

接收用戶對消息推送的反饋事件,比如說應用在後臺收到了通知,用戶點擊了這條通知進入到了APP裡面,我們需要獲取這個事件去做一些處理,比如跳去某個界面,這裡例子不講這麼複雜,只通過簡單地判斷用戶是通過哪個通知進來的。

接收回調代理事件前,需要遵循UNUserNotificationCenterDelegate協議,並設置delegate接收的對象。

extension AppDelegate: UNUserNotificationCenterDelegate {}

UNUserNotificationCenter.current().delegate = self

Swift語言中,可以通過extension擴展類遵循的協議,併在extension

當應用在前臺運行時,收到的是這個-userNotificationCenter:willPresentNotification:withCompletionHandler:代理方法。UNNotification對象存儲了傳遞到應用的一些數據,通過此對象可以拿到此條通知關聯的觸發器notification.request.trigger,從而判斷其類型。

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    guard let trigger = notification.request.trigger else { return; }
    if trigger.isKind(of: UNTimeIntervalNotificationTrigger.classForCoder()) {
        print("Notification did receive, Is class UNTimeIntervalNotificationTrigger")
    } else if trigger.isKind(of: UNCalendarNotificationTrigger.classForCoder()) {
        print("Notification did receive, Is class UNCalendarNotificationTrigger")
    }
}

當應用在後臺,或者被殺死的狀態下,收到的是這個-userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:代理方法。此方法接收UNNotificationResponse類型的參數,它裡面包含notification屬性,因此可以參考上面的代碼進行觸發器的判斷。

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    guard let trigger = response.notification.request.trigger else { return; }
    if trigger.isKind(of: UNTimeIntervalNotificationTrigger.classForCoder()) {
        print("Notification did receive, Is class UNTimeIntervalNotificationTrigger")
    } else if trigger.isKind(of: UNCalendarNotificationTrigger.classForCoder()) {
        print("Notification did receive, Is class UNCalendarNotificationTrigger")
    }
}

總結

  1. 本地通知有三種類型的觸發器,分別是UNTimeIntervalNotificationTrigger、UNCalendarNotificationTrigger和UNLocationNotificationTrigger。
  2. UNTimeIntervalNotificationTrigger在設置迴圈通知時,所設定的時間隔不能低於60秒,否則會報運行時錯誤。

往期回顧

  1. SwiftUI - 一起來仿寫微信APP之一首頁列表視圖
  2. SwiftUI - 一步一步教你使用UIViewRepresentable封裝網路載入視圖(UIActivityIndicatorView)

Demo 源碼下載

我已經把 Demo 上傳至 GitHub 上面,項目名字是 SwiftUI-Tutorials,目錄名為GCLocalUserNotification,有需要的朋友可以去下載運行一下,當然你也可以跟著文章去做一遍,這樣更有利於你掌握此方面的知識。

如果本文章對你有幫助,請關註我,你的關註就是我後續寫文章的動力,下期會更精彩噢!

關於作者

博文作者:GarveyCalvin

微博:https://weibo.com/feiyueharia

博客園:https://www.cnblogs.com/GarveyCalvin

本文版權歸作者,歡迎轉載,但必須保留此段聲明,並給出原文鏈接,謝謝合作!

公眾號

作者第一次運營公眾號,請你們一定要關註我的公眾號,給我點動力,後期主要運營公眾號為主。這是第三篇發佈的文章,需要你們的支持,謝謝你們!

微信群

佛系等待你們的到來,若二維碼過期,請加我QQ:1147626297,記得寫備註,我重新發鏈接給你。快來加入我的“億”個人群吧!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 結構化查詢語言(SQL)是第四代編程語言的典型,這種命令式的語言更像一種指令,使用它,你只需要告訴電腦“做什麼”,而不用告訴電腦“怎麼做”。第四代編程語言普遍具有簡單、易學、能更快的投入生產等優點,但也失去了部分第三代編程語言(C,C++,Java等)的靈活性。PL/SQL 在 SQL 的基礎上... ...
  • 2020-06-09 19:31:01 一、疑問 前段時間;QQ群里有人對“這個表(0,4)這行數據我做了update操作,查看索引的page數據,看到索引一直指向(0,4),用ctid='(0,4)'查詢業務表是查不到數據的;然後我做了表的vacuum,reindex甚至drop/create i ...
  • 1. API基本概念 Flink程式可以對分散式集合進行轉換(例如: filtering, mapping, updating state, joining, grouping, defining windows, aggregating) 集合最初是從源創建的(例如,從文件、kafka主題或本地內 ...
  • 參考:1、vmware安裝centos ,ping 百度 成功https://www.cnblogs.com/jpwz/p/10466826.html 2、vmware克隆centos7後網路配置和主機名問題https://blog.csdn.net/mo_ing/article/details/8 ...
  • 一:MongoDB 概述 一、NoSQL 簡介 1. 概念:NoSQL(Not Only SQL的縮寫),指的是非關係型資料庫,是對不同於傳統的關係型資料庫的資料庫管理系統的統稱。用於超大規模數據的存儲,數據存儲不需要固定的模式,無需多餘操作就可以橫向擴展。 2. 特點 1. 優點:具有高可擴展性、 ...
  • 最近花了不少時間把項目資料庫從oracle遷移到達夢8,遷移過程中碰上了不少問題,後面有時間我整理一下心得。 今天先發一下php使用dm_pdo操作達夢資料庫的示例代碼,裡面包括了常規的綁定變數查詢,存儲過程調用,clob類型操作等。 使用的是達夢提供的pdo_dm驅動,相關配置信息請參考達夢的官方 ...
  • 利用Sql Server的Sum函數開窗得到累計值 具體詳解https://www.cnblogs.com/zhaoshujie/p/9594676.html 個人示例例子 DECLARE @Sale Table (--年份 月份 銷售總額 [Year] INT, [Month] INT, Tota ...
  • 順序查找:就是從第一個元素開始,按索引順序遍歷待查找序列,直到找出給定目標或者查找失敗 缺點:效率低 -- 需要遍歷整個待查序列 二分法查找:也稱為折半法,是一種在有序數組中查找特定元素的搜索演算法。 1:首先,從數組的中間元素開始搜索,如果該元素正好是目標元素,則搜索過程結束,否則執行下一步。 2: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...