App Extension
App Extension是從iOS8開始引入的一種應(yīng)用服務(wù)和交互方式。App Extension需要依賴于容器應(yīng)用(Containing App)發(fā)布和部署奶栖。常見的App Extension例如:Today Extension 和 Share Extension等圈驼。
-
容器應(yīng)用(Containing App) 和 宿主應(yīng)用(Host App):
- 容器應(yīng)用(Containing App):即由開發(fā)者開發(fā)的主應(yīng)用挫酿。
- 宿主應(yīng)用(Host App):能夠運(yùn)行Extension的應(yīng)用即為宿主應(yīng)用惨缆,Today Extension對應(yīng)的宿主應(yīng)用即為Today View辟灰。Share Extension對應(yīng)的宿主應(yīng)用即為能夠調(diào)起Share Extension的第三方應(yīng)用岔冀。
App Extension凯旭、Host App、Containing App 三者之間的關(guān)系:
- App Extension的基本生命周期:
- App Extension基本認(rèn)知:
- Extension不能單獨(dú)發(fā)布和部署使套,需要依賴于容器應(yīng)用(Containing App)罐呼。
- Extension和容器應(yīng)用(Containing App)的生命周期是獨(dú)立的,分別為兩個(gè)不同的進(jìn)程.
- Extemsion的運(yùn)行依賴于宿主應(yīng)用(Host App)侦高,生命周期由宿主應(yīng)用決定嫉柴。
- Extension作為一個(gè)單獨(dú)的target存在,但會隨著容器應(yīng)用(Containing App)的安裝和卸載而安裝和卸載奉呛。
- Extension需要獨(dú)立的證書用來打包和測試计螺。
widgets簡介
-
widgets介紹:
- 在iOS系統(tǒng)中有多種Extension,Today Extension作為其中之一,通常被稱為widgets侧馅。widgets讓用戶在鎖屏狀態(tài)下(鎖屏狀態(tài)下直接調(diào)起Containing App 需要解鎖后才能調(diào)起)和解鎖狀態(tài)下危尿,都可以通過widgets來瀏覽應(yīng)用當(dāng)前的重要信息。
- 注:iOS和OS X系統(tǒng)都支持widgets馁痴,下文僅以iOS系統(tǒng)中的widgets展開說明谊娇。
-
widgets的正確使用姿勢:
適當(dāng)響應(yīng)用戶交互。
展示最新的Containing App內(nèi)容罗晕。
正確的使用widgets并盡可能減少其內(nèi)存占用济欢,否則系統(tǒng)會終止widgets。
注:根據(jù)官方推薦的widgets使用方式小渊,widgets中不應(yīng)該出現(xiàn)復(fù)雜的交互或者做耗時(shí)的操作法褥。
-
widgets中對UI的約束:
widgets中不支持滑動類型的交互設(shè)計(jì)。
widgets中不支持鍵盤酬屉,所以不應(yīng)出現(xiàn)輸入框類設(shè)計(jì)半等。
注:widgets視圖寬度是由today view來決定的,高度局部可調(diào)呐萨。以4.7屏幕為例杀饵,高度最大不要超過528,最小為110谬擦,寬度為359切距。
-
widgets生命周期:
- 第一次下拉Today View的時(shí)候widgets的生命周期即為viewController的生命周期,但是再次下拉Today View的時(shí)候由于系統(tǒng)采用快照的方式填充widgets惨远,直到其內(nèi)容更新或者UI被更新才被替換谜悟,所以再次下拉的時(shí)候起生命周期只會執(zhí)行viewWillAppear方法话肖。
創(chuàng)建widgets
- 打開Containing App的項(xiàng)目(即需要添加Today Extension的App),添加Extension的target。
- 選擇Today Extension葡幸。
- 添加Extension后的target最筒。
- 系統(tǒng)提供的默認(rèn)入口為MainInterface.storyboard文件。
- 如果使用代碼的方式自定義controller礼患,需要更改info.plist中NSExtensionMainStoryboard字段為NSExtensionPrincipalClass是钥,并修改入口為自定義類。
到這里Today Extension即widget已經(jīng)可以運(yùn)行并顯示了缅叠。
- 設(shè)置 App Extentsion 顯示名:
- 設(shè)置extension target的info.plist.
- iOS8-iOS9中Widget的AppIcon需要設(shè)置才能正確顯
- 可以在Extension Target中單獨(dú)創(chuàng)建Assets悄泥,然后添加AppIcon,也可以直接設(shè)置Containing App 中的Assets為 兩個(gè)Target共用肤粱。
- Extension Target -> Build Settings -> Assset Catalog Compiler - Options -> Asset Catalog App Icon Set Name 添加AppIcon名字即可弹囚。
-
widgets的更新機(jī)制說明:
- 為了保證當(dāng)前內(nèi)容為最新的內(nèi)容,系統(tǒng)偶爾會捕獲widgets的視圖快照领曼,當(dāng)widgets再次可見時(shí)鸥鹉,將顯示最新的快照,直到更新的實(shí)時(shí)版本替換為止庶骄。
-
widgets更新內(nèi)容
- 如果想要在系統(tǒng)捕獲快照前更新widgets的內(nèi)容毁渗,就要遵守NCWidgetProviding協(xié)議。并在方法
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult result))completionHandler;
中做內(nèi)容更新操作单刁。
- widgets 的隱藏和顯示
- 在沒有內(nèi)容或者沒有最新內(nèi)容的情況下可以選擇隱藏widgets灸异,系統(tǒng)指定了一種用來隱藏和顯示widgets的方式:
/**
* flag: BOOL 隱藏或者顯示
* bundleID: 要隱藏或者顯示的Extension的bundleId
*/
- (void)setHasContent:(BOOL)flag forWidgetWithBundleIdentifier:(NSString *)bundleID;
該方法在App Extension和Containing App中都可以調(diào)用,需要導(dǎo)入#import <NotificationCenter/NotificationCenter.h>
-
App Extension 和 Containing App 的通信:
- App Extension 和 Containing App 的通信需要分別對App Extension 和 Containing App 都開啟App Groups羔飞,二者使用相同的group肺樟。
-
App Extension 調(diào)起 Containing App:
- 通過自定義URL scheme的方式調(diào)起Containing App,系統(tǒng)提供了NSExtensionContext來實(shí)現(xiàn)這種方式。
[self.extensionContext openURL:[NSURL URLWithString:@"yourContainingAppCustomURLScheme://?parma=value"] completionHandler:^(BOOL success) { NSLog(@"%u", success); }];
- 自定義URL Scheme的方式在調(diào)起Containing App的同時(shí)也可以進(jìn)行數(shù)據(jù)傳遞逻淌。
-
通過group的方式實(shí)現(xiàn)App Extension 和 Containing App的數(shù)據(jù)共享
- group的方式會為App Extension 和 Containing App 創(chuàng)建一個(gè)二者都可以訪問的沙盒路徑么伯,所有需要共享的數(shù)據(jù)都存放在group路徑中。這個(gè)路徑以groupid為標(biāo)識唯一存在卡儒。
- 獲取group路徑:
NSString *suiteName = @"group.com.iticle.TodayExtensionDemo"; NSString *groupPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:suiteName]
* NSUserDefault * 創(chuàng)建一個(gè)group路徑下的userDefault: ```-objc NSString *suiteName = @"group.com.iticle.TodayExtensionDemo"; _userDefalut = [[NSUserDefaults alloc] initWithSuiteName:suiteName]; ``` * NSFileManager(推薦NSFileCoordination避免讀寫同步的問題) * Sqlite/CoreData
- group的方式會為App Extension 和 Containing App 創(chuàng)建一個(gè)二者都可以訪問的沙盒路徑么伯,所有需要共享的數(shù)據(jù)都存放在group路徑中。這個(gè)路徑以groupid為標(biāo)識唯一存在卡儒。
-
App Extension 和 Containing App 代碼共享:
- 共享自定義代碼
- framework
- 給需要共享的代碼添加一個(gè)target
- 共享Cocoapods引入的第三方庫
-
修改podfile文件田柔,添加App Extension的target依賴的第三方庫
img_4.png
-
- 共享自定義代碼
文章鏈接
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Today.html
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionCreation.html#//apple_ref/doc/uid/TP40014214-CH5-SW8
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html#//apple_ref/doc/uid/TP40014214-CH2-SW2
https://developer.apple.com/documentation/notificationcenter