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 | } |