美文网首页iOS进阶系统方法解读iOS学习
UIDocumentInteractionController之

UIDocumentInteractionController之

作者: SuperDanny | 来源:发表于2016-02-26 10:59 被阅读1457次

    iOS中的沙盒可以让平台更加的安全,这也是沙盒给用户带来的最主要好处。不过由于沙盒的严格限制,导致程序之间共享数据比较麻烦。一般在程序间共享文档可以通过UIDocumentInteractionController类实现通讯。它支持在你的app中用其他app预览和显示文档。同时也支持文件关联,允许其他app通过你的程序打开文件。这些技术包括了UIKit中提供的UIDocumentInteractionController类(UIDocumentInteractionController Class Reference),以及Quick Look框架(Quick Look Framework Reference)。

    本文将就如何在应用之间进行文件共享进行基本探究。还请大牛勿喷。

    苹果官方文档

    效果图

    文件共享 跨APP傳文件

    预览文档和呈现选项菜单

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

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

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

    1. 为每个你想打开的文件创建一个UIDocumentInteractionController类的实例
    2. 实现UIDocumentInteractionControllerDelegate代理
    3. 显示预览窗口/显示菜单。

    一、创建实例

    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

    是一个数组,包含多个UTIUniform 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.myapp.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;
    }
    

    再一次感谢您花费时间阅读这篇文章!

    微博: @Danny_吕昌辉
    博客: SuperDanny

    2015 年 12月 26日

    相关文章

      网友评论

      • flightlessBirdT:从iCould路径下拿到的数据为nil 请问博主怎么解决的这个问题?
      • 大头herob:楼主, 能否把这个demo共享一下,谢谢
      • 捞月亮的猴子:可以把自己app里面的文件,图片发送给别的app,然后在别的app里面社会化分享,编辑之类的。

      本文标题:UIDocumentInteractionController之

      本文链接:https://www.haomeiwen.com/subject/gucwkttx.html