App Extension Programming Guide-App Extension Essentials AppExtension程式設計指南:擴充套件基礎3
Creating an App Extension 建立應用擴充套件
iOS8/OS X v10.10
翻譯自蘋果官方文件 App Extension Programming Guide--App Extensions Essentials
建立應用擴充套件
iOS8/OS X v10.10
當你準備好開發一個應用擴充套件時,可以從選擇一個支援你想執行的任務的擴充套件點開始。然後選擇適用於你所選的擴充套件點的Xcode模板,如果需要的話,可使用自定義程式碼和自定義使用者介面來增強預設檔案。最後,在你除錯並優化你的應用擴充套件之後,就可以打包進你的應用程式給使用者使用了。
從選擇正確的擴充套件點開始
每個擴充套件點都針對一個定義明確的使用者場景,你首先要清楚這個應用能為使用者提供什麼樣的功能,所以要選擇一個支援該功能的擴充套件點。這是非常關鍵的,因為每個擴充套件點定義了不同的API,為你提供不同的功能開發,所以如果選錯了擴充套件點,那麼很有可能無法實現想要的功能。表1-1列出了iOS和OS X中支援的所有擴充套件點。
選定了一個適用於應用擴充套件的擴充套件點後,在你的containing app中會有一個新的Target。新增應用擴充套件Target最簡單的方式就是使用Xcode提供的模板,這些模板為擴充套件點提供了預配置。
你可以通過選單選擇 File > New > Target在你的Xcode工程中新增一個新Target。在左邊的側邊欄中,選擇iOS或OS X的Application Extension選項,然後在右邊皮膚呈現的Xcode 模板中選擇你想要建立的應用擴充套件模板,如下圖所示:
選擇好模板,並在工程中新增Target,在自定義擴充套件程式碼之前,你可以試著編譯並執行一下專案。如果你是基於Xcode提供的模板建立的擴充套件,那麼當編譯成功後,就會生成一個副檔名為 .appex的應用擴充套件包。
注意64位的架構: 一個應用程式擴充套件在Architectures設定中必須要包含arm64的架構,否則在上傳App Store時會被拒絕。建立完一個應用擴充套件後,你可以在Xcode的“Standard architectures”設定選項中設定arm64架構。
如果你的包含擴充套件的應用程式使用了一些嵌入框架,那麼你的應用程式也必須要包含arm64架構,否則上傳App Store時也會被拒絕。
關於64位架構開發環境的更多資訊,請根據你的target平臺參閱64-Bit Transition Guide for Cocoa Touch或者64-Bit Transition Guide for Cocoa。
在大多數情況下,你可以通過在System Preferences或Settings中啟用應用擴充套件或者授予許可權來測試預設的應用擴充套件,然後可以通過其他應用來訪問它。比如你可以在OS X系統中通過Safari中開啟一個頁面來測試分享擴充套件,點選分享按鈕,然後選擇你要測試的擴充套件即可。
檢查預設的擴充套件模板
一般情況下,每個擴充套件模板都包含一個屬性列表檔案(就是Info.plist檔案),一個View Controller類和一個預設的UI,這些都是擴充套件點定義的。預設的View Controller類(或principal class)都含有擴充套件點對應功能的方法,需要我們去實現。
應用擴充套件Target的Info.plist檔案除了識別擴充套件點外還羅列了應用擴充套件的詳細資訊。該檔案至少包括NSExtension字典以及擴充套件點指定的其他鍵值字典。。比如NSExtensionPointIdentifier的key值就是擴充套件點的反向DNS名稱
,比如com.apple.widget-extension。在應用擴充套件的NSExtension字典中還有其他的Key和值:
NSExtensionAttributes:這是一個描述擴充套件點具體屬性的字典,就像照片編輯擴充套件中的PHSupportedMediaTypes一樣。
NSExtensionPrincipalClass:這是擴充套件模板建立的主體檢視控制器類,比如SharingViewController。當載體應用程式(host app)呼叫擴充套件時,擴充套件點會例項化這個類。
NSExtensionMainStoryboard(只適用於iOS):擴充套件預設的Storyboard檔案,一般名為MainInterface。
除了在屬性列表中設定以外,擴充套件模板還可以設定一些預設的功能。每個擴充套件點可以定義擴充套件點支援的適用於某個型別任務的功能。比如,一個iOS的Document Provider擴充套件就包含com.apple.security.application-groups的功能。
所有的OS X擴充套件模板都預設包含應用程式沙箱和com.apple.security.files.user-selected.read-only功能。如果你開發的擴充套件需要適用網路,或者訪問使用者的相簿,再或者需要訪問使用者的通訊錄,那麼你就需要額外定義這些功能。
注意:通常情況下,如果使用者允許主應用程式(containing app)訪問他們的私有資料,那麼主程式裡的擴充套件也同樣擁有該許可權。
響應“載體程式”(Host App)的請求
正如你在Understand How an Extension Works這篇文件中瞭解的,當使用者在host app選擇一個擴充套件,並使host app向擴充套件發出請求時,就會開啟擴充套件。說的再詳細一點,你的擴充套件會根據使用者的操作接收到請求,幫使用者執行任務,然後完成或者關閉請求。比如說,一個分享擴充套件收到了來自host app的請求,然後該擴充套件會開啟相應檢視來響應請求。然後使用者在該介面中編輯要分享的內容,使用者可以選擇傳送或者不傳送,最後擴充套件根據使用者的行為響應完成還是關閉請求。
當host app向擴充套件發出請求時,一般都會指明擴充套件執行的上下文。對於很多擴充套件來說,最重要的一部分就是要設定一個工作項,這個工作項就是使用者在使用這個擴充套件時要處理的工作項。比如說,一個分享擴充套件的上下文可能就包含使用者選擇的想要分享的一段文字。
當host app發出一個請求(通常就是呼叫beginRequestWithExtensionContext:
方法),你的擴充套件就可以用主試圖控制器中的 extensionContext
屬性來獲得上下文,然後使用 NSExtensionContext
類解析上下文並獲得工作項。通常,在檢視控制器的 loadView 方法中解析上下文並獲得工作項,這樣在載入完檢視後就可以將資訊顯示在檢視介面中了。獲取擴充套件上下文可以使用如下程式碼:
NSExtensionContext *myExtensionContext = [self extensionContext];
複製程式碼
有意思的是內容物件的 inputItems 屬性,它包含了應用擴充套件需要使用的工作項。inputItems 屬性包含一個 NSExtensionItem 型別的陣列,陣列的每一個成員都包含一個可執行的工作項。從上下文中獲取工作項可以使用如下程式碼:
NSArray *inputItems = [myExtensionContext inputItems];
複製程式碼
每個 NSExtensionItem
物件都包含若干個描述工作項的屬性,比如標題、文字內容、附件資訊、使用者資訊。
注意 attachments
屬性,它包含一個與工作項相關聯的媒體資料陣列。比如說一個分享請求的工作項,那麼 attachments 屬性可能就包含使用者想要分享網頁中的資訊。
當使用者工作項處理完後,應用擴充套件通常會給使用者兩個選擇,完成任務或取消任務。根據使用者的選擇,擴充套件會呼叫 completeRequestReturningItems:expirationHandler:completion: 方法,把工作項返回給 host app,或者會呼叫 cancelRequestWithError: 方法,返回一個錯誤程式碼。
在iOS中,你的應用程式擴充套件可能需要更多的時間去處理潛在的需長時間處理的任務,比如說往網上上傳內容。這種情況下,你就要使用 NSURLSession
類將該任務轉為後臺處理的任務。因為轉換到後臺處理任務需要用一個單獨的執行緒,所以在擴充套件完成主應用請求並關閉後仍然可以處理。想了解更多關於擴充套件中NSURLSession類的用法,請參閱:Performing Uploads and Downloads。
重要:雖然你可以設定一個後臺URL來上傳或下載任務,但是有一些型別的後臺任務,比如支援 VoIp 或者在後臺播放音樂的任務,是不能通過擴充套件來實現的。
如果你應用擴充套件的Info.plist檔案中含有 UIBackgroundModes 關鍵字,那麼在上傳App Store時會被拒絕。(想了解更多關於 UIBackgroundModes 關鍵字的內容,請參閱 Information Property List Key Reference 中的 UIBackgroundModes)
優化效率和效能
應用擴充套件在記憶體使用優先順序上要明顯低於當前執行的應用程式。不管是 iOS 還是 OS X,系統都會毫不猶豫地終止擴充套件,因為使用者想返回到host app中的主要目標中。但是也有一些應用擴充套件的記憶體使用優先順序要高於其他擴充套件,比如說widgets就要求要高一些,因為它要實時的顯示一些資訊,因為一般使用者更傾向於同時開啟多個widgets。
你的應用擴充套件並不擁有主迴圈執行緒,你要遵循這一規則,以便讓擴充套件在主迴圈執行緒中發揮最好的效能。比如說,如果你的應用擴充套件阻止了主迴圈執行緒,那麼在使用者使用主應用程式的過程中會造成非常糟糕的使用者體驗效果。 我們需要記住的一點是,GPU在系統中是一個共享的資源,所以應用擴充套件不會得到很高的優先順序照顧。比如說,如果你正在玩一個對GPU消耗很高的遊戲,那麼由於記憶體壓力比較大,它就有可能會選擇關閉Today widget。
設計一個精簡的使用者介面
大多數的擴充套件點都要求你向使用者提供一些自定義的介面,它在使用者開啟你的應用擴充套件時呈現給使用者。通常情況下,應用擴充套件的介面要儘可能的簡約、內斂,並主要關注一個單一任務。為了提高效能和使用者體驗效果,你要避免與該擴充套件功能無關的介面出現。
大多數Xcode 提供的應用擴充套件模板都包含一個初始介面檔案,你可以從這個檔案中設計介面開始。
在使用者的慣性思維中,一般他們都是通過應用擴充套件的圖示來辨識擴充套件功能的。通常情況下,應用擴充套件的圖示和它的主體應用的圖示是一致的。使用主體應用的圖示作為應用擴充套件的圖示有利於使用者去判斷這個擴充套件的來源,也就是說讓使用者確信這個擴充套件是來源於他們安裝的主體應用。當然也有一些例外。
在iOS中,自定義的Action擴充套件的圖示使用其主體應用的圖示。 在OS X中,如果一個擴充套件的主體程式只是用來安裝擴充套件的封裝包,那麼該擴充套件要提供一個單獨的圖示,否則都會使用主體應用的圖示。
應用擴充套件要使用一個簡短,語義明確的名字,這能讓幫助使用者把擴充套件和你的主應用程式聯絡起來,並且能讓他們在系統中更好的管理應用擴充套件。通過應用擴充套件 Target
的 CFBundleDisplayName
屬性來設定它的名稱,你可以在Info.plist
檔案中修改它。如果你沒有給 CFBundleDisplayName
設定值,也就是沒有給擴充套件設定名稱,那麼應用擴充套件會使用其主體應用的名稱,也就是CFBundleName
屬性中的值。
同時一些應用擴充套件也需要一個簡短的說明。比如說,OS X中的 Widget 擴充套件就會顯示一個簡單的描述,這能幫助使用者更好的選擇他們想要顯示在今日通知中的Widget擴充套件。擴充套件的描述可以在 InfoPlist.strings
檔案的widget.description
屬性中設定。
確保您的iOS App擴充套件適用於所有裝置
您必須確保提交的應用擴充套件程式是通用的:它必須適用於iPhone,iPod touch和iPad。無論您為包含的應用選擇哪個目標裝置系列,此要求均適用。Xcode中的應用程式擴充套件模板已針對通用目標裝置系列進行了正確配置。
要宣告您的應用擴充套件程式是通用的,請使用Xcode中的目標裝置系列構建設定,指定“iPhone / iPad”值。
確保您的應用擴充套件程式具有通用性
- 在keyboard project的Xcode專案導航器中,選擇專案檔案。 如果隱藏了專案編輯器中的project和targets列表,請顯示它。為此,請單擊project編輯器選項卡欄左側的按鈕。
- 在project 和 targets列表的targets組中,選擇應用擴充套件程式的targets。
- 在project編輯器中選擇Build Settings選項卡。 確保選中Basic 和 Combined按鈕,以便於您更輕鬆地找到所需的設定。
- 在project編輯器的Deployment group中,檢視“Targeted Device Family”設定。對於Debug和Release配置,值應為“iPhone / iPad”。 如果您找到不同的值,請將其更正為“iPhone / iPad”。
在設計和構建應用擴充套件時 使用Auto Layout和size classes類。測試您的應用擴充套件程式,以確保其符合您對所有裝置大小和方向的預期行為。如“ Simulator User Guide所述,在iOS模擬器中執行此操作,如果可能,還可以在兩個方向上對物理裝置進行測試。
請記住,即使您的主體應用(containing app)
僅針對iPad裝置系列,您所包含的應用擴充套件程式也會以相容模式執行顯示在的iPhone應用中。
重要 要通過App Review,您必須將“iPhone / iPad”(有時稱為 universal) )指定為應用擴充套件程式的目標裝置系列,無論您為
主體應用(containing app)
選擇哪個目標裝置系列。
在以後的iOS更新中,應用擴充套件程式僅在擴充套件程式主體應用本機支援的裝置(或裝置相容模式)上執行。例如,在相容模式下使用iPhone應用程式時,在只有iPad的
主體應用(containing app)
提供的擴充套件程式將不可見。為確保獲得最佳使用者體驗,我們建議您的主體應用(containing app)和其應用擴充套件程式是通用的。
除錯,配置和測試你的應用擴充套件
注意:要確保主體應用中的所有擴充套件都要使用相同簽名方式的程式碼。 Xcode專案中的所有target都必須以相同的方式進行程式碼簽名。例如,在測試期間,您可以使用臨時程式碼簽名或使用開發人員證書,但必須對專案中的所有target使用相同的方法。要提交到App Store,請使用您的分發證書來獲取所有目標。
使用 Xcode 除錯應用擴充套件和除錯其他程式基本是一樣的,但唯一點不同的是:你要選擇一個能訪問擴充套件的載體應用。當你編譯執行應用擴充套件後,Xcode 會執行載體應用,等待你去使用擴充套件並觸發除錯點來除錯擴充套件。你要在 scheme 中要為擴充套件指定一個載體應用(一個 scheme 封裝了 Target 編譯的說明)。
當你在主體應用工程中新增一個應用擴充套件的Target時,Xcode 就會為應用擴充套件預設建立一個 scheme。應用擴充套件的 scheme 可以讓你指定在除錯時由哪個應用程式來呼叫你的擴充套件,也就是指定一個除錯時的載體應用。預設情況下,當你編譯執行擴充套件時,會詢問你使用哪個載體應用來呼叫該擴充套件。
在你編譯執行應用擴充套件之前,你要確保你的擴充套件已經選擇了一個 scheme。你可以通過 Product > Scheme > MyExtensionName 或者使用 Xcode 選單欄撥出 scheme 選單並選擇 MyExtensionName 來設定應用擴充套件的 scheme。
注意:如果你執行主體應用的 scheme 代替應用擴充套件的 scheme,那麼你在編譯工程時Xcode會告訴你它正在等待除錯應用擴充套件。
當你編譯執行應用擴充套件時,Xcode會為你列出允許呼叫該擴充套件的載體應用程式。當你選擇一個載體應用程式並且執行後,偵錯程式就準備開始工作了,並準備好在你打的斷點處進行攔截。當你在載體應用程式中使用擴充套件時,就可以對應用擴充套件進行Debug除錯了。除錯應用擴充套件的方式和使用Xcode除錯其他程式一樣。
在OS X中,你在載體應用程式中訪問擴充套件之前,要確保該擴充套件是允許被使用的。一般情況下,在System Preferences的擴充套件皮膚中開啟或關閉擴充套件(你也可以在共享或Action選單中開啟應用擴充套件皮膚)。這裡要注意一點,在 OS X 中使用 Widget 模擬器除錯 Widget擴充套件時,是不需要對其進行開啟操作的。當你要除錯鍵盤擴充套件時,必須要開啟該擴充套件(你可以通過Settings > General > Keyboard > Keyboards開啟鍵盤擴充套件)。
在除錯時,Xcode會在OS X中建立一個持續的編譯應用擴充套件的會話。這意味著,如果你要使用OS X系統下的擴充套件,你需要使用Finder把它從構建處拷貝到類似 Applications folder的地方。
注意:在Xcode的除錯控制檯日誌中,應用擴充套件的二進位制值可能是和 CFBundleIdentifier 屬性關聯,而不是 CFBundleDisplayName 屬性。
由於應用擴充套件必須具有響應性和高效性,因此當執行應用擴充套件時,最好在除錯導航器中檢視除錯指標( the debug gauges)
。除錯指標顯示擴充套件在執行時如何使用CPU,記憶體和其他系統資源。當你發現類似佔用CPU資源出現異常的效能問題時,例如CPU使用率出現異常高峰,您可以使用Instruments來分析您的擴充套件,並確定需要改進的地方。通過在任何除錯儀表報告中單擊Instruments中的配置檔案,您可以在除錯會話期間開啟Instruments(要檢視除錯儀報告,請單擊除錯區域中的儀表)。想學習瞭解除錯監控器,請查閱Debug Your App;想學習瞭解Instruments,請查閱Instruments User Guide。
注意:在Xcode中選擇 Product > Profile可以直接在Instruments中編譯並執行應用擴充套件。Instruments使用方案的Profile部分中的可執行檔案集作為擴充套件的載體。
如果要使用Xcode提供的測試框架(比如XCTest APIs)測試應用擴充套件,你需要在主體應用程式中寫一些測試用例程式碼。想了解更多XCTest的知識,請參閱Testing with Xcode。
分發擴充套件主體應用程式
你無法直接將應用擴充套件上傳至App Store,除非它包含在主體應用程式中,並且你不能將應用擴充套件從一個應用程式中轉到另一個應用程式。
如果想讓使用者使用你的應用擴充套件,你必須提交一個主體應用程式到App Store中,並且主體應用程式如要有其他的功能,不能只包含應用擴充套件。
如果你想提交 OS X 應用程式擴充套件,推薦你將主體應用程式提交至App Store,但這也不是唯一的途徑。在OS X中,主體應用程式就可以只包含應用擴充套件,而不需要提供擴充套件外的其他功能。
注意:如果你不使用App Store來將主體應用程式和OS X 擴充套件交付給使用者,那麼在主體應用程式通過稽核前,Gatekeeper是不會允許應用擴充套件生效的。同時,如果你不將主體應用程式上傳至App Store,那麼該主體應用程式也不能簽署你的開發者ID名稱,所以使用者必須明確從主體應用程式中過載Gatekeeper,才可以讓應用擴充套件生效。