iOS-Document Interaction

iOS系统,提供了用于预览一些App不支持的文件的方法,也提供了注册App可以处理的文件格式的方法,以及通过Quick Look Framework进行打印的方法。

Previewing a Document or Presenting Options

当App需要与不支持的文件交互时,可以使用UIDocumentInteractionController对象来管理。UIDocumentInteractionControllerQuick Look Framework交互,并判断一个文件是否可被预览,可被其他App打开,或者两者皆可。

UIDocumentInteractionController经常用于处理一些下载的文件,例如Email中的附件,也可以用于处理其他App传过来的文件,同步目录为:

1
Documents/Shared

如果是直接预览,调用方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@interface ViewController ()<UIDocumentInteractionControllerDelegate>
@property (nonatomic, strong) UIDocumentInteractionController *docController;
@end

@implementation ViewController

- (void)open
{
NSURL *fileUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Background" ofType:@"png"]];
_docController = [UIDocumentInteractionController interactionControllerWithURL:fileUrl];
_docController.delegate = self;
if([_docController presentPreviewAnimated:YES]){
NSLog(@"Success..");
}else{
NSLog(@"Failed..");
}
}


- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
{
return self.navigationController;
}

@end

注意,UIDocumentInteractionControllerDelegate是必须的,回调也必须实现,且根据presentPreviewAnimated方法的返回值判断是否预览成功。

如果是提供多功能菜单给用户(预览、打开、复制等),调用方式如下:

1
2
3
4
5
if([_docController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES]){
NSLog(@"Success..");
}else{
NSLog(@"Failed..");
}

如果只提供单功能菜单给用户(打开),调用方式如下:

1
2
3
4
5
if([_docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES]){
NSLog(@"Success..");
}else{
NSLog(@"Failed..");
}

如果是查看文件的信息,调用方法如下:

1
NSLog(@"%@:%@ %@", controller.name, controller.URL, controller.icons);

如果是让其他App打开,需要传递额外的信息,调用方法如下:

1
controller.annotation = @"Addtional Information";

对应App的接收方法参考下文。

如果想要取消预览页面或者菜单,调用方法如下:

1
2
[_docController dismissPreviewAnimated:YES];
[_docController dismissMenuAnimated:YES];

Registering the File Types Your App Supports

如果App支持打开一些特定格式的文件,可以在Info.plist中添加CFBundleDocumentTypes字段进行注册。

格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dict>
<key>CFBundleTypeName</key>
<string>PNG</string>
<key>CFBundleTypeIconFiles</key>
<array>
<string>MySmallIcon.png</string>
<string>MyLargeIcon.png</string>
</array>
<key>LSItemContentTypes</key>
<array>
<string>public.png</string>
</array>
<key>LSHandlerRank</key>
<string>Default</string>
</dict>

其中,属性对应如下:

  • CFBundleTypeName:文件类型的名称;
  • CFBundleTypeIconFiles:文件类型的图标;
  • LSItemContentTypes:UTI格式的文件类型;
  • LSHandlerRank:定义了该文件类型是App独有的,还是App只是能打开。

CFBundleDocumentTypes字段是一个数组,所以可以声明多个类型,对于多个类型对应同一种的,例如.doc和.docx文件,可以在LSItemContentTypes中声明为同一种。这取决于App的属性,例如,对于图片处理App,出于处理上的考虑,.jpeg和.png文件可能声明为不同类型,而对于一个文件处理App,这两者可能都被声明为图片类。

Opening Supported File Types

对于声明支持的文件格式,系统随时可能会要求App来打开。在App启动函数中,需要对其立即进行处理:

1
2
3
4
5
6
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"%@", [launchOptions valueForKey:UIApplicationLaunchOptionsURLKey]);
NSLog(@"%@", [launchOptions valueForKey:UIApplicationLaunchOptionsSourceApplicationKey]);
NSLog(@"%@", [launchOptions valueForKey:UIApplicationLaunchOptionsAnnotationKey]);
return YES;
}

如果App已经打开了,那么在监听跳转函数中,对其进行处理:

1
2
3
4
5
6
7
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
NSLog(@"%@", url);
NSLog(@"%@", [options valueForKey:UIApplicationOpenURLOptionsSourceApplicationKey]);
NSLog(@"%@", [options valueForKey:UIApplicationOpenURLOptionsAnnotationKey]);
return YES;
}

从打印结果可以看出,实际上文件是被复制到以下目录:

1
/Documents/Inbox/

Using the Quick Look Framework

如果需要更好的控制文件的预览,例如,同时预览多个文件,可以直接使用Quick Look framework里面的QLPreviewController。使用方式如下:

先在项目中导入QuickLook.framework,然后调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#import "ViewController.h"
#import <QuickLook/QuickLook.h>

@interface ViewController ()<QLPreviewControllerDataSource>
@end

@implementation ViewController

- (void)preview
{
QLPreviewController *ql = [QLPreviewController new];
ql.dataSource = self;
[self.navigationController pushViewController:ql animated:YES];
}

- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return 2;
}

- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
if(index == 0)
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"png"]];
else
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"xlsx"]];
}

@end

Quick Look默认从路径的最后取文件名,如果要修改,可以通过以下方式修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface Item : NSObject <QLPreviewItem>

@end

@implementation Item

- (NSString *)previewItemTitle
{
return @"New Name";
}

- (NSURL *)previewItemURL
{
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"png"]];
}

@end

Quick Look自带打印功能,无需额外编码。另外,Quick Look支持的格式如下:

  • iWork文件;
  • Office文件;
  • Rich Text Format(RTF)文件;
  • PDF文件;
  • Image文件;
  • public.text类别下的文件,参考UTI;
  • Comma-separated value(csv)文件。