iOS APP之间数据共享

前言

iOS中的沙盒可以让平台更加的安全,这也是沙盒给用户带来的最主要好处。不过由于沙盒的严格限制,导致程序之间共享数据比较麻烦。

我们在iOS平台上想要实现不同App之间的内容分享一般有几种常用方式:

  1. 第一种是通过AirDrop实现不同设备的App之间文档和数据的分享;

  2. 第二种是给每个App定义一个URL Scheme,通过访问指定了URL Scheme的一个URL,实现直接访问一个APP

  3. 第三种是通过UIDocumentInteractionController或者是UIActivityViewController这俩个iOS SDK中封装好的类在App之间发送数据、分享数据和操作数据;

  4. 第四种是通过App Groups,在iOS 8的SDK中提供的扩展新特性实现跨App的数据操作和分享;这个功能需要APP使用同一个证书。

  5. 第五种是通过UIPasteboard剪切板,粘贴板的内容可以是文本、URL、图片和UIColor等,另一个app就可以根据粘贴板的名字去读取相关的信息。

  6. 第六种是Shared Keychain Access来实现数据共享,不过要使用同一个证书

  7. 还有一种集成第三方SDK实现的有限个App的数据分享,比如社交平台(QQ,微信,新浪微博等)给我们提供的官方SDK,或者是集成了多个社交平台的ShareSDK组件和友盟分享组件等

本文主要讨论UIDocumentInteractionController实现数据共享。

预览文档和呈现选项菜单

如果你的app需要打开它不支持的文件(PDF文件、图像文件,等等),或者需要将app的文件传输给另外一个允许接收此类型文件的app时。可以使用文件交互控制器(UIDocumentInteractionController类的实例)为用户提供可接收程序来处理文件,说的简单点就是通过Quick Look框架判断文档是否能被另一个app打开和预览。

UIDocumentInteractionController在iOS3.2中就已经存在了,使用起来非常灵活,功能也比较强大。它除了支持同设备上app之间的文档共享外,还可以实现文档的预览、打印、发邮件以及复制。

要使用一个文件交互控制器(UIDocumentInteractionController类的实例),需要以下步骤:

  • 为每个你想打开的文件创建一个UIDocumentInteractionController类的实例

  • 实现UIDocumentInteractionControllerDelegate代理

  • 显示预览窗口/显示菜单

一、创建实例

DocumentInteraction Controller使用静态方法interactionControllerWithURL创建实例,这个方法使用一个NSURL作为参数。

//创建实例
NSURL *filePath = [NSURL fileURLWithPath:path];
UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];

二、显示预览窗口

Document Interaction Controller对象使用presentPreviewAnimated方法弹出一个全屏的文档预览窗口。

BOOL b = [documentController presentPreviewAnimated:YES];

三、显示菜单

如果你不想在本应用里面打开文件,那么可以通过第三方应用打开预览文件。通过OptionsMenu(选项菜单),显示能够接收该类型文件的应用,由用户选择相应的操作。
显示菜单可以使用下列方法:

- presentOptionsMenuFromRect:inView:animated:
- presentOptionsMenuFromBarButtonItem:animated:
- presentOpenInMenuFromRect:inView:animated:
- presentOpenInMenuFromBarButtonItem:animated:

这些方法都是类似的,只是显示位置有区别而已。以下代码演示其中一个方法的使用。

CGRect navRect = self.navigationController.navigationBar.frame;
navRect.size = CGSizeMake(1500.0f, 40.0f);
[documentController presentOptionsMenuFromRect:navRect
inView:self.view
animated:YES];

四、使用委托

如果你显示一个Document Interaction Controller,则必需要为delegate属性用指定一个委托。让委托告诉DocumentInteraction Controller如何显示。

documentController.delegate = self;

委托对象需要实现一系列委托方法,最常见的包括:

- documentInteractionControllerViewControllerForPreview:
- documentInteractionControllerViewForPreview:
- documentInteractionControllerRectForPreview:

这3个方法在用户点击“快速查看”菜单时依次调用。

- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {
return self;
}
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller {
return self.view;
}

- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller {
  return self.view.frame;
}

//点击预览窗口的“Done”(完成)按钮时调用
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller {
}

分享文件

- (void)shareFile {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"皮卡丘"
ofType:@"jpeg"];

//创建实例
UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];

//设置代理
documentController.delegate = self;
BOOL canOpen = [documentController presentOpenInMenuFromRect:CGRectZero
inView:self.view
animated:YES];
if (!canOpen) {
NSLog(@"沒有程序可以打開要分享的文件");
}
}

预览文件(注册应用程序支持的文件类型)

- (void)preview {
if (!_path) {
return;
}

NSURL *fileURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self getURL], [_path lastPathComponent]]];

//创建实例
UIDocumentInteractionController *documentController =
[UIDocumentInteractionController
interactionControllerWithURL:fileURL];

//设置代理
documentController.delegate = self;

[documentController presentPreviewAnimated:YES];
}

向系统注册本应用

配置Info.plist文件

如果你的程序能够打开某种文件,你可以向系统进行注册。方便其他程序通过 iOS 的document interaction技术提供给用户一个选择,从而调用你的程序处理这些文件。

这需要在程序的Info.plist文件中添加CFBundleDocumentTypes
键(查看CoreFoundation Keys)。
系统将该键中包含的内容进行登记,这样其他程序就可以通document interaction controller访问到这些信息。

CFBundleDocumentTypes键是一个dictionary数组,每个dictionary表示了一个指定的文档类型。一个文档类型通常与某种文件类型是一一对应的。
但是,如果你的程序对多个文件类型采用同样的处理方式,你也可以把这些类型都分成一个组,统一视作一个文档类型。例如,你的程序中使用到的本地文档类型,有一个是旧格式的,还有一个新格式(似乎是影射微软office文档),则你可以将二者分成一组,都放到同一个文档类型下。这样,旧格式和新格式的文件都将显示为同一个文档类型,并以同样的方式打开。

CFBundleDocumentTypes数组中的每个 dictionary 可能包含以下键:

  • CFBundleTypeName
    指定文档类型名称。

  • CFBundleTypeIconFiles
    是一个数组,包含多个图片文件名,用于作为该文档的图标。

  • LSItemContentTypes
    是一个数组,包含多个UTI【Uniform Type Identifiers】类型的字符串。UTI
    类型是本文档类型(组)所包含的文件类型。

  • LSHandlerRank
    表示应用程序是“拥有”还是仅仅是“打开”这种类型而已。

下表列出了Info.plist中的一个CFBundleTypeName官方示例。

  1. 自定义文件格式的文档类型
<dict>
<key>CFBundleTypeName</key>
<string>My File Format</string>
<key>CFBundleTypeIconFiles</key>
<array>
<string>MySmallIcon.png</string>
<string>MyLargeIcon.png</string>
</array>
<key>LSItemContentTypes</key>
<array>
<string>com.example.myformat</string>
</array>
<key>LSHandlerRank</key>
<string>Owner</string>
</dict>
  1. 自己程序配置文件
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>com.appname.common-data</string>
<key>LSItemContentTypes</key>
<array>
<string>com.microsoft.powerpoint.ppt</string>
<string>public.item</string>
<string>com.microsoft.word.doc</string>
<string>com.adobe.pdf</string>
<string>com.microsoft.excel.xls</string>
<string>public.image</string>
<string>public.content</string>
<string>public.composite-content</string>
<string>public.archive</string>
<string>public.audio</string>
<string>public.movie</string>
<string>public.text</string>
<string>public.data</string>
</array>
</dict>
</array>

打开支持的文件类型

你可以在应用程序委托的application:didFinishLaunchingWithOptions:
方法中获得该文件的信息。如果你的程序要处理某些自定义的文件类型,你必须实现这个委托方法(而不是applicationDidFinishLaunching:方法) 并用这个方法启动应用程序。

application:didFinishLaunchingWithOptions:方法的option参数包含了要打开的文件的相关信息。尤其需要在程序中关心下列键:

  • UIApplicationLaunchOptionsURLKey
    包含了该文件的NSURL。

  • UIApplicationLaunchOptionsSourceApplicationKey
    包含了发送请求的应用程序的 Bundle ID。

  • UIApplicationLaunchOptionsAnnotationKey
    包含了源程序向目标程序传递的与该文件相关的属性列表对象

如果UIApplicationLaunchOptionsURLKey键存在,你的程序应当立即用该 URL 打开该文件并将内容呈现给用户。其他键可用于收集与打开的文件相关的参数和信息。

如果你的应用程序处于活跃状态,此时application:didFinishLaunchingWithOptions:方法是不会被调用的。需要实现application:openURL:options:方法

以下是参考别人的写法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_vc = [[ViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:_vc];

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];

if (launchOptions) {
NSString *str = [NSString stringWithFormat:@"\n发送请求的应用程序的 Bundle ID:%@\n\n文件的NSURL:%@\n\n文件相关的属性列表对象:%@",
launchOptions[UIApplicationLaunchOptionsSourceApplicationKey],
launchOptions[UIApplicationLaunchOptionsURLKey],
launchOptions[UIApplicationLaunchOptionsSourceApplicationKey]];

[[[UIAlertView alloc] initWithTitle:@""
message:str
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil] show];

_vc.path = [launchOptions[UIApplicationLaunchOptionsURLKey] description];
[_vc preview];
}
return YES;
}

- (BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options {
if (options) {
NSString *str = [NSString stringWithFormat:@"\n发送请求的应用程序的 Bundle ID:%@\n\n文件的NSURL:%@", options[UIApplicationOpenURLOptionsSourceApplicationKey], url];

[[[UIAlertView alloc] initWithTitle:@""
message:str
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil] show];

_vc.path = [url description];
[_vc preview];
}
return YES;
}

参考

SuperDannyUIDocumentInteractionController之程序间文档共享

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容