iOS 12 新通知功能:添加互動性 在通知中實作複雜功能


如果你看了 Apple 的 “What’s New in iOS 12” 網站的話,會看到 ” Interactive Controls in Notifications ” 這個段落,寫著:

通知內容應用擴展 (Notification content app extensions) 現在支援自定義視圖中的使用者互動性,如果 App 通知的內容需要驅使使用者互動,可請添加按鈕和開關等控件。

在本次的教學裡,我會讓你看看如何讓本地或是遠端(推播)通知擁有一個客製化使用者介面 (UI)。使用者現在可以跟你的通知內容進行互動。而 iOS 12 則讓我們能夠添加一個可以客製化的 UIViewController 子類別到通知本身。我們可以加入一些控件如 UIButtonUIImageView 以及 UISwitch 到 ViewController 之中,然後以 IBOutletIBAction 來撰寫一些客製化的功能,並且可以藉由 AutoLayout 來進行 UI 排版;而上述所有都是在通知本身裡面進行。我們終於可以提供多於單一點擊的功能了,這樣就可以在通知空間限制和時間考量內,開發出更多想要提供的使用者體驗。

我會講述使用者如何在不開啟 App 情況下,與客製化通知介面互動來回應通知。我將展示之前釋出給開發者的軟體,特別是 iOS 12 beta 2 以及 Xcode 10 beta 2 的開發者。

讀完本篇教學,你將能夠讓 App 使用者收到通知,並看到一個客製化 UI,使用者點擊按鈕就可以取得確認,而這些動作都是在一個通知裡發生,就像是這樣:

範例 App 的使用情境

你剛剛看到的 GIF 範例動畫,就是在模擬真實世界的情境中,以新 iOS 12 功能所建立並處理的通知。假設你在銀行裡有個支票帳戶可以讓一個 iOS App 來管理你的金錢和交易,而你已經在 iPhone 上擁有一個這樣的 App。

再假設你的銀行有一個價值 2 美元的透支保障計劃,但你沒有選擇該計劃,因為你的帳戶通常都收支平衡。不過這家銀行十分聰明,即使你不選擇透支保障計劃,銀行仍會發出通知,告訴你可以一次性以 25 美元透支費來幫你處理透支金額。只要你在他們新 iOS 12 互動通知裡選擇同意,他們將會為你處理透支金額。

有時付出一筆透支費當然比在信用記錄中留下汙點好,而且最好付清所有因沒有付款而你收取的所有其他費用。不過請記得,這只是一個雛形而不是真的銀行 App。

Xcode 範例專案

我已經放了一個用 Swift 撰寫的 Xcode 10 範例專案,這樣你就可以在教學裡跟著我的程式碼一起學習。你可以從 GitHub 下載範例專案。

編輯註:為了可以正常地構建及執行這個專案,請更改 Bundle Identifier 為自己的 Identifier。

user-notification-demo-project

不要搞混

請不要將本次教學的新 iOS 12 通知功能,與之前作業系統允許你做的東西搞混,例如在通知底部預設定義的 “Accept” 以及 “Decline” 按鈕,這種做法就有在 Apple 開發者文件的 “Declaring Your Actionable Notification Types” 描述過了。

關於測試軟體

請注意我說的測試軟體可能有許多 Bug 以及需要調整的地方。就像 Apple 在這裡所說的:

請注意,由於 Public Beta 版軟件並非 Apple 的商業發行版本,因此可能存在錯誤或不准確的地方,而且運行效果可能不像商業發行版本那麼理想。

還有這裡

Apple 文檔可能包含一些初步信息,與開發中的 API 或技術 Beta 版本相關。這些信息有可能會改變,因此,你應為根據文檔實作的軟件,以最終操作系統進行測試。請閱讀正在使用的軟件版本的發行說明,以取得最新信息。

撰寫發送通知的程式碼

讓我們繼續教學,以 Single View App 樣板為基礎,建立一個 Xcode 10 專案。

作為一個 iOS 開發者,你現在應該很熟悉本地以及遠端(推播)通知。雖然我會介紹發送通知的基本設定,但我假設你不需要詳細的說明都可以繼續閱讀教學。

要收到通知,很明顯我必須先發送一個本地或是遠端通知。為了節省時間,並專注在客製化通知的教學中,我會使用本地通知。無論本地或是遠端發送通知,其通知和任何客製化 UI 及互動功能都會是相同的。不過我還是會重點講述一些發送遠端通知的重要步驟。

請記住我在這裡構建的 App 名為 “iOS 12 Notifications”,我將會在不少圖像中用到這個 App 的名字。

向使用者請求權限

你必須向 App 的使用者請求權限,來獲得發送通知給他們的准許,這是一個必要的步驟。為了達到這個目的,最好的方法便是置入請求權限的程式碼到 Xcode 專案中的 AppDelegate.swift 檔案裡。此外,每當要編寫通知程式碼時,別忘了要匯入 import UserNotifications。以下是範例程式碼:

當使用者第一次執行我們建置的 App 時,他們將須選擇允許通知,才能享受 iOS 12 的新互動通知功能。啟動 App 時,他們會收到一個警告,然後需要點擊 “Allow” 按鈕:

在我點擊 “Allow” 後,下面這個訊息就會列印在 Xcode 10 控制台裡:

定義通知類型 (Category Identifier)

iOS 要求我們定義字串來區別 App 可以發送與接收的通知類型,這讓我們可以識別和準備不同的 UI、樣式、動作等來支援通知。對於新 iOS 12 通知客製化 UI 功能,Apple 官方文件有相當明確的說明。

為了定義這次教學內的「通知種類數值」,我在範例 App 的 ViewController.swift 中加入以下程式碼到 viewDidLoad() 方法。請注意,當中有兩行帶有相應編號註釋的程式碼,我將在下面詳細解釋。

#1.1 ── 我以 init(identifier:actions:intentIdentifiers:options:) 初始器建立了一個 UNNotificationCategory 類別的實例。因為我的通知將會有一個客製化介面,所以我關心的是 identifier 實例屬性,我把剩下的參數留空,不過需要注意的是 actions 參數,雖然 Apple 說:「如果你不想呈現客製化動作的話,可以指定 nil 給這個參數」,但是在 Beta 編譯器只接受一個空陣列([])。

#1.2 ── 我用一個 UNNotificationCategory 型態的常數 debitOverdraftNotifCategory 呼叫 setNotificationCategories(_:),藉此來註冊 App 的通知類型。請記得我們的目的,我們只關心「每個 categories 參數裡的物件,都含有一個字串來識別通知的類型。」

建立並發送一則本地通知

就如先前所說,我不會在建立及發送通知上詳述。我的程式碼非常可讀,亦有附上註解,而你也可以隨時到這個或是這個連結閱讀 Apple 官方文件,來了解整個過程。

編註:你也可以參考我們的 User Notification framework 教學文章。

為了確認 User Notification 的效果,我們先建立通知內容,並定義一個觸發器來決定何時實際發送通知,然後將它們放在一起來設定發送通知的時程。我把下列程式碼加入到範例 App ViewController.swift 檔案裡的 sendNotificationButtonTapped(_:) 方法內,把 @IBAction 連接到 App Storyboard 裡的一個按鈕。程式碼內亦有註解,應該足以解釋建立和發送通知的整個過程。請注意,當中有兩行帶有相應編號的程式碼,我將會在下文詳細解釋。以下是程式碼:

#2.1 ── 在 #1.1#1.2 步驟中,我指派字串 “debitOverdraftNotification” 給 UNNotificationCategoryidentifier 屬性,並把它註冊到 UNUserNotificationCenter。關於 categoryIdentifier 屬性,Apple 官方是這麼說的:

為此屬性分配一個數值時,該值應與 App 之前註冊 UNNotificationCategory 物件的 identifier 屬性匹配。如果你指定的字串與註冊的類別不匹配,系統會在沒有客製化操作的情況下顯示通知,也不會通過你的應用擴展進行路由。

如下文所見,我們希望透過後面撰寫的擴展來發送通知。

如果你對推播有興趣,根據 Apple,為了把 Category Identifier 加入到一個遠端通知裡,你需要包含 category 鍵在 JSON 中的 aps Dictionary 裡,就像下面所顯示的:

#2.2 ── 在預設狀態中,當 App 在前景時,通知不會顯示出來。你可以更改這個行為,不過我們不會在這裡實作。為了繞過這點,我設定通知在相關的要求被傳送到 add(_:withCompletionHandler:) 的 10 秒後發送。為了簡化它,我點擊與上面 @IBAction 連接的按鈕,然後按下 “Home” 鍵。這樣我的 “iOS 12 Notifications” App 就會進入到背景,並等待通知出現。

請注意,我必須在通知上點擊、按住並下拉,來顯示這新的 iOS 12 通知功能。(我假設你們會需要在 iOS 12 測試通知,來找出它們是否有延伸 UI。)藍色的 “info” (i) 圖像及藍色的 “Cover” 按鈕是我為客製化通知介面加進去的。

不過我的經驗與 Apple 官方在測試文件上的描述有點不太一樣:

當 iOS 設備收到包含提醒的通知時,系統將分兩個階段顯示提醒內容。一開始的時候,它會顯示縮寫橫幅,帶有標題、副標題和通知的 2-4 行正文文本。如果使用者按下橫幅,iOS 會顯示完整的通知界面,包括任何與通知相關的操作。系統為橫幅提供界面,但你可以使用通知內容應用擴展來客製化完整界面。

撰寫程式碼來客製化通知 UI

留意在上面引用段落的最後一句:「你可以使用通知內容應用擴展來客製化完整界面」,所以我們可以加入一個通知內容應用擴展到我們的範例 App 專案裡。這個擴展加入了一個調用 UNNotificationContentExtension 協定的 UIViewController 子類別。

加入一個新的擴展到 Xcode 10 專案

在講述如何加入 iOS 12 通知內容應用擴展到範例 App 之前,讓我分享一下 Apple 官方所說的功能吧:

通知內容應用擴展可以管理顯示客製化通知界面的視圖控制器。該視圖控制器可以補充或替換通知的默認系統界面。你可以使用視圖控制器來:

• 客製化物件的位置,包括提醒的標題、副標題和正文。
• 使用不同字體或樣式替換界面元素。
• 顯示 App 的特定數據(例如,儲存於通知內容特定鍵中的數據。)
• 包含客製化圖片或品牌。

應用擴展必須使用現有數據來配置視圖控制器,例如通知的內容和應用擴展包中的文件。如果使用 App Group 在 App 和應用擴展之間共享數據,你就可以使用在 App Group 中的任何文件。為了確保能夠及時提交通知,你需要盡早配置視圖。請不要執行任何長期運行的任務,比如嘗試通過網絡檢索數據。

如果你一直有跟住我們的教學,請先確認一下你的範例 App 專案是在 Xcode 10 裡開啟。讓我們新增所需的擴展吧:

  1. 前往 File -> New -> Target,就像這樣:
  2. 在打開的面板中,確認選擇的是 iOS 分頁,然後選擇 Notification Content Extension 模版,接著按下 Next 按鈕,就如下圖所示:

  3. 在下一個畫面裡,在 Product Name 區塊填上內容,然後為你的擴展選擇一個有效的 Team,接著按下 Finish 按鈕,像這樣:

  4. Xcode 會提示你啟用你新加入的擴展。點擊對話框內的 “Activate” 按鈕:

你的 Xcode 10 專案現在會有個虛擬的資料夾以及檔案,就如紅框所標示:

在 Xcode 中測試擴展

要記得,如果你想要在擴展的程式碼裡設定斷點、執行 App 與附隨的擴展,然後觸發那些斷點的話,你會需要在 Xcode 10 裡設定啟動 Scheme 到你的擴展,然後執行與 App 匹配的擴展。這相當容易,你可以跟著這樣做:

關於擴展的預設程式碼

由新擴展所提供的預設程式碼和 Storyboard 可以教你如何入手建立客製化通知 UI。開啟擴展的 Info.plist 檔案,然後檢視 NSExtension Dictionary。

你還記得我如何指派字串 “debitOverdraftNotification” 為 UNNotificationCategory 物件的 identifier 屬性,並用它來註冊 UNUserNotificationCenter 嗎?

因為你現在正在查看擴展的 Info.plist 檔案,所以讓我們來更改 UNNotificationExtensionCategory 的數值,從 “myNotificationCategory” 改為 “debitOverdraftNotification”。這會把我們的通知導引到擴展。以下是我們想要做的更動:

執行 App,然後自己看看:

設定 UNNotificationExtensionCategory 鍵為 “debitOverdraftNotification”,這是一個非常重要的步驟,讓這個擴展監聽 App 發送的通知,並且給予這個通知一個客製化 UI

請注意,通知 UI 裡的綠色矩形中,包含了我指派到 UNMutableNotificationContent 物件中 body 屬性的字串,UNMutableNotificationContent 是我在 ViewController.swift 檔案裡建立並作為通知發送的物件 。我設定的字串 “One-time overdraft fee is $25. Should we cover transaction?” 是顯示在 UIViewController 子類別 NotificationViewController 裡的 UILabel 上。說到 MVCUILabel 是在 MainInterface.storyboard 裡的 視圖,而 NotificationViewControllerNotificationViewController.swift 檔案裡的 控制器

我們已經看過了擴展的 Info.plist 檔案,所以現在讓我們簡單地檢視一下其他兩個檔案。以下是 MainInterface.storyboard 檔案:

這是基本的 Storyboard。你應該能夠檢視並理解它的架構。我已經 Control Click 了來向你展示 UILabel 有一個在 NotificationViewController 裡的 @IBOutlet。以下是 NotificationViewController.swift 檔案裡的內容:

因為 NotificationViewController 類別調用了 UNNotificationContentExtension 協定,所以它必須實作 didReceive(_:) 實例方法。這方法是通知內容被存取的地方,亦是讓來自 App 發送的訊息的 body 字串可以顯示在通知裡面的地方,就像我們在上面的 GIF 動畫看到那樣。

要注意的是,UNNotificationContentExtension 協定使用相同的命名法,比如說 didReceive(_:)UNUserNotificationCenterDelegate 會使用 userNotificationCenter(_:didReceive:withCompletionHandler:) 方法。

你現在應該清楚我會如何編碼通知內容應用擴展,來滿足上文所說的銀行帳戶 App 的要求,實作成果如下:

配置 Extension 的 Info.plist 檔案

當要開始製作通知內容應用擴展時,最好從 Info.plist 檔案開始。大部分的開發者能專注在 NSExtension Dictionary 的部份。我們將從配置四個鍵(稍後會再說明)開始。現在,進行編輯讓Info.plist 檔案以 Property List 格式開啟 :

或是以 Source Code (XML format) 格式開啟:

讓我們看看編輯或是新增了的四個鍵。這是關於前三個鍵的官方文件;然後 這個連結就是第四個鍵的資訊,特別是 “Support Interactive Controls” 這個段落。要注意的是,我預設使用了 Xcode 10 的 Storyboard 來設計 iPhone 8 的 UI:

1) UNNotificationExtensionCategory(必要):我們已經更換了裡面的數值。再一次提醒你,我指派了字串 “debitOverdraftNotification” 作為 UNNotificationCategory 物件的 identifier 屬性,並將其註冊到 UNUserNotificationCenter

2) UNNotificationExtensionInitialContentSizeRatio(必要):「它是一個浮點數 (floating-point number),代表著視圖控制器的視圖寬高比例的初始尺寸。」你現在可以保留它的預設值 1。我覺得 Apple 仍在糾結這個部分。當你新增擴展時,Apple 把 MainInterface.storyboardNotificationViewController 的高度固定為 37 pt。這樣的設定應該是正確的,因為一些人體工學的理由,你不會希望設計出一個過於複雜的 Notification UI 讓使用者感到困惑。我已經用這個鍵實驗過,所以選用了 0.12 這個數值,這是我從下面的方程式計算出來的:

我這樣做是因為如果 UNNotificationExtensionInitialContentSizeRatio 被設定為 1, iOS 12 會預設建立一個非常的通知,然後快速地自動更正通知的高度,讓它變短一點來顯示我的擴展視圖應有的尺寸。你主要會在第一次執行 App 或擴展時看到。

當更改擴展視圖控制器高度時請小心,而更改寬度時也要特別注意!

3) UNNotificationExtensionDefaultContentHidden: Apple 提供的定義已非常充足。比如說,我認為原本的通知是來傳送給所有需要做決定的使用者。我加入了一個圖標來標記我有一個 “Cover” 按鈕。如果他們想要支付 $25 來處理透支額度的話,他們可以按這個按鈕;如果不想支付,就可以藉由內建的 (X) 按鈕來撤掉這個通知。引用 Apple 的定義,它是「一個布林 (Boolean) 值。當它設定為 true 時,系統只會在通知介面裡顯示自己的客製化視圖控制器;當設定為 false 時,系統除了顯示自己的視圖控制器內容外,也會顯示預設的通知內容。不論如何設定,客製化動作按鈕和撤掉按鈕會一直顯示。如果你沒有指定這個鍵的數值的話,預設值會是 false。」

4) UNNotificationExtensionUserInteractionEnabled:如果你想你的客製化介面可以對使用者手勢作出回應,你就要設定這個為 true不需要做其他事情,例如是在擴展的視圖控制器裡加入手勢識別,如果這樣做的話,後果可以很可怕。

5) UNNotificationExtensionOverridesDefaultTitle:我在這次教學裡沒有用到這個鍵,但是你可以看到它的作用,它是「一個布林值。當設定為 true 時,系統會使用視圖控制器的 title 屬性來作為通知標題;當設定為 false 時,系統設定通知標題為 App 的名字。如果你沒有指定這個鍵的數值,預設值為 false。」

配置 Extension 的 MainInterface.storyboard 檔案

你已經讀過使用情境,亦看過 GIF 動畫來呈現範例 App 及擴展的運作。你應該能夠理解我的 MainInterface.storyboard 檔案:

UIImageView 的 @1x、@2x 及 @3x 圖檔存放在 Media.xcassets 資料夾內,我將其加入至擴展中。我已經將名為 “Cover” 的 UIButton 連結至 NotificationViewController.swift 檔案裡的 @IBActioncoverButtonTapped(_:) 方法。另外,我還有一些用來製作動畫的 @IBOutlet 變數。我會讓你自己好好研究一下範例 App 的 Storyboard。

編寫擴展的 NotificationViewController.swift 檔案

現在,你應該很了解我為通知客製化 UI 上做的事情。不過,我仍會利用一系列的步驟來講述程式碼,而每個步驟亦會有註解。我會讓你先看程式碼,然後再作解說。

#3.1 ── 你現在應該知道我為什麼需要引入這些程式庫。

#3.2 ── 因為 NotificationViewController 類別調用 UNNotificationContentExtension 協定,所以他必須實作 didReceive(_:) 實例方法。如果這個視圖控制器沒有調用 UNNotificationContentExtension 協定,就沒有用處了。

#3.3 ── 這些 Outlet 允許我添加動畫效果(淡入/淡出)到按鈕,為使用者提供舒服的體驗。

#3.4 ── 一開始時隱藏 “Your overdraft was covered!” 字樣的 UILabel。這只會在 “Cover” 被點擊時顯示。

#3.5 ── didReceive(_:) 只會在擴展偵測到通知時被呼叫。(為什麼呢?因為這個擴展的 Info.plist 註冊了 “debitOverdraftNotification” 通知分類類型。)這個方法是個做些像解碼銀行帳戶或交易數字等事的好地方。它也給了我們機會來解析在 Payload 之外的其它重要資訊,像是透支金額。

#3.6 ── 當使用者點擊客製化 UI 裡的 “Cover” 按鈕時,這個 @IBAction 就會被呼叫。雖然進行金融交易的方法有很多,但安全的 REST APIs 是現今最熱門、支援又好的方式。我們可以建立一個 Payload,把它加個密,來呼叫我們的 REST APIs,然後傳送交易來處理的透支。

#3.7 ── 當使用者點擊 “Cover” 按鈕時,我將它淡出然後同時淡入 “Your overdraft was covered!” 訊息。

請注意,你可以看到當你按下 “Cover” 按鈕時,我的擴展會作出回應,在控制台印出 “[Cover] button tapped.” 字樣。如果你將 Xcode 10 設定成上文「在 Xcode 中測試擴展」 段落中提到的樣子,你會看到這個成果:

總結

人總是在尋找更好的方法,讓自己保持連線、並更高效又方便地達成任務,藉此來節省時間。Apple 的通知技術已經前進了一大步,而在 iOS 12 亦已針對這些目標做了很大的改進。

在重要的事情上獲得通知、以及能夠在通知藉由客製化 UI 迅速回應,絕對是 iOS 的一大進步。一個支援許多 Apple 控制元件的客製化 UI,絕對比只能在通知底部添加按鈕更為進步。

我的銀行使用情境和雛形 App 突顯了 iOS 12 的全新功能,就是允許使用者即時回應事件。我亦想到幾個相關例子。

試想像在你發現信用卡出現了一些不尋常的大額消費,而信用卡提供商能夠傳送一則有多個按鈕的通知給你:一個讓客服人員立即打電話給你的按鈕、以及另一個顯示相關交易內容的按鈕。

又試想像你需要維持某些設施的溫度於一定範圍內。你可以將感測器連接到工作站 (workstation),而工作站能夠產生有滑桿的推播通知,讓你能夠即時調整設施的問題。

一切皆可能。有了 iOS 12 的新通知功能,你可以發揮想像力,大大改善你的 App。

譯者簡介:楊敦凱-目前於科技公司擔任 iOS Developer,工作之餘開發自有 iOS App同時關注網路上有趣的新玩意、話題及科技資訊。平時的興趣則是與自身專業無關的歷史、地理、棒球。來信請寄到:[email protected]

原文New in iOS 12: Adding a Custom UI and Interactivity in Local and Push Notifications


熱愛寫作的多產作家,亦是軟體工程師、設計師、和開發員。最近專注於 Objective-C 和 Swift 的 iOS 手機 App 開發。但對於 C#、C++、.NET、JavaScript、HTML、CSS、jQuery、SQL Server、MySQL、Oracle、Agile、Test Driven Development、Git、Continuous Integration、Responsive Web Design 等。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This