共享數據場景:git
iOS9以後用通用連接替換。github
//源應用 -(void)openTargetApp{ NSURL *url = [NSURL URLWithString:@"com.yourdomain.app://x-callback-url/quote?ticker=GOOG\%start=2014-01-01&end=2015-12-31"];//1.構造URL UIApplication *app = [UIApplication sharedApplication]; if ([app canOpenURL:url]){//2.檢查應用是否被安裝 //棄用openURL [app openURL:url];//3.啓動目標應用 [app openURL:url options:[NSDictionary new] completionHandler:^(BOOL success) { }]; } } //跳轉的應用 //廢棄 //-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ // return YES; //} -(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{//4.接受URL目標應用的委託回調 NSString *host = url.host;//5.從URL中提取必要的詳細信息 NSString *path = url.path; NSDictionary *params = [self parseQuery:url.query]; if ([@"x-cakkvacj-url" isEqualToString:host]){//6.處理URL if ([@"quote" isEqualToString:path]){ [self processQuoteUsingParameters:params]; } } return YES; } -(NSDictionary *)parseQuery:(NSString *)query{ NSMutableDictionary *dict = [NSMutableDictionary new]; if (query){ //以 & 和 = 做爲分隔符解析 NSArray *pairs = [query componentsSeparatedByString:@"&"];//8.解析查詢字符串 for (NSString *pair in pairs){ NSArray *kv = [pair componentsSeparatedByString:@"="]; NSString *key = [kv.firstObject stringByRemovingPercentEncoding]; NSString *value = [kv.lastObject stringByRemovingPercentEncoding]; [dict setObject:value forKey:key]; } } return [NSDictionary dictionaryWithDictionary:dict]; } -(void)processQuoteUsingParameters:(NSDictionary *)params{ NSString *ticker = [params objectForKey:@"ticker"]; NSString *startDate = [params objectForKey:@"start"]; NSString *endDate = [params objectForKey:@"end"];//9處理提取的值 }
官方文檔描述:剪貼板試試用於在應用以內或之間交換數據的安全且標準化的機制。許多操做取決於剪貼板,特別是賦值--剪切--粘貼。但你也能夠在其餘狀況下使用剪貼板,例如,在應用之間共享數據時。 剪貼板能夠是公共的或私有的。每一個剪貼板必須有惟一的名稱。 下圖顯示了一個具備兩個項目的剪貼板,每一個項目都有多種格式。正則表達式
共享數據的代碼示例:數組
//使用剪貼板共享數據 -(void)shareToPublicRTFData:(NSData *)rtfData text:(NSString *)text{ [[UIPasteboard generalPasteboard] setData:rtfData forPasteboardType:(NSString *)kUTTypeRTF];//設置已知類型kUTTypeRTF的二進制數據 [[UIPasteboard generalPasteboard] setData:text forPasteboardType:kUTTypePlainText]; [UIPasteboard generalPasteboard].string = text; [UIPasteboard generalPasteboard].strings = @[text]; } //假設數據的UTI類型是"com.yourdomain.app.type" -(void)shareToPublicCustomData:(NSData *) data{ [[UIPasteboard generalPasteboard] setData:data forPasteboardType:@"com.yourdomain.app.type"];//爲自定義類型設置二進制數據 } //共享至自定義命名的剪貼板 -(void)sharePrivatelyCustomData:(NSData *)data{ UIPasteboard *appPasteboard = [UIPasteboard pasteboardWithName:@"myApp" create:YES];//獲取具備給定名稱的剪貼板。若不存在,新建一個 [appPasteboard setData:data forPasteboardType:@"com.yourdomain.app.type"];//設置自定義剪貼板的數據。 } //從公共的剪貼板讀取 -(NSArray *)readShareStrings{ return [UIPasteboard generalPasteboard].strings; } //從命名的剪貼板讀取 -(NSData *)readPrivateData{ UIPasteboard *appPasteboard = [UIPasteboard pasteboardWithName:@"myApp" create:YES]; return [appPasteboard dataForPasteboardType:@"com.yourdomain.app.type"];//在自定義剪貼板中檢索自定義類型的數據 }
與深層連接相比,剪貼板優勢:緩存
最佳實踐:安全
UIDocumentInteractionController類容許應用利用設備上的其餘應用打開文檔。支持預覽,打印,郵寄和複印文檔。 UIDocumentInteractionController不是UIViewController的子類,必須配置一個控制器來預覽文檔 控制器的使用涉及兩個方面:發佈者和用戶服務器
1.發佈者app
統一類型標識符:(uniform type identifier,UTI) 是用來惟一標識某一項目類型的文本字符串. |
---|
內置的UTI用來標識公共系統對象。例如,文檔的public.document,JPEG圖像的public.jpeg和純文本的public.plain-text.dom
第三方開發人員添加本身的UTI,用於特定應用或專有用途。例如,用於PDF文檔的con.adobe.pdf和用於Apple Keynote文檔的com.apple.keynote.key 編輯器
#import <MobileCoreServices/MobileCoreServices.h>//1.UIDocumentInteraction類,相關類型以及常量定義在MobileCoreServices中 @interface ZJDocumentViewController : UIViewController<UIDocumentInteractionControllerDelegate>//2.所在控制器須要實現協議 @property (nonatomic , strong) UIDocumentInteractionController *docController; @end @implementation ZJDocumentViewController - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark document Delegate -(UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller{//3.此方法提供將要展現子視圖的UIViewController,必須實現 return self; } -(NSURL *)fileInDocsDirectory:(NSString *)filename{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docsDir = [paths firstObject]; NSString *fullPath = [docsDir stringByAppendingPathComponent:filename]; return [NSURL fileURLWithPath:fullPath]; } -(void)configureDIControlWithURL:(NSURL *)url uti:(NSString *) uti{//4.使用URL和UTI類型配置控制器 UIDocumentInteractionController *controller = [UIDocumentInteractionController interactionControllerWithURL:url];//5獲取URL指向的控制器引用 controller.delegate = self; controller.UTI = uti;//6指定委託和UTI類型 self.docController = controller;//7設置對控制器的強引用,確保控制器不會過早地被釋放 } #pragma Action -(IBAction)previewDocument:(id)sender{//預覽操做 NSURL *fileURL = [self fileInDocsDirectory:@"sample.pdf"];//8UIDocumentInteractionController對象引用的URL必須是操做系統可訪問的 if (fileURL){ [self configureDIControlWithURL:fileURL uti:(__bridge NSString *)kUTTypePDF]; [self.docController presentPreviewAnimat ed:YES];//預覽文檔 } } -(IBAction)openDocument:(id)sender{//打開PDF操做 NSURL *fileURL = [self fileInDocsDirectory:@"sample.pdf"]; if (fileURL){ [self configureDIControlWithURL:fileURL uti:(__bridge NSString *)kUTTypePDF]; [self.docController presentOpenInMenuFromRect:self.view.frame inView:self.view animated:YES];//顯示「在。。。。打開」的菜單,並讓用戶選擇某一應用打開文檔 } }
UIDocumentInteractionController須要一個NSURL來讀取內容,它必須指向一個使用文件scheme的本地文件。任何其餘scheme將引起異常。
2.消費者 文檔的消費者須要兩個基本步驟:註冊應用支持的文件類型,而後處理文檔內容。 要想註冊應用支持的文件類型,必須在應用的Info.plist中的文檔類型部分配置一下詳細信息。
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{//接受URL目標應用的委託回調 DDLogDebug("%s src :%@,url:%@", __PRETTY_FUNCTION__,src,url); return YES; }
UIActivityViewController提供了一個統一的服務接口,以便共享和執行與應用中數據有關的操做。 使用UIActivityViewController比使用UIDocumentInteractionController更容易,靈活。UIDocumentInteractionController只容許文件URL,可是用UIActivityViewController能夠共享一下一種或多種類型。
-(void)shareSomeContent{ NSString *text = @"Text to share"; NSURL *url = [NSURL URLWithString:@"http://github.com"]; UIImage *image = [UIImage imageNamed:@"blah"];//1要共享的元素 NSArray *item = @[text,url,image]; UIActivityViewController *ctrl = [[UIActivityViewController alloc]initWithActivityItems:item applicationActivities:nil]; ctrl.excludedActivityTypes = @[UIActivityTypePostToFacebook];//排除不容許的活動類型 [self presentViewController:ctrl animated:YES completion:nil]; }
共享鑰匙串:共享鑰匙串是在應用間安全分享數據的另外一種選擇。只有屬於相同羣組的ID,且使用相同證書籤名的應用才能共享數據。 在全部應用中實現單點登陸的惟一方法就是使用共享鑰匙串 要實如今同一發佈者的應用之間共享數據,這是惟一方法,且不須要從用戶正在使用的應用調用其餘應用
添加應用擴展條目:
實現數據共享的:
iOS8中添加的新類:
當建立操做擴展時,Xcode將建立一下的附加內容:
渲染源應用共享圖像的典型代碼:
- (void)viewDidLoad { [super viewDidLoad]; // Get the item[s] we're handling from the extension context. // For example, look for an image and place it into an image view. // Replace this with something appropriate for the type[s] your extension supports. BOOL imageFound = NO; for (NSExtensionItem *item in self.extensionContext.inputItems) {//1.掃描全部的擴展項 for (NSItemProvider *itemProvider in item.attachments) {//2.對於每一個項目而言,掃描全部的附件 if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) {//3.檢查附件是否爲圖像類型 // This is an image. We'll load it, then place it in our image view. __weak UIImageView *imageView = self.imageView; [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) {//4若是是,請檢索內容 if(image) { [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [imageView setImage:image];//5由於檢索回調能夠在非主線程上被調用,因此切換上下文,以便使用UIImage內容更新UIImageview }]; } }]; imageFound = YES; break; } } if (imageFound) { // We only handle one image, so stop looking for more. break; } } }
建立共享擴展時,Xcode將建立一下附加內容:
ShareViewController與如下生命週期事件掛鉤:
要想讀取共享文檔的內容,請使用UIDocumentPickerViewController。要呈現一個UI來共享文檔,則應該子類化UIDocumentPickerViewController。 使用文檔提供者須要iCloud受權。
1.打開/導入文檔
UIDocumentPickerViewController對象須要配置一下項目:
//協議UIDocumentPickerDelegate -(void)clickOpen{ NSArray *types = @[];// 能夠處理的UTI類型 UIDocumentPickerViewController *dpvc = [[UIDocumentPickerViewController alloc]initWithDocumentTypes:types inMode:UIDocumentPickerModeImport]; dpvc.delegate = self; [self.navigationController presentViewController:dpvc animated:YES completion:nil]; } //委託 -(void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url{ NSData *data = [NSData dataWithContentsOfURL:url];//url是本地文件URL,文檔的內容將複製到應用的tmp/DocumentPickerIncoming文件夾中 //處理數據,在編輯器中渲染,讓用戶編輯 } -(void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller{//取消選擇文檔回調 //獲取能夠展現一條信息,代表用戶沒有選擇文件 }
2.提供文檔 想成爲提供文檔的數據源,須要如下步驟:
@interface ZJDocumentPickerExtensionViewController : UIDocumentPickerExtensionViewController @end @interface ZJDocumentPickerExtensionViewController ()<UITableViewDelegate , UITableViewDataSource>//1.UIDocumentPickerExtensionViewController向用戶提供可用文檔和目標的列表 @property (nonatomic , strong) NSArray *allFiles; @end @interface HPEntry //2表示遠程文件條目的模型類 @property (nonatomic , copy) NSString *fileName; @property (nonatomic , copy) NSString *serverPath; @property (nonatomic , assign) NSUInteger *size; @property (nonatomic , copy) NSString *uti; @property (nonatomic , copy) NSURL *iconURL; @end @implementation ZJDocumentPickerExtensionViewController - (void)viewDidLoad { [super viewDidLoad]; //從服務器檢索文件的元數據並更新 //UITableview是很好的選擇 } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ HPEntry *selected = [self.allFiles objectAtIndex:indexPath.row]; //若是須要從服務器下載內容 若是文件內容在服務器上,則必須由應用擴展下載。最終的內容必須來自本地URL NSURL *localFileURL = [self.documentStorageURL URLByAppendingPathComponent:selected.fileName];//將內容保存到self.documentStorageURL文件夾中 [self dismissGrantingAccessToURL:localFileURL];//通知操做系統,編輯器應用必須被授予使用該文件的權限 } @end
雖然擴展老是與應用捆綁在一塊兒,但它在本身的進程中運行,並有本身的數據沙箱。
由於應用擴展在本身的沙箱中運行,因此它所以沒法直接訪問由容器應用直接存儲的數據(文檔文件夾,用戶默認數據,緩存文件夾,Core Data,SQLite,等等)
建立一個共享沙箱,容器應用和應用擴展均可以訪問它。應用羣組支持在多個應用之間共享數據---但與共享鑰匙串相似,應用必須使用相同的證書進行簽名。
-(void)sharedDataUsingAppGroups{ NSString *sharedGroupId = @"group.com.m10v.hperf";//1羣組ID;必須與Capabilities中提供的匹配 NSUserDefaults *defs = [[NSUserDefaults alloc]initWithSuiteName:sharedGroupId];//2初始化NSUserDefaults NSFileManager *fileMgr = [NSFileManager defaultManager]; NSURL *groupFolder = [fileMgr containerURLForSecurityApplicationGroupIdentifier:sharedGroupId];//3獲取共享文件夾 }