iOS App文件共享

通过UIDocumentInteractionController或者是QLPreviewController来预览PDF等格式文件的时候,我们可以通过自带的UIActivityViewController把该文件共享出去或进行打印等处理。如图所示:

*行的AirDrop是iOS7之后给用户提供的一种在苹果设备之间共享文件的快捷方式,类似于安卓上的蓝牙无线传输文件。

第二行是通过文档类型关联技术识别的App的列表。

第三行是通过文档关联技术识别的Action的列表,表示对文件可进行的一些操作,如复制,打印,保存等。

我们知道在iOS系统下有一种安全体系–沙盒机制,每个iOS应用程序都是一个独立的文件系统,并且只能在自己的文件系统进行操作,所以iOS系统下并不能像安卓一样轻松取到其他应用程序下的文件。

既然我们能在自己的应用程序下预览文件时把文件共享到其他App中,那么反过来怎么能让其他App共享文件到我们App呢?

info.plist注册文件类型
我们需要在info.plist文件中,添加一个新的属性CFBundleDocumentTypes(实际上输入的是Document type),这是一个数组类型的属性,意思就是我们可以同时注册多个类型。而针对数组中的每一个元素,都有许多属性可以指定,详细的属性列表我们可以从官方文档上找到: Core Foundation Keys —- CFBundleDocumentTypes。这里列举我们在做iOS开发时常用的属性:

CFBundleTypeName

字符串类型,指定某种类型的别名,也就是用来指代我们规定的类型的别称,一般为了保持唯一性,我们使用UTI来标识。

CFBundleTypeIconFiles
数组类型,包含指定的png图标的文件名,指定代表某种类型的图标,而图标有具体的尺寸标识:

Device Sizes
iPad 64 x 64 pixels, 320 x 320 pixels
iPhone and iPod touch 22 x 29 pixels, 44 x 58 pixels (high resolution)
* LSItemContentTypes

数组类型,包含UTI字符串,指定我们的应用程序所有可以识别的文件类型集合
* LSHandlerRank
字符串类型,包含Owner,Default,Alternate,None四个可选值,指定对于某种类型的优先权级别,而Launcher Service会根据这个优先级别来排列显示的App的顺序。优先级别从高到低依次是Owner,Alternate,Default。None表示不接受这种类型。

我们选择Source code方式打开info.plist文件添加以下代码:

1 <key>CFBundleDocumentTypes</key>
2     <array>
3         <dict>
4             <key>CFBundleTypeName</key>
5             <string>PDF</string>
6             <key>LSHandlerRank</key>
7             <string>Owner</string>
8             <key>LSItemContentTypes</key>
9             <array>
10                 <string>com.adobe.pdf</string>
11             </array>
12         </dict>
13         <dict>
14             <key>CFBundleTypeName</key>
15             <string>Microsoft Word</string>
16             <key>LSHandlerRank</key>
17             <string>Alternate</string>
18             <key>LSItemContentTypes</key>
19             <array>
20                 <string>com.microsoft.word.doc</string>
21                 <string>com.microsoft.word.wordml</string>
22                 <string>org.openxmlformats.wordprocessingml.document</string>
23             </array>
24         </dict>
25         <dict>
26             <key>CFBundleTypeName</key>
27             <string>Microsoft Excel</string>
28             <key>LSHandlerRank</key>
29             <string>Alternate</string>
30             <key>LSItemContentTypes</key>
31             <array>
32                 <string>com.microsoft.excel.xls</string>
33                 <string>org.openxmlformats.spreadsheetml.sheet</string>
34             </array>
35         </dict>
36         <dict>
37             <key>CFBundleTypeIconFiles</key>
38             <array/>
39             <key>CFBundleTypeName</key>
40             <string>Microsoft PowerPoint</string>
41             <key>LSHandlerRank</key>
42             <string>Alternate</string>
43             <key>LSItemContentTypes</key>
44             <array>
45                 <string>com.microsoft.powerpoint.​ppt</string>
46                 <string>org.openxmlformats.presentationml.presentation</string>
47                 <string>public.presentation</string>
48             </array>
49         </dict>
50         <dict>
51             <key>CFBundleTypeName</key>
52             <string>Text</string>
53             <key>LSHandlerRank</key>
54             <string>Alternate</string>
55             <key>LSItemContentTypes</key>
56             <array>
57                 <string>public.text</string>
58                 <string>public.plain-text</string>
59                 <string>public.utf8-plain-text</string>
60                 <string>public.utf16-external-plain-​text</string>
61                 <string>public.utf16-plain-text</string>
62                 <string>com.apple.traditional-mac-​plain-text</string>
63                 <string>public.source-code</string>
64                 <string>public.c-source</string>
65                 <string>public.objective-c-source</string>
66                 <string>public.c-plus-plus-source</string>
67                 <string>public.objective-c-plus-​plus-source</string>
68                 <string>public.c-header</string>
69                 <string>public.c-plus-plus-header</string>
70                 <string>com.sun.java-source</string>
71                 <string>public.script</string>
72                 <string>public.shell-script</string>
73             </array>
74         </dict>
75         <dict>
76             <key>CFBundleTypeName</key>
77             <string>Rich Text</string>
78             <key>LSHandlerRank</key>
79             <string>Alternate</string>
80             <key>LSItemContentTypes</key>
81             <array>
82                 <string>public.rtf</string>
83                 <string>com.apple.rtfd</string>
84                 <string>com.apple.flat-rtfd</string>
85             </array>
86         </dict>
87         <dict>
88             <key>CFBundleTypeName</key>
89             <string>HTML</string>
90             <key>LSHandlerRank</key>
91             <string>Alternate</string>
92             <key>LSItemContentTypes</key>
93             <array>
94                 <string>public.html</string>
95                 <string>public.xhtml</string>
96             </array>
97         </dict>
98         <dict>
99             <key>CFBundleTypeName</key>
100             <string>Web Archive</string>
101             <key>LSHandlerRank</key>
102             <string>Alternate</string>
103             <key>LSItemContentTypes</key>
104             <array>
105                 <string>com.apple.webarchive</string>
106             </array>
107         </dict>
108         <dict>
109             <key>CFBundleTypeName</key>
110             <string>Image</string>
111             <key>LSHandlerRank</key>
112             <string>Alternate</string>
113             <key>LSItemContentTypes</key>
114             <array>
115                 <string>public.image</string>
116             </array>
117         </dict>
118         <dict>
119             <key>CFBundleTypeName</key>
120             <string>iWork Pages</string>
121             <key>LSHandlerRank</key>
122             <string>Alternate</string>
123             <key>LSItemContentTypes</key>
124             <array>
125                 <string>com.apple.page.pages</string>
126                 <string>com.apple.iwork.pages.pages</string>
127                 <string>com.apple.iwork.pages.template</string>
128             </array>
129         </dict>
130         <dict>
131             <key>CFBundleTypeName</key>
132             <string>iWork Numbers</string>
133             <key>LSHandlerRank</key>
134             <string>Alternate</string>
135             <key>LSItemContentTypes</key>
136             <array>
137                 <string>com.apple.numbers.numbers</string>
138                 <string>com.apple.iwork.numbers.numbers</string>
139                 <string>com.apple.iwork.numbers.template</string>
140             </array>
141         </dict>
142         <dict>
143             <key>CFBundleTypeName</key>
144             <string>iWork Keynote</string>
145             <key>LSHandlerRank</key>
146             <string>Alternate</string>
147             <key>LSItemContentTypes</key>
148             <array>
149                 <string>com.apple.keynote.key</string>
150                 <string>com.apple.iwork.keynote.key</string>
151                 <string>com.apple.iwork.keynote.kth</string>
152             </array>
153         </dict>
154         <dict>
155             <key>CFBundleTypeName</key>
156             <string>Audio</string>
157             <key>LSHandlerRank</key>
158             <string>Alternate</string>
159             <key>LSItemContentTypes</key>
160             <array>
161                 <string>public.audio</string>
162             </array>
163         </dict>
164         <dict>
165             <key>CFBundleTypeName</key>
166             <string>Movie</string>
167             <key>LSHandlerRank</key>
168             <string>Alternate</string>
169             <key>LSItemContentTypes</key>
170             <array>
171                 <string>public.movie</string>
172             </array>
173         </dict>
174         <dict>
175             <key>CFBundleTypeName</key>
176             <string>Archive</string>
177             <key>LSHandlerRank</key>
178             <string>Alternate</string>
179             <key>LSItemContentTypes</key>
180             <array>
181                 <string>public.archive</string>
182             </array>
183         </dict>
184     </array>

添加这些代码,你的App就可以支持大部分文件类型了,可以根据自己项目的需求,添加相关类型的代码,像我自己的项目只需要支持PDF和word格式的文件。添加完这些代码,我们选择Property list打开info.plist文件:

或者在info页面打开Document types列表

这个时候就代表我们已经成功的注册好了App支持的文件类型,这个时候我们在编译运行,然后再到其他App(我这边用的QQ)打开下载好的文件,这个时候出来的页面是这样的:

我们可以看到自己的App图标已经出现在第二栏的列表中,这个时候我们点击图标按钮即可把文件共享到自己App中。

如何处理共享文件
当点击图标按钮的时候,会跳转到我们自己的应用程序中,这个时候在AppDelegate.m会走- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options该回调方法。

但是在iOS9之前回调的是- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation,所以我们需要针对不同的设备版本做出改变。

我们可以在回调方法里进行文件处理操作,如将文件上传、文件预览、文件保存一些工作。在做文件预览的时候我们必定得跳转到对应的控制器中,这个时候我们首先得获取到当前的视图控制器

1 //获取当前屏幕显示的viewcontroller
2 – (UIViewController *)getCurrentVC
3 {
4     UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
5
6     UIViewController *currentVC = [self getCurrentVCFrom:rootViewController];
7
8     return currentVC;
9 }
10
11 – (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
12 {
13     UIViewController *currentVC;
14
15     if ([rootVC presentedViewController]) {
16         // 视图是被presented出来的
17
18         rootVC = [rootVC presentedViewController];
19     }
20
21     if ([rootVC isKindOfClass:[UITabBarController class]]) {
22         // 根视图为UITabBarController
23
24         currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];
25
26     } else if ([rootVC isKindOfClass:[UINavigationController class]]){
27         // 根视图为UINavigationController
28
29         currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];
30
31     } else {
32         // 根视图为非导航类
33
34         currentVC = rootVC;
35     }
36
37     return currentVC;
38 }

拿到控制器我们可以回到回调方法里进行跳转工作,我这边还是用UIDocumentInteractionController做文件预览

1 #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
2 – (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation{
3     // 判断传过来的url是否为文件类型
4     if ([url.scheme isEqualToString:@”file”]) {
5         _docVc = [UIDocumentInteractionController interactionControllerWithURL:url];
6         _docVc.delegate = self;
7         [_docVc presentPreviewAnimated:YES];
8
9     }
10
11 }
12
13 #else
14 – (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{
15     // 判断传过来的url是否为文件类型
16     if ([url.scheme isEqualToString:@”file”]) {
17         _docVc = [UIDocumentInteractionController interactionControllerWithURL:url];
18         _docVc.delegate = self;
19         [_docVc presentPreviewAnimated:YES];
20     }
21     return YES;
22 }
23 #endif
24
25 #pragma mark — UIDocumentInteractionControllerDelegate
26 – (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
27 {
28     // 返回当前控制器
29     return [self getCurrentVC];
30 }