iOS中Today擴展插件與宿主APP的交互
擴展是iOS8后系統開發給開發者的新開發思路與接口,每一個擴展都可以理解為一個簡單的小應用程序,只是其不是獨立存在的,要寄附于某一個主應用上。介紹iOS8擴展與Today插件的專題見如下博客:
iOS8中擴展與Today插件:http://my.oschina.net/u/2340880/blog/485533。
上述博客中只是簡單的介紹擴展的應用場景與創建Today擴展插件的方法,在實際開發中,由于擴展是寄附于某個應用程序之上的,因此其通常需要和宿主APP進行數據交互。創建Today擴展Target后,Xcode模板會自動幫助開發者生成一個ViewController作為主界面,開發者可以向其中添加展示UI或者交互控件,十分強大的是,Today擴展中是支持對UIViewController的切換的。需要注意,擴展與原APP是在不同的目錄結構中的,默認情況下,擴展與原APP的數據并不共享,代碼也不能復用。例如原APP中可能有網絡請求,數據持久化存儲等結構框架,擴展中不可以直接使用,擴展需要提供自己的網絡請求框架愛,數據持久化結構框架等。
如果項目是使用Pod進行的管理,則可以通過手動設置,使擴展中可以使用繼承的Pod庫,步驟如下:
完成上面兩張圖中的步驟,即可在擴展中使用Pod庫了。
Xcode擴展模板創建的ViewController會自動遵守NSWidgetProviding這個協議,這個協議中的方法和意義如下,開發者可以根據需求選擇實現:
//數據更新時調用的方法 系統會定期更新擴展- (void)widgetPerformUpdateWithCompletionHandler:(void(^)(NCUpdateResult result))completionHandler;//設置擴展UI邊距 注意 在使用Storyboard時,若要所見即所得 這個方法中需要返回UIEdgeInsetsZero- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets;
注意:Today擴展有其自己的plist配置文件,若需要對擴展進行配置,注意不要與宿主工程的plist文件混淆。
在Today擴展中打開原宿主APP使用openURL的方式,示例如下:
[viewController.extensionContextopenURL:[NSURLURLWithString:[NSStringstringWithFormat:@"MyApp://action=%@",@"action"]]completionHandler:nil];
上面打開原宿主APP的代碼中,MyApp是宿主APP配置的url Schemes,配置方式如下圖:
可以通過為url配置參數的方式來進行Today擴展與原宿主APP的信息交互,當擴展使用openURL的方式打開原宿主APP時,宿主APP會調用AppDelegate中的如下方法:
-(BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary *)options{//可以拿到url做相應邏輯處理UIAlertView* alert = [[UIAlertViewalloc]initWithTitle:url.absoluteString message:nildelegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];? ? [alert show];returnYES;}
上面介紹的openURL的方式只是進行跳轉交互,參數傳遞,并不能完成數據共享的需求,并且通過openURL的方式傳遞的數據是單向的。實際上,擴展和原宿主APP共享數據的應用場景十分廣泛,例如電商類宿主APP中拉取到一批商品信息,Today擴展中也需要這些信息進行展示,如果數據不共享,同樣的數據將在宿主APP內部和擴展都都請求一次,十分浪費,難很難同步。系統還提供了另一種方式來使宿主APP和Today擴展可以共享一塊存儲空間,這需要使用App Group技術來實現。開發者在進行App Group相關功能的測試時,必須與AppID進行關聯。
首先,需要開啟宿主APP的App Group,示例圖如下:
在Today擴展中,選擇相同的App Group,如下:
開啟了App Group功能后,Xcode會自動生成一套匹配的權限文件,如下:
配置工作完成后,可以通過兩種方式共享數據存儲空間,示例如下:
//使用數據共享的NSUserDefaults 這個NSUserDefaults是宿主APP與擴展所共享的NSUserDefaults* defaults =[NSUserDefaultsalloc]initWithSuiteName:@"開發者設置的AppGroup名稱"];//使用數據共享的文件目錄NSFileManager* manager = [NSFileManagerdefaultManager];//共享目錄NSURL* baseURL = [manager containerURLForSecurityApplicationGroupIdentifier:@"開發者設置的AppGroup名稱"];//找文件NSURL* filePath =? [baseURL URLByAppendingPathComponent:@"file"];
注意:還有一點細節需要注意,擴展與原宿主APP素材文件也是互相獨立的,要在擴展中使用的素材必須添加進擴展Target。
小提示:使用Xcode調試擴展時,需要運行擴展的Target,開發者有時會發現斷點失效,將模擬器上的應用刪掉,重新運行擴展即可解決。