iOS 8 應用擴展教程

已發表: 2022-03-11

以前很少有人嘗試過(看看這個),但蘋果的第一款 iPhone 定義了智能手機和移動操作系統的外觀。 蘋果在硬件和用戶體驗方面取得了令人難以置信的突破。 然而,我們經常忘記,它們還為移動操作系統的工作方式以及智能手機應用程序的開發方式設定了標準。

在應用程序之間建立混凝土牆,使它們完全隔離並且彼此不知道,是保證它們安全和保護數據的最佳方法。 所有活動都受到 iOS 的密切監控,應用程序只能在其範圍之外執行少數操作。

“禁慾是最好的保護!” - 但這其中的樂趣在哪裡?

他們花了一段時間; 如果你問我,時間太長了,但 Apple 決定使用 iOS 8 來找點樂子。 iOS 8 引入了一個名為 App Extensions 的新概念。 這個新功能並沒有打破應用程序之間的隔閡,但它打開了幾扇門,在一些應用程序之間提供了溫和而切實的聯繫。 最新的更新為 iOS 開發者提供了自定義 iOS 生態系統的選項,我們也渴望看到這條道路的開放。

ios 8 應用擴展

什麼是 iOS 8 應用擴展以及它們如何工作?

簡單來說,iOS 8 App Extensions 提供了一種與您的應用程序交互的新方法,無需啟動它或將其顯示在屏幕上。

正如預期的那樣,Apple 確保他們掌握一切,因此您的應用程序可以提供一些新的入口點:

  • 今天(也稱為小部件)- 顯示在通知中心的今天視圖中的擴展顯示簡要信息並允許執行快速任務。
  • 共享 - 一種擴展,使您的應用能夠與社交網絡和其他共享服務上的用戶共享內容。
  • 操作 - 一個擴展,允許在操作表中創建自定義操作按鈕,以讓用戶查看或轉換源自主機應用程序的內容。
  • 照片編輯 - 允許用戶在照片應用程序中編輯照片或視頻的擴展程序。
  • Document Provider - 用於允許其他應用訪問由您的應用管理的文檔的擴展。
  • 自定義鍵盤 - 替換系統鍵盤的擴展。

應用程序擴展不是獨立的應用程序。 他們正在提供應用程序的擴展功能(可以從其他應用程序訪問,稱為主機應用程序),旨在提高效率並專注於單個任務。 它們有自己的二進製文件、自己的代碼簽名和自己的元素集,但作為包含應用程序二進製文件的一部分通過 App Store 交付。 一個(包含)應用程序可以有多個擴展。 一旦用戶安裝了具有擴展的應用程序,它們將在 iOS 上可用。

讓我們看一個示例:用戶使用 Safari 找到一張圖片,點擊分享按鈕並選擇您的應用程序擴展進行分享。 Safari 與 iOS 社交框架“對話”,後者加載並呈現擴展。 擴展程序的代碼運行,使用系統的實例化通信通道傳遞數據,一旦任務完成 - Safari 就會關閉擴展程序視圖。 此後不久,系統終止進程,您的應用程序從未顯示在屏幕上。 但它完成了圖片分享功能。

iOS,使用進程間通信,負責確保宿主應用程序和應用程序擴展可以一起工作。 開發人員使用擴展點和系統提供的高級 API,因此他們不必擔心底層的通信機制。

生命週期

應用擴展生命週期

應用擴展的生命週期與 iOS 應用不同。 主機應用程序啟動擴展程序的生命週期作為對用戶操作的響應。 然後系統實例化應用程序擴展並在它們之間建立通信通道。 擴展程序的視圖使用主機應用程序請求中收到的項目顯示在主機應用程序的上下文中。 一旦顯示擴展的視圖,用戶就可以與之交互。 為了響應用戶的操作,擴展程序通過立即執行/取消任務來完成主機應用程序的請求,或者在必要時啟動後台進程來執行它。 在那之後,宿主應用程序會拆除擴展程序的視圖,並且用戶返回到宿主應用程序中的先前上下文。 一旦該過程完成,執行此過程的結果可能會返回到主機應用程序。 擴展程序通常在完成從主機應用程序接收到的請求(或啟動後台進程以執行它)後很快終止。

系統從宿主應用打開用戶操作的擴展,擴展顯示 UI,執行一些工作,並將數據返回給宿主應用(如果這適合擴展的類型)。 包含的應用程序在其擴展程序運行時甚至沒有運行。

創建應用程序擴展 - 使用 Today 擴展的動手示例

今日擴展,也稱為小部件,位於通知中心的今日視圖中。 它們是為用戶呈現最新內容(例如顯示天氣狀況)或執行快速任務(例如在待辦事項列表應用程序的小部件中標記已完成的事情)的好方法。 我必須在這裡指出,不支持鍵盤輸入

應用擴展的工作原理

讓我們創建一個 Today 擴展,它將顯示來自我們應用程序的最新信息(GitHub 上的代碼)。 為了運行此代碼,請確保您已經(重新)為項目配置了 App Group(選擇您的開發團隊,請記住 App Group 名稱必須是唯一的並遵循 Xcode 的說明)。

ios 8 應用擴展

今天的應用擴展

今天使用的應用程序擴展

創建一個新的小部件

正如我們之前所說,應用程序擴展不是獨立的應用程序。 我們需要一個包含應用程序,我們將在其上構建應用程序擴展。 一旦我們有了包含應用程序,我們選擇通過導航到 File -> New -> Target 到 Xcode 添加一個新目標。 從這裡我們為我們的新目標選擇模板以添加今日擴展。

創建小部件模板

在下一步中,我們可以選擇我們的產品名稱。 該名稱將出現在通知中心的“今天”視圖中。 在此步驟中也可以選擇在 Swift 和 Objective-C 之間選擇語言。 完成這些步驟後,Xcode 創建了一個 Today 模板,它為主體類(名為TodayViewController )提供了默認的頭文件和實現文件,其中包含Info.plist文件和一個接口文件(一個故事板或 .xib 文件)。 默認情況下, Info.plist文件如下所示:

 <key>NSExtension</key> <dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.widget-extension</string> </dict>

如果您不想使用模板提供的情節提要,請刪除NSExtensionMainStoryboard鍵並添加NSExtensionPrincipalClass鍵,並將視圖控制器的名稱作為值。

Today 小部件應該:

  • 確保內容始終是最新的
  • 適當地響應用戶交互
  • 表現良好(iOS 小部件必須明智地使用內存,否則它們將被系統終止)

共享數據和共享容器

應用程序擴展及其包含的應用程序都可以訪問其私有定義的共享容器中的共享數據 - 這是包含應用程序和擴展程序之間間接通信的一種方式。

你不只是喜歡 Apple 如何讓這些東西變得如此“簡單”嗎? :)

通過NSUserDefaults共享數據既簡單又常見。 默認情況下,擴展及其包含的應用程序使用單獨的NSUserDefaults數據集,並且不能訪問彼此的容器。 為了改變這種行為,iOS 引入了App Groups 。 在包含應用程序和擴展程序上啟用應用程序組後,不要使用[NSUserDefaults standardUserDefaults]使用[[NSUserDefaults alloc] initWithSuiteName:@"group.yourAppGroupName"]來訪問相同的共享容器。

更新小部件

為了確保內容始終是最新的,Today 擴展提供了一個 API 用於管理小部件的狀態和處理內容更新。 系統偶爾會捕獲小部件視圖的快照,因此當小部件變得可見時,會顯示最近的快照,直到它被實時版本的視圖替換。 符合NCWidgetProviding協議對於在拍攝快照之前更新小部件的狀態非常重要。 一旦小部件接收到widgetPerformUpdateWithCompletionHandler:調用,小部件的視圖應該使用最新的內容進行更新,並且應該使用以下常量之一調用完成處理程序來描述更新的結果:

  • NCUpdateResultNewData - 新內容需要重繪視圖
  • NCUpdateResultNoDate - 小部件不需要更新
  • NCUpdateResultFailed - 更新過程中發生錯誤
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { // Perform any setup necessary in order to update the view. // If an error is encountered, use NCUpdateResultFailed // If there's no update required, use NCUpdateResultNoData // If there's an update, use NCUpdateResultNewData [self updateTableView]; completionHandler(NCUpdateResultNewData); }

控制小部件何時可見

要控制小部件何時顯示,請使用NCWidgetController類中的setHasContent:forWidgetWithBundleIdentifier:方法。 此方法將讓您指定小部件內容的狀態。 它可以從小部件或其包含的應用程序(如果它處於活動狀態)中調用。 您可以將NOYES標誌傳遞給此方法,定義小部件內容是否已準備好。 如果內容尚未準備好,iOS 將不會在今日視圖打開時顯示您的小部件。

 NCWidgetController *widgetController = [[NCWidgetController alloc] init]; [widgetController setHasContent:YES forWidgetWithBundleIdentifier:@"com.your-company.your-app.your-widget"];

從小部件打開包含的應用程序

Today 小部件是唯一可以通過調用openURL:completionHandler:方法請求打開其包含應用程序的擴展。 為了確保包含應用程序以在用戶當前任務的上下文中有意義的方式打開,應定義自定義 URL 方案(小部件和包含應用程序都可以使用)。

 [self.extensionContext openURL:[NSURL URLWithString:@"customURLsheme://URLpath"] completionHandler:nil];

用戶界面注意事項

在設計你的小部件時,利用UIVisualEffectView類,記住應該模糊/充滿活力的視圖必須添加到contentView而不是直接添加到UIVisualEffectView 。 Widgets(符合NCWidgetProviding協議)應該在viewWillAppear:中加載緩存狀態,以便匹配上一個viewWillDisappear:的視圖狀態,然後在新數據到達時平滑過渡到新數據,這不是普通視圖的情況控制器(UI 在viewDidLoad中設置,並在viewWillAppear中處理動畫和加載數據)。 小部件應設計用於執行任務或單擊即可打開包含的應用程序。 鍵盤條目在小部件中不可用。 這意味著不應使用任何需要文本輸入的 UI。

無法將垂直和水平滾動條添加到小部件中。 或者更準確地說,可以添加滾動視圖,但滾動不起作用。 Today 擴展中滾動視圖中的水平滾動手勢將被通知中心攔截,這將導致從 Today 滾動到通知中心。 垂直滾動今日擴展內的滾動視圖將被今日視圖的滾動中斷。

技術說明

在這裡,我將指出一些在創建 App Extension 時要牢記的重要事項。

所有擴展共有的功能

以下各項適用於所有擴展:

  • sharedApplication 對像不受限制:應用程序擴展無法訪問 sharedApplication 對象,或使用與該對象相關的任何方法。

  • 攝像頭和麥克風不受限制:應用擴展程序無法訪問設備上的攝像頭或麥克風(但並非所有硬件元素都如此)。 這是某些 API 不可用的結果。 要訪問應用擴展中的某些硬件元素,您必須檢查其 API 是否可用於應用擴展(使用上述 API 可用性檢查)。

  • 大多數後台任務是不受限制的:應用擴展不能執行長時間運行的後台任務,除了啟動上傳或下載,這將在下面討論。

  • AirDrop 不受限制:應用程序擴展無法使用 AirDrop 接收(但可以發送)數據。

在後台上傳/下載

可以在後台執行的一項任務是使用NSURLSession object進行上傳/下載。

上傳/下載任務啟動後,擴展程序可以完成宿主應用程序的請求並終止,而不影響任務的結果。 如果在後台任務完成時擴展沒有運行,系統會在後台啟動包含應用程序,並調用應用程序的委託方法application:handleEventsForBackgroundURLSession:completionHandler:

擴展程序啟動後台NSURLSession任務的應用程序必須設置一個共享容器,包含應用程序及其擴展程序都可以訪問該容器。

確保為包含的應用程序及其每個應用程序擴展創建不同的後台會話(每個後台會話應該有一個唯一的標識符)。 這很重要,因為一次只有一個進程可以使用後台會話。

行動與分享

從編碼人員的角度來看,Action 和 Share 擴展之間的區別並不完全清楚,因為在實踐中它們非常相似。 Xcode 的共享擴展目標模板使用SLComposeServiceViewController ,它提供了可用於社交共享的標準撰寫視圖 UI,但這不是必需的。 共享擴展也可以直接從 UIViewController 繼承以實現完全自定義的設計,就像 Action 擴展可以從SLComposeServiceViewController繼承一樣。

這兩種類型的擴展之間的區別在於它們的使用方式。 使用 Action 擴展,您可以構建沒有自己的 UI 的擴展(例如,用於翻譯所選文本並將翻譯返回給主機應用程序的擴展)。 共享擴展可讓您直接從主機應用程序共享評論、照片、視頻、音頻、鏈接等。 UIActivityViewController驅動 Action 和 Share 擴展,其中 Share 擴展在頂行顯示為彩色圖標,而操作擴展在底行顯示為單色圖標(圖 2.1)。

禁止的 API

不能使用在頭文件中標有NS_EXTENSION_UNAVAILABLE宏或類似宏不可用的 API(例如:iOS 8 中的 HealthKit 和 EventKit UI 框架不適用於任何應用程序擴展)。

如果您在應用程序和擴展程序之間共享代碼,您必須記住,即使引用應用程序擴展程序不允許的 API 也會導致您的應用程序被 App Store 拒絕。 您可以選擇通過將共享類重新分解為層次結構來處理此問題,具有共同的父類和針對不同目標的不同子類。另一種方法是通過#ifdef檢查使用預處理器。 因為仍然沒有內置的目標條件,你必須創建你自己的。

另一個不錯的方法是創建自己的嵌入式框架。 只需確保它不包含任何不可用於擴展的 API。 要配置應用程序擴展以使用嵌入式框架,請導航到目標的構建設置並將“僅需要應用程序擴展安全 API”設置設置為是。 在配置 Xcode 項目時,在 Copy Files 構建階段,必須選擇“Frameworks”作為嵌入式框架的目標。 如果您選擇“SharedFrameworks”目的地,您的提交將被 App Store 拒絕。

關於向後兼容性的說明

儘管應用程序擴展僅在 iOS 8 之後才可用,但您可以使包含的應用程序可用於之前的 iOS 版本。

Apple 人機界面合規性

在設計應用程序擴展時,請牢記 Apple 的 iOS 人機界面指南。 無論您的包含應用程序支持哪種設備,您都必須確保您的應用程序擴展是通用的。 要確保應用程序擴展是通用的,請在 Xcode 中使用目標設備系列構建設置,指定“iPhone/iPad”值(有時稱為通用)。

結論

應用程序擴展無疑在 iOS 8 中具有最明顯的影響。由於 79% 的設備已經在使用 iOS 8(根據 App Store 於 2015 年 4 月 13 日進行的測量),應用程序擴展是應用程序應該利用的令人難以置信的功能。 通過結合 API 的限制以及在擴展程序及其包含的應用程序之間共享數據的方式,Apple 似乎設法在不損害其安全模型的情況下解決了對該平台的最大抱怨之一。 第三方應用程序仍然無法直接相互共享數據。 雖然這是一個非常新的概念,但看起來很有前途。