筆記:Develop in Swift Data Collections_Local Notifications
Published in
27 min readNov 27, 2023
· 學習目標
· 基礎概念
· 1.Local and Remote Notifications
· 2.Best Practices
· 3.Requesting Permission
∘ 3–1.Scheduling Local Notifications
· 4.Handling and Responding to Notifications
· 5.Actionable Notifications
∘ 5–1.Categories
∘ 5–2.Actions
∘ 5–3.Text Input Actions
· 6.Foreground Notification Handling
· Practice - Alarm
∘ 1.Get Permission and Set Up the Notification Actions and Category
∘ 2.Create and Schedule Notifications
∘ 3.Set Up the UI
∘ 4.Handle the Notification
∘ 4–1.當App在前景運行時的通知處理
∘ GitHub
· Lab - BillManager
∘ 1.Request Authorization and Set Up the Notification Actions and Category
∘ 2.Remove the Reminder
∘ 3.Schedule a Reminder
∘ 4.Call the Set Reminder Function
∘ 5.Handle the Notification Response
∘ GitHub
學習目標
- 通知的形式:
橫幅通知:
- 當有新的通知時,會以橫幅的形式出現在螢幕頂端。
- 這個橫幅包括 App 的名稱、小圖標,以及一個可選的訊息(包含標題和內容)。
音效和Badge:
- 通知可能伴隨著聲音,並且會在App圖標上顯示或更新 Badge。
- Badge 通常是一個小紅點,上面有數字,顯示新的或未讀的項目數量。
Local Notifications (本地通知)
是一個即使用戶沒在用 App 時,也能跟他們互動、提醒重要事項的好方法。- 利用 UserNotifications 框架,可以提醒用戶注意特定事件,並讓他們對這些事件做出回應。
- 這類通知可以是
自己設定的本地通知
,也可以是從伺服器推送的
。
1. 使用本地通知:
- 用來告知用戶新的或更新的資訊,或是提醒他們某些事項。
2. 設定和安排本地通知:
- 設定時間和內容,以安排通知在特定時刻發送。
3. 創建可操作的通知:
- 設計帶有自訂行動的通知,讓用戶可以直接在通知上進行互動。
4. 處理接收到的通知:
- 當 App 在前台或背景運行時,如何處理接收到的通知。
基礎概念
- Actionable Notification
(可操作通知)
1. 方便快速:
- 除了顯示資訊外,還會有按鍵或輸入框讓你可以直接在通知上回應,
2. 增加互動:
- 讓用戶與 App 間的互動不僅限於打開 App。
3. 多樣用途:
- 從快速回訊息到確認行程,都能透過這種通知輕鬆搞定。
- Badge
1. 清楚提醒:
- 讓使用者一目了然地知道有新的通知或未處理的事項。
2. 直觀顯示:
- 紅色圓形標章很容易吸引注意,並直接展示重要的數量資訊。
3. 提高互動:
- 鼓勵使用者打開App,查看新的內容或回應。
- Banner
(橫幅通知)
1. 立即可見:
- 由於它從螢幕頂部滑下,用戶可以立即看到通知內容。
2. 不干擾使用:
- 橫幅通知不會完全阻擋螢幕,允許用戶繼續目前的操作。
3. 訊息展示:
- 通常顯示簡短的通知文本,有時還包括應用標誌或其他相關圖標。
- Local Notification
「Local Notification」是指只在用戶的裝置上設置和觸發的通知,不涉及從伺服器遠程發送。
對比之下,「Remote Notification」是從伺服器發送給裝置的通知。
1. 裝置自主:
- 不需要網路連接,裝置自己根據設定時間觸發通知。
2. 用途廣泛:
- 可用於提醒、日程安排、鬧鐘等多種場景。
3. 用戶體驗:
- 提高用戶參與度,及時提醒用戶重要訊息。
- Remote Notification
1. 來源不同:
- Remote Notification 來自伺服器,本地通知則在裝置本身產生。
2. 需要網路連接:
- 由於Remote Notification來自伺服器,因此接收這種通知需要裝置連接到網路。
3. 更動態互動:
- Remote Notification適合用於實時更新或提供即時反饋給用戶,如新訊息通知或App更新提醒。
- Notification Category
「Notification Category」是指定義 App 所支援的通知類型和任何相關的操作。
- EX: 如果 APp 是一個待辦事項管理器,可能會有「提醒類別」的通知,包括如「標記為完成」或
「延後提醒」等動作。
1. 自訂類型:
- 可以根據App的功能需求,自行設定不同的通知類型。
2. 附加操作:
- 每種通知類型都可以包含用戶可以互動的操作,例如點擊按鈕或回覆訊息。
3. 增強互動:
- 這與「可操作通知」相關,後者允許用戶直接在通知上執行特定操作。
1.Local and Remote Notifications
- 本地通知:
1. 在用戶的手機上設定,依時間、日期或地點觸發。
2. 適合提醒用戶任務或活動,如待辦事項或日曆提醒。
- 遠程通知:
1. 在伺服器上製作,用來將資訊傳送到用戶手機。
2. 透過 Apple 的推送通知服務(APNs)發送,用於推送新消息或更新。
- 主要差異:
1. 來源不同:
- 本地通知是手機上直接製作,遠程通知則由伺服器發出。
2. 用戶感受相似:
- 無論是本地還是遠程,通知的外觀和感覺對用戶來說都差不多。
3. 開發方式一致:
- 無論本地還是遠程,都是用 UserNotifications 框架來管理。
2.Best Practices
3.Requesting Permission
- 基本步驟
1. 獲得授權:
- iOS 要求App必須得到用戶授權才能發送通知。
2. 初次請求:
- 最初時,App可透過系統界面請求權限,與其他權限請求方式相同。
3. 後續調整:
- 用戶可在「設定」中隨時調整通知權限。
- 實作方法
1. 使用 UNUserNotificationCenter 的 requestAuthorization(options:completionHandler:) 來請求權限。
2. 在 options 裡選擇App需要的通知類型,如:.alert、.badge、.sound。
- 處理授權結果
通過完成處理程序(closure)來處理授權結果,其中包含授權狀態和可能的錯誤。
- 進階選項
1. 臨時通知:
- 加入 .provisional 選項,可先行發送非打擾式的通知至通知中心,
等待用戶選擇是否啟用完整通知。
2. 標準請求:
- 如果不使用 .provisional,系統會提示用戶選擇是否接收通知。這種提示只會出現一次。
- 注意事項
1. 首次請求後:
- 用戶必須在「設定」中手動更新通知權限。
2. 適時說明:
- 在適當的時機(如設定鬧鐘時)向用戶說明為何需要通知權限,有助於增加理解和接受度。
3–1.Scheduling Local Notifications
- 例如,安排一個包含訊息、播放聲音並在5分鐘後發送給用戶的本地通知的步驟:
1. 設定通知內容:聲音、標記、標題和主體
2. 設定通知觸發:5分鐘後發送,不重複
3. 提交通知請求:創建 UNNotificationRequest,並提交
4.Handling and Responding to Notifications
5.Actionable Notifications
5–2.Actions
- 創建動作
- 例子
- 在 App 中的註冊與處理
- 範例
5–3.Text Input Actions
- 使用
UNTextInputNotificationAction
類別創建的動作:
當用戶選擇這樣的動作時,會出現一個文本框和一個按鈕,讓他們輸入並提交文字。
- 在 App 中實現和處理文字輸入通知的步驟
6.Foreground Notification Handling
Practice — Alarm
- 鬧鐘 App ,允許一次設定一個鬧鐘。
1. 創建鬧鐘:
- 實現用戶設定鬧鐘的功能。
2. 獲取通知授權:
- 向用戶請求發送通知的授權。
3. 安排本地通知:
- 設置並安排鬧鐘相關的本地通知。
1.Get Permission and Set Up the Notification Actions and Category
- 建立鬧鐘結構體與基本功能:
1. 導入 UserNotifications 框架。
2. 建立一個 Alarm struct,包含 schedule(completion:) 和 unschedule() 方法。
- 請求通知權限:
1. 建立 authorizeIfNeeded(completion:),用來在第一次設定鬧鐘時請求用戶授權通知。
2. 根據不同的授權狀態(已授權、未決定、被拒絕)來決定是否完成設置。
- 建立
通知類別
和動作Id
:
- 完成通知的設置:
1. 在 AppDelegate 的 application(_:didFinishLaunchingWithOptions:)
中設置自定義的貪睡動作和通知類別。
2. 使 AppDelegate 遵循 UNUserNotificationCenterDelegate 協議,並設置通知中心的代理。
2.Create and Schedule Notifications
- 確認
通知授權
1. 在安排通知前,需要確認 App 是否有發送通知的權限。
2. 這是透過呼叫 authorizeIfNeeded(completion:) 來完成。
3. 如果授權未被允許(granted 為 false),則使用 completion(false) 結束這個函數。
- 由於授權可能在後台進行,請在主線程上進行此調用。
- 建立
通知內容
一旦授權成功,就可以建立通知的內容。這包括設定通知的標題、內文、聲音和分類標識符。
- 如果閉包的布爾參數為 true,則創建通知內容並指定通知的類別標識符
- 建立
通知觸發器
1. 通知需要一個觸發器來確定何時發送。這通常是基於「日期和時間」的設定。
2. 使用 UNCalendarNotificationTrigger 並以「鬧鐘」設定的日期作為觸發時機。
- 建立
通知請求
使用剛建立的「內容」和「觸發器」來建立一個通知請求。
每個請求都需要一個id,用來追蹤並管理通知。
- 安排通知
1. 將「通知請求」加入到 UNUserNotificationCenter。
2. 如果過程中出現錯誤,則print錯誤訊息並用 completion(false) 結束;
若成功則使用 completion(true),同樣將完成調用放在主線程上。
- 取消安排的通知
透過 removePendingNotificationRequests(withIdentifiers:) 取消已安排的通知。
這需要使用之前設定的id。
- 初始化鬧鐘實體
為 Alarm struc 新增一個初始化方法,允許通過參數設定「日期」和「通知識別符」。
如果識別符未提供,則自動生成一個唯一識別符。
3.Set Up the UI
- 設置鬧鐘後,
Label
會顯示選定的時間和日期
,並禁用 Date Picker
,將Button的標題
從「Set Alarm
」改為「Remove Alarm
」。
- 處理鬧鐘通知:
1. 當鬧鐘被設置或取消時,需要發送通知來更新其他物件。
2. 為 Notification.Name 擴展 alarmUpdated 。
- 追蹤和管理已設定的鬧鐘:
1. 創建 scheduled 屬性來追蹤已設定的鬧鐘。
2. 為 scheduled 屬性實作 getter 和 setter 方法,利用 JSON 編碼和解碼存取鬧鐘資訊。
3. 使用 alarmURL 屬性來讀取和寫入文件系統。
- 設置和取消鬧鐘:
1. 在 schedule(completion:) 中,如果成功將鬧鐘加入 UNUserNotificationCenter,
則設置 Alarm.scheduled。
2. 在 unschedule() 方法中,當取消鬧鐘時設置 scheduled 為 nil。
- 更新 UI 方法:
1. 創建 updateUI() 來根據鬧鐘是否被設定來更新 UI。
2. 如果鬧鐘存在,顯示鬧鐘時間,禁用Date Picker,並更改按鈕標題為「移除鬧鐘」。
3. 如果鬧鐘不存在,更改標籤為「設置鬧鐘」,啟用 Date Picker,並將按鈕標題設置為「設置鬧鐘」。
- 流程:
1. 自定義通知名稱:
- 透過擴展 Notification.Name,新增自定義的通知名稱 .alarmUpdated,用於表示
鬧鐘設置或取消時的事件。
2. 發送通知:
- 當 Alarm 的 scheduled 被設置(新增或移除鬧鐘)時,會使用 NotificationCenter
發送一個通知。這代表任何對鬧鐘的更改都會觸發這個通知。
3. 註冊通知觀察者:
- 在 ViewController 中,使用 NotificationCente 註冊為 .alarmUpdated 通知的觀察者。
這表示當 .alarmUpdated 通知被發送時,ViewController 的 updateUI 方法會被呼叫。
4. 處理通知:
- 一旦 .alarmUpdated 通知被發送,ViewController 的 updateUI 方法會被觸發,
更新用戶界面以反映鬧鐘的最新狀態。
- 設置鬧鐘按鈕:
在 setAlarmButtonTapped(_:) 中,檢查 Alarm.scheduled 是否存在。
- 如果存在,執行 alarm.unschedule()。
- 如果不存在,創建新的 Alarm 並用日期選擇器的日期安排它。
- 處理通知權限:
1, alarm.schedule 方法包含一個閉包,用於處理未授予通知權限的情況。
2. 如果未授予權限,從閉包中呼叫 presentNeedAuthorizationAlert() 方法。
3. presentNeedAuthorizationAlert() 會展示一個警告,提示用戶前往設定更改通知權限。
4.Handle the Notification
- 當使用者在通知中做出反應(比如按下
貪睡按鈕
)時,因此需要在AppDelegate
中加入一個方法來處理這個動作。
- 方法定義
userNotificationCenter(_:didReceive:withCompletionHandler:):
這是一個用來處理使用者對通知反應的方法。
- 檢查動作
判斷使用者的反應是否為"貪睡"。
這是通過檢查 response.actionIdentifier 是否等於 Alarm.snoozeActionID 來做的。
- 創建新的貪睡鬧鐘
1. 如果使用者選擇了"貪睡",則創建一個新的鬧鐘,設定在當前時間後的9分鐘。
2. 使用Date().addingTimeInterval(9 * 60)來計算新的鬧鐘時間。
- 安排鬧鐘
1. 調用alarm.schedule(completion:)來安排鬧鐘。
2. 最後,調用completionHandler()來結束這個方法。
4–1.當App在前景運行時的通知處理
- 即使App正在
前景運行
,也希望鬧鐘通知能夠正常顯示。 - 方法定義:
userNotificationCenter(_:willPresent:withCompletionHandler:):
這個方法用來定義當App在前景時如何處理通知。
- 設置通知顯示選項:
1. 使用completionHandler([.alert, .sound])來確保通知可以以彈窗和聲音的形式呈現。
2. 將Alarm.scheduled設置為nil,因為通知即將顯示,用戶可以安排新的鬧鐘。
Lab — BillManager
- 為了提醒用戶支付即將到期的款項,需要添加「
本地通知
」。
1. 兩個視圖控制器:
- 主視圖(Master View):展示賬單列表。
- 詳細視圖(Detail View):用於展示單個賬單的詳情。
2. 模型對象:
- 有一個 Bill 的模型對象。
3. Bill 的擴展(Extension):
- hasReminder(是否設置提醒)、isPaid(是否已支付)和 formattedDueDate(格式化的到期日期)。
1.Request Authorization and Set Up the Notification Actions and Category
- 新增方法至 Bill 擴展:
1. 新方法來新增、移除提醒,以及如何請求顯示通知的權限。
2. 為這些功能在 Bill 中定義基本的方法框架。
- 基本方法架構:
1. 移除提醒方法:
- 不用加參數。
2. 排程提醒方法:
- 要改變 Bill,加入一個代表提醒日期的 Date 參數,還有一個回傳更新過的 Bill 的閉包。
3. 檢查通知授權方法:
- 私密設定,用一個回傳布林值的閉包來確認是否有顯示通知的權限。
- 實作權限檢查:
1. 若還沒問過用戶要不要授權,就在這裡問。
2. 無論結果如何,都要用適當的布林值結束這個方法。
1. 如果尚未請求授權,則在此方法中請求授權。
2. 確保所有可能的程式碼路徑結束時,都呼叫完成閉包(completion closure),
並傳遞適當的布林值,以指示 App 是否有權安排使用者通知。
- 設定Id:
在 Bill 加個 notificationCategoryID 的靜態變數,設個要用的字串。
- AppDelegate 設定通知動作:
1. 在 application(_:didFinishLaunchingWithOptions:) 加入兩個通知動作:
- 一個是一小時後再提醒,另一個是標記帳單為已付款。
2. 標記為已付款的動作要設定 .authenticationRequired,這樣只有裝置主人解鎖後才能用。
3. 用這兩個動作建立一個類別,並註冊到用戶通知中心。
4. 設定通知中心的代理。
2.Remove the Reminder
- 在
Bill
擴展中實現刪除提醒
的方法。 - 這個過程確保了提醒能夠被有效且安全地從系統中移除,同時也保持了
Bill
類別狀態的一致性和準確性
1. 功能目的:
- 主要目的是從使用者的通知中心中移除掉設定的提醒。
2. 檢查與取用:
- 首先會確認提醒編號(notificationID)是否設定好了。如果存在,則繼續執行下一步。
3. 移除提醒:
- 一旦獲得了notificationID,就會用這個編號去找出並刪除所有待處理的通知。
這個動作就等於取消了這個提醒。
4. 重設屬性:
- 在移除提醒之後,會將notificationID(提醒編號)和remindDate(提醒日期)設置為nil。
這代表提醒已被完全清除,並且與該賬單相關的提醒資訊也被重置。
3.Schedule a Reminder
1. 加入追蹤功能:
- 為了區分每個帳單的提醒,需要在 Bill類別 中新增 notificationID 屬性,型態是String?。
2. 實作設定提醒方法:
- 由於在變更方法(mutating method)中不能使用指向自己(self)的逃逸閉包。
所以需要先複製一份自己(var updatedBill = self),再對這個副本進行必要的修改,
並在完成閉包中返回這個副本。
3. 先清除舊提醒:
- 這個方法的第一個動作是用之前寫的移除提醒功能,以刪除該帳單之前設定的任何提醒。
- 這確保使用者不會收到他們以為已經更改的提醒。
4. 檢查是否有發通知的權限:
- 先檢查是否有權限發通知。如果沒有權限,就直接結束這個方法,並回傳剛才的副本實例。
5. 設計通知的內容:
- 標題設為「Bill Reminder」,內容要包含帳單金額、收款人和到期日。
- EX:「需支付$12.00給Alexis Key,2021年4月10日到期」。
- 類別標識符使用之前註冊類別時使用的ID。
- 建立和加入通知:
1. 使用方法中傳入的日期創建一個通知觸發器。
2. 創建新的通知ID(用UUID().uuidString),並賦值給notificationID。
3. 使用內容、觸發器和識別碼創建一個新的通知請求。
4. 如果已經有發通知的權限,就把這個請求加到用戶通知中心,並更新複製體的通知ID和提醒日期。
5. 最後呼叫完成閉包,並傳回這個更新過的副本實例。
6. 注意執行緒:所有對完成處理程序的調用都應在主執行緒上進行。
4.Call the Set Reminder Function
1. 場景:當使用者點擊「完成」按鈕時,會「呼叫設定提醒」的函式。
2. 操作步驟:
- 在 BillDetailTableViewController中,找到 prepare(for:sender:) 函式。
- 在這個函式內,尋找檢查 remindSwitch.isOn 條件的 if-else 語句。
3. 修改 if-else 語句
- 目的:
- 根據提醒開關的狀態來設置或移除提醒。
- 操作:
- 開關開啟:設置 remindDate,並呼叫「設定提醒函式」。
- 開關關閉:將 remindDate 設為 nil,並呼叫「取消提醒函式」。
3. 處理未授權情況
- 問題:
- 若未授權通知,則無法設定提醒。
- 解決方案:
- 如果 notificationID 是 nil,顯示提醒要求使用者去 iOS 設定授權。
- 建立 presentNeedAuthorizationAlert() 方法顯示警告。
4. 更新資料庫
- 時機:無論是「成功設置提醒」還是「關閉提醒」,都在完成閉包內更新資料庫。
- 實作:在設定提醒的方法的完成閉包中,以及當提醒開關設為關閉的情況下,更新資料庫。
5.Handle the Notification Response
1. 在 AppDelegate 中實現代理方法:
- 實作 userNotificationCenter(_:didReceive:withCompletionHandler:) 方法。
- 從回應裡拿到通知的ID: let notificationID = response.notification.request.identifier。
2. 用這個ID找到對應的賬單:
- 在 Database 設置 getBill(forNotificationID:) 方法,讓它根據通知ID找到相關賬單。
3. 判斷用戶選擇的操作:
- 使用 switch 或 if-else 語句來判斷用戶選擇了哪個操作。
4. 根據用戶的選擇做不同的處理:
- 如果選「稍後提醒」RemindAction,就再設一個一小時後的提醒,在完成閉包中保存更新後的賬單。
- 如果選「標為已付款」MarkAsPaidAction,就把付款日期設為現在,並保存新數據。
5. 完成通知中心的處理:
- 在 userNotificationCenter(_:didReceive:withCompletionHandler:) 結束時呼叫完成處理程序。
6. 即使app在前台也要顯示通知:
- 寫 userNotificationCenter(_:willPresent:withCompletionHandler:) 即使
App 在前台運行時,也顯示通知。
- 測試:兩個同時間的任務通知排程