共享数据场景: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获取共享文件夹 }