App Extension Programming Guide-App Extension Essentials AppExtension編程指南:擴展基礎3html
Creating an App Extension 建立應用擴展編程
iOS8/OS X v10.10數組
翻譯自蘋果官方文檔 App Extension Programming Guide--App Extensions Essentialsbash
iOS8/OS X v10.10網絡
當你準備好開發一個應用擴展時,能夠從選擇一個支持你想執行的任務的擴展點開始。而後選擇適用於你所選的擴展點的Xcode模板,若是須要的話,可以使用自定義代碼和自定義用戶界面來加強默認文件。最後,在你調試並優化你的應用擴展以後,就能夠打包進你的應用程序給用戶使用了。架構
每一個擴展點都針對一個定義明確的用戶場景,你首先要清楚這個應用能爲用戶提供什麼樣的功能,因此要選擇一個支持該功能的擴展點。這是很是關鍵的,由於每一個擴展點定義了不一樣的API,爲你提供不一樣的功能開發,因此若是選錯了擴展點,那麼頗有可能沒法實現想要的功能。表1-1列出了iOS和OS X中支持的全部擴展點。app
選定了一個適用於應用擴展的擴展點後,在你的containing app中會有一個新的Target。添加應用擴展Target最簡單的方式就是使用Xcode提供的模板,這些模板爲擴展點提供了預配置。框架
你能夠經過菜單選擇 File > New > Target在你的Xcode工程中添加一個新Target。在左邊的側邊欄中,選擇iOS或OS X的Application Extension選項,而後在右邊面板呈現的Xcode 模板中選擇你想要建立的應用擴展模板,以下圖所示:編輯器
選擇好模板,並在工程中添加Target,在自定義擴展代碼以前,你能夠試着編譯並運行一下項目。若是你是基於Xcode提供的模板建立的擴展,那麼當編譯成功後,就會生成一個擴展名爲 .appex的應用擴展包。ide
注意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)訪問他們的私有數據,那麼主程序裏的擴展也一樣擁有該權限。
正如你在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
屬性中設置。
您必須確保提交的應用擴展程序是通用的:它必須適用於iPhone,iPod touch和iPad。不管您爲包含的應用選擇哪一個目標設備系列,此要求均適用。Xcode中的應用程序擴展模板已針對通用目標設備系列進行了正確配置。
要聲明您的應用擴展程序是通用的,請使用Xcode中的目標設備系列構建設置,指定「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,纔可讓應用擴展生效。