簡單的說,App Extension 可讓開發者們拓展自定義的功能和內容到應用程序以外,並在用戶與其餘應用程序或系統交互時提供給用戶。html
你能夠建立一個app extension經過打開一個特殊的開關。例如ios
extension point : 啓用擴展的區域稱爲擴展點,也就是每個具備特定功能具體的extension。web
每一個擴展點提供了使用說明和API爲開發者去建立一個app extension.數據庫
下表是蘋果官方提供的全部Extension point列表數組
每個extension都是一個獨立的二進制文件,它獨立於用於發佈它的應用程序。咱們必須使用一個app去包含而且發佈你的extension。瀏覽器
host app : 咱們能夠把它理解爲宿主的App,可以調起extension的app被稱爲host app,好比:Safari app 裏面網頁分享到微信, Safari就是 host app ; widget的host app就是Today。緩存
Xcode Target 介紹安全
咱們經過Xcode新建一個target,Xcode會爲每一種extension point提供一個模板,每種模板裏會提供特定的源文件(源文件中會包含一些示例代碼)和設置信息,build這個target將會生成一個指定的二進制文件被添加到app’s bundle中。性能優化
當咱們要發佈的APP中包含app extension,開發者須要提交a containg app到 App Store. 當用戶安裝了這個containg app,extensions也會被隨之安裝。若是要開啓app extension功能,須要用戶手動去觸發它,觸發的地方多是containing app 內部也多是外部,例如Today widget 這個extension 須要用戶在通知中心點擊編輯按鈕去添加,還有好比須要在偏好設置中去管理的extensions等等.bash
app extension不是一個app, 它是爲了實現了一個特定的的任務,不一樣的extension point定義了不一樣的任務。
由於app extension不是一個app,它的生命週期和app是不一樣的,在大多狀況下,當用戶從app的UI上或者其餘活動視圖控制器中選擇開啓extension功能的選項時將會開始執行。
開始:A host app 定義了上下文提供給extension, 當它發送一個請求而且用戶正確相應後開啓extension的生命週期。
結束:一般會在完成host app收到的請求後當即終止。
例如,當用戶從Host app 中選擇一張圖片而後長按圖片點擊分享按鈕,用戶能夠從可分享的列表中進行選擇,選擇後將會完成分享的動做,此時分享的extension將會結束。
app extension 和 containing app將不可以直接交互,典型的,containing app可能尚未開始運行然而它包含的app extension已經在運行了。(例如,一個天氣的app,當你尚未打開它時,你能夠在Today Widget中看到今每天氣的信息)
在一個典型的請求響應事務中,系統表明的host app打開app extension, 經過host提供的extension上下文(context)傳遞數據, 這個extension經過界面的展現來執行一些任務,若是適用於extension的目的,返回數據給host.
上圖的虛線表明了app extension 和 containing app之間有限的交互。例如Today widget(只有 Today Extension 才支持經過調用其餘不能夠) 經過調用 NSExtensionContext類中openURL:completionHandler:
方法來要求系統去打開它的containing app.
正以下圖的讀寫箭頭所示,任意一個app extension和它的containing app可以在一個私有的shared container中分享數據。下圖展現了containing app , app extension 和 host app之間完整的交互方式。
注意:系統使用進程間通訊來確保host app和app extension能夠一塊兒工做從而實現一個完整的體驗。在你的代碼中,你沒必要考慮它們之間潛在的通訊規則,由於你使用了extension point 和 系統提供的上層API。
每一個extension point都針對一個特定的用戶場景。你的第一步是選擇支持你計劃交付功能的extension point.這個選擇將決定你你可以使用哪些API以及在特定情景下API的使用方式。
在iOS 和 OS X 中支持extension points, NSExtensionPointIdentifier中描述了它們的info.plist 中extension point中標識符的key.
爲你須要使用的app extension 選擇一個合適的extension point, 以後須要添加一個新的target在你的containing app中。使用Xcode template是最簡單的方式來添加一個app extension爲你的extension point提供預先配置好的target。
每一個app extension模板都包含一些配置文件如Info.plist,一個view controller class和一個默認的user interface,全部的這些將都由extension point定義。默認的view controller class能夠包含你要實現的extension point方法。
app extension target的Info.plist文件能夠標識extension point,並制定extension的詳細信息。這個文件至少要包含NSExtension這個key和這個extension point指定的含有鍵值對的字典。例如,NSExtensionPointIdentifier key將須要一個值來展現extension point反向DNS的名字,例如com.apple.widget-extension。下面列舉了一些在NSExtension字典中的鍵值對。
除了plist文件中的設置,默認狀況下,模板可能會設置一些功能。每一個extension point可以定義capabilities使extension point支持的任務類型變得有意義。例如,iOS 文檔Provider extension包含com.apple.security.application-groups entitlement.
OS X app extension 全部的模板將默認包含App Sandbox 和 com.apple.security.files.user-selected.read-only entitlements。若是須要去作一些其餘事情例如訪問網絡或者訪問照片,聯繫人等信息時你須要定義額外的capabilities對於extension。
在用戶接受一個帶有host app請求的app extension時app extension將被打開。app extension在收到請求後會打開幫助用戶執行特定任務,具體是完成或者取消任務取決於用戶在UI界面上的動做。例如,Share Extension收到一個host app請求以後經過彈出一個分享的view做爲響應。用戶將能夠經過這個View上選擇分享的目標或者是取消本次分享。
當一個host app發送一個請求給app extension,它將指定一個extension context.對於大部分extensions,context最重要的部分是在extension中設置用戶想要的items工做。例如,OS X Share extension 的 context可能包含一個用戶想要發送的文本選擇信息。
發請求
一旦Host app 發出請求(一般調用beginRequestWithExtensionContext:
方法),app extension可使用 extensionContext屬性在主view controller中獲取這個context.子view controllers也能經過連接訪問該屬性。
獲取Context
你可使用 NSExtensionContext類去檢查這個context而且獲得它的items。它能夠很好地在視圖控制器的loadView方法中後去這個context和Items以便在你的視圖中展現須要的信息。代碼以下 NSExtensionContext *myExtensionContext = self.extensionContext;
獲取Items
context 對象的inputItems屬性中包含了extension 須要使用的全部items。 NSArray *inputItems = myExtensionContext.inputItems;
每一個NSExtensionItem對象包含了該tiem各方面的不少屬性,例如它的title, content text, attachments, and user info.
注意attachments屬性包含了與item關聯的media data數組。例如,在關聯sharing request的item中,attachments 屬性包含了用戶想要去分享網頁的信息。
完成或取消任務
app extension給用戶一個選擇去完成或取消這次任務。咱們能夠經過completeRequestReturningItems:completionHandler:
方法來選擇返回NSExtensionItem對象給host app,或者cancelRequestWithError:
方法,返回一個錯誤代碼
注意:若是app extension調用
completeRequestReturningItems:completionHandler:
方法將提供一個completionHandler回調,系統要求你至少應該暫停app extension。
在iOS系統中,app extension 可能須要更多時間來完成一個潛在的耗時任務。例如上傳一個網頁的內容。在這種狀況下,你可使用NSURLSession class在後臺進行傳輸。由於後臺傳輸使用一個獨立的進程,傳輸會繼續,做爲一個低優先級的任務,extension 的進程在完成host app請求後應該被終止。
儘管咱們能夠在後臺完成上傳或下載的任務,可是其餘後臺任務例如支持VOIP或者後臺播放音樂等在extensions中不能被實現。若是app extension的Info.plist文件中包含UIBackgroundModes,發佈時將會被拒。
用戶感受靈活輕便。設計您的extension,以便在一秒鐘內完成目標。啓動速度過慢的擴展由系統終止。
原則:簡單,集中完成一個單一的任務。
注意:extension 的圖標要與app保持一致。
運行extension的內存限制遠小於前臺應用程序的內存限制。在這兩個平臺上,系統可能會主動終止extension,由於用戶但願返回主機應用程序中的host app。某些extension可能比其餘extension的內存限制更低,例如widgets必須特別高效,由於用戶可能同時打開多個widgets。
app extension 一旦開啓後是一條獨立的進程,不在containing app 主運行循環中,若是extension的回調在主運行循環,它可能有一個較差的用戶體驗在另外一個extension或app.
注意:app纔是系統資源的主要使用者,extension只是輔助。
你必須爲containing app 和 它的app extensions提供各自簽名信息(即建立不一樣的apple id但extension的app id 是app的子id).
使用Xcode去debug一個app extension就像去degbug其餘進程同樣,不一樣的是,在extension scheme 運行階段,你要指定一個host app做爲可執行文件。指定完成後,Xcode調試器將附加到該extension。
當你將Xcode運行的target選擇到你的extension時,在運行時將會彈出選擇一個app去運行,若是你想要每次都選用一個指定的,你須要進行一下的操做
編輯scheme,在彈出菜單中選擇Run,在右側的Info信息中將Executable選擇到咱們的host app.
在你build或run app extension以前,確保選擇了正確的extension’s scheme去調試。若是你直接去調試containing app scheme,Xcode不會將你的app extension附加上去除非你從containing app 中調用它。
在Xcode debug控制檯的日誌中,app extension的二進制文件可能與CFBundleIdentifier屬性的值相關聯,而不是CFBundleDisplayName屬性的值。
若是直接運行containing app在控制檯Log信息中看不到extension 文件中打印的信息。
咱們能夠建立一個framework在containing app 和app extension之間共享代碼。
咱們須要在包含extension的Target build setting中將「Require Only App-Extension-Safe API」設置爲YES。若是你不這麼設置,Xcode會提醒你「linking against dylib not safe for use in application extensions」.
爲了確保你的framework不包含app extensions不可用的API,若是您有一個包含此類API的自定義框架,您能夠從containing app中安全地連接到該框架,但不能與該應用程序包含的extensions共享該代碼。
當配置Xcode的project時,在Copy Files build phase中你必須選擇「Frameworks」做爲destination在你的framework中。
Deploying a Containing App to Older Versions of iOS
app extension 和 containing app 之間不能直接訪問彼此的存儲數據的容器。
但咱們能夠共享數據。
注意:app extension 的target工程不能夠直接訪問應用程序沙盒。
爲了使用數據共享功能,咱們須要在當前Target設置中的Capabilities中,打開App Group開關,而且在apple developer中建立APP Group,並向咱們當前target和containing app的app id中打開並配置app group功能。 Adding an App to an App Group
配置成功後,app extension和containing app可使用 NSUserDefaults API共享一個容器來同步須要交互的數據。咱們可使用下面的API
// Create and share access to an NSUserDefaults object
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName: @"com.example.domain.MyShareExtension"];
// Use the shared user defaults object to update the user account
[mySharedDefaults setObject:@"Hello World!" forKey:@"小東邪"];
[shared synchronize];
複製代碼
能夠經過下面的方法從shared container中讀取存入的數據。
- (NSString *)readDataFromNSUserDefaults {
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.wangzz"];
NSString *value = [shared valueForKey:@"小東邪"];
 return value;
}
複製代碼
下圖展現了containing app , extension 與shared container之間的關係。
注意:當咱們創建好一個共享容器時,containing app 和 每一個app extension 都具備對容器讀寫的權限,因此咱們必需要考慮數據同步的問題。
保存數據的時候必須指明group id;
並且要注意NSUserDefaults可以處理的數據只能是可plist化的對象,詳情見Property List Programming Guide。
爲了防止出現數據同步問題,不要忘記調用[shared synchronize];
在Share extension 和 Action extension(僅iOS)中,可讓用戶訪問web內容經過請求Safari運行JavaScript文件並將結果返回到擴展名。
3-6的具體步驟可參考蘋果官方文檔