玩转iOS开发:iOS 11 新特性《基于文档管理的App》

文章转至个人我的博客: https://cainluo.github.io/15132142909284.htmlhtml


众所周知iOS是一个封闭的系统, 每一个App都有一个属于它们本身的沙盒, AppApp之间是不能够互相访问的, 也因为这一点, iOS也能够被称为安全的系统.git

但这又会带来另外一个问题, 就是在管理文件的方式上比较复杂, 用户没法自由的浏览文件, 咱们须要专门的工具与流程才能在iOS上的应用程序之间共享文件.github

为了解决这个问题, 苹果爸爸在iOS 11里加入了一个用于管理文件的新工具:UIDocumentBrowserViewController.数组

这个全新的视图控制器可让咱们建立文档浏览器的App, 就像iOS 11上的新的文件App同样, 可让咱们自由管理全部可用位置上的文档.浏览器

PS: 这篇文章所演示的Demo在模拟器上是不能正常工做的, 最好备好iOS 11的设备来构建和测试该App.安全

转载声明:如须要转载该文章, 请联系做者, 而且注明出处, 以及不能擅自修改本文.app

开始前的知识补充

在开始建立这个项目以前, 咱们要了解iOS Document的工做原理, UIDocument是一个几乎运行在全部基于文档的应用的强大类.异步

UIDocument是一个物理文件的包装, 它能够在咱们的设备, iCloud上异步读取/写入文件, 自动保存, 文件版本控制等等.ide

虽然咱们能够不用强制性使用UIDocument, 但我仍是强烈建议去使用, 由于它能够帮咱们省下不少事情, 好比咱们须要在iPhoneMacBook上使用同一个iCloud文件, UIDocument就能够帮咱们处理全部的事情.工具

文档提供者

提供文档的App扩展容许其余App在你的文件上进行修改, 避免沙盒化.

UIDocumentPickerViewController就是该扩展的一部分, 这是其余App将显示你的App中选择文档的可视化界面.

提供文档的App容许其余App从它自己内导入文件, 这也就说明这个文件会被拷贝一份, 而原始文件则会保持不变.

固然咱们也能够容许其余App直接打开提供文档的App, 直接选择文件进行处理并覆盖源文件.

文档浏览器

这里咱们就讲UIDocumentBrowserViewController, 它是一种App的类型, 并非咱们所写的App的扩展名.

咱们定制的UIDocumentBrowserViewController子类必须是App的根视图, 换一句话说, 这就是iOS 11文档类型App的自定义实现.

开始写代码

这里咱们就拿颜色管理来做为场景, 在文件浏览器上去管理这些RGB颜色值, 它的扩展名也定义为.color.

咱们在建立好工程以后, 须要在Info.plist里把UISupportsDocumentBrowser设置为YES.

自定义扩展

咱们在使用.color扩展名的文件时, 须要用逗号分隔RGB颜色值, 好比白色的话, 咱们就会声明为255,255,255.

在此, 若是要使得文档浏览器中支持自定义的.color扩展名, 咱们须要注册一个新的赞成类型标识符(UTI这个东西在上一章文章的末尾就有介绍, ), 而后咱们须要将新的文件与咱们的App关联.

打开咱们的项目找到Info这个选项, 而后把咱们自定义的内容填好:

1

Exported UTIs所填写的内容:

  • Description: 文件名的描述, 这里输入RGB Color File
  • Identifier: 文件惟一标识符, 这里咱们输入为com.cainluo.colorExtension
  • Conforms To: UTI能够符合其余类型, 就好像父类子类同样, 这里咱们就写public.text, 由于咱们的.color也是简单的文本类型, 若是你是HTML的话, 那你能够写成public.html.

写完这个以后, 咱们还须要指定扩展名, 展开Additional exported UTI properties, 填入一个UTTypeTagSpecification字典, 而后在这个字典里建立一个名为public.filename-extension的数组, 最后再填入一个color对象.

定义好这个UTI以后, 咱们须要在Document Types填入对应的NameTypes, Name就填入Color Extension, Types就填入com.razeware.colorExtension.

2

若是你想了解更多关于UTI的内容, 能够去apple.co/2v0FiHO看看.

开始写代码

建立好对应的控制器以后, 咱们要设置一下:

self.delegate = self;
    self.allowsDocumentCreation = YES;
复制代码

而后遵照UIDocumentBrowserViewControllerDelegateUIViewControllerTransitioningDelegate两个协议, 而且实现它们的代理方法:

#pragma mark - UIViewControllerTransitioningDelegate
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                            presentingController:(UIViewController *)presenting
                                                                                sourceController:(UIViewController *)source {

    return self.documentBrowserTransitionController;
}

#pragma mark - UIDocumentBrowserViewControllerDelegate
- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
didRequestDocumentCreationWithHandler:(void(^)(NSURL *_Nullable urlToImport, UIDocumentBrowserImportMode importMode))importHandler {
    
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"ColorFile"
                                         withExtension:@"color"];
    
    importHandler(url, UIDocumentBrowserImportModeCopy);
}

- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
 didImportDocumentAtURL:(NSURL *)sourceURL
       toDestinationURL:(NSURL *)destinationURL {
 
    [self presentColorControllerWithDocument:[[ColorDocument alloc] initWithFileURL:destinationURL]];
}

- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
failedToImportDocumentAtURL:(NSURL *)documentURL
                  error:(NSError * _Nullable)error {
    
    [self showAlertViewControllerWithTitle:@"Failed" message:@"Failed to import"];
}


- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
    didPickDocumentURLs:(NSArray <NSURL *> *)documentURLs {
 
    [self presentColorControllerWithDocument:[[ColorDocument alloc] initWithFileURL:documentURLs[0]]];
}

- (NSArray<__kindof UIActivity *> *)documentBrowser:(UIDocumentBrowserViewController *)controller
               applicationActivitiesForDocumentURLs:(NSArray <NSURL *> *)documentURLs {
  
    ColorDocument *colorDocument = [[ColorDocument alloc] initWithFileURL:documentURLs[0]];
    
    return @[[[DocumentActivity alloc] initDocumentActivityWithColorDocument:colorDocument]];
}
复制代码

另外咱们还须要配置一些东西, 而且使得能够跳转到咱们须要跳转的编辑页面:

#pragma mark - Present Controller
- (void)presentColorControllerWithDocument:(ColorDocument *)colorDocument {
    
    UIStoryboard *mineStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    
    ColorController *colorController = [mineStoryboard instantiateViewControllerWithIdentifier:@"ColorController"];
    
    colorController.colorDocument = colorDocument;
    colorController.transitioningDelegate = self;
    
    self.documentBrowserTransitionController = [self transitionControllerForDocumentURL:colorDocument.fileURL];
    
    [self presentViewController:colorController animated:YES completion:nil];
}
复制代码

解释一下代理方法:

  1. 在成功导入新文档的时候会调用
- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
 didImportDocumentAtURL:(NSURL *)sourceURL
       toDestinationURL:(NSURL *)destinationURL;
复制代码
  1. 这是在将要呈现新文档时会调用, 它接受一个ColorDocument对象, 而ColorDocument又是UIDocument的子类, 负责保存和加载色彩文件, 待会咱们就会ColorController里预览和编辑颜色文件.
- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
didRequestDocumentCreationWithHandler:(void(^)(NSURL *_Nullable urlToImport, UIDocumentBrowserImportMode importMode))importHandler;
复制代码
  1. 在新文档没法导入时的时候就会调用, 好比当咱们无权访问importHandler回调中传递的文件时.
- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
failedToImportDocumentAtURL:(NSURL *)documentURL
                  error:(NSError * _Nullable)error;
复制代码
  1. 当用户选择要在文档浏览器中打开文件时, 就会调用该方法, UIDocumentBrowserViewController支持打开多个文件, 但咱们这里只须要使用一个, 因此就只去第一个.
- (void)documentBrowser:(UIDocumentBrowserViewController *)controller
    didPickDocumentURLs:(NSArray <NSURL *> *)documentURLs;
复制代码

预览与编辑界面

打开ColorController以后, 咱们须要设置一下, 看看是否能够读取对应的文件:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    ColorDocument *colorDocument = self.colorDocument;
    
    if (!colorDocument) {
        return;
    }
    
    if (colorDocument.documentState == UIDocumentStateNormal) {
        
        [self configControllerUI];
        
    } else {
        
        [colorDocument openWithCompletionHandler:^(BOOL success) {
            
            if (success) {
                
                [self configControllerUI];

            } else {
                
                [self showAlertViewControllerWithTitle:@"Error"
                                               message:@"Can't Open Document"];
            }
        }];
    }
}
复制代码

为了能够保存修改后的内容, 这里用了一个保存的方法:

- (IBAction)saveColorModel:(UIButton *)sender {
    
    ColorDocument *colorDocument = self.colorDocument;
    
    if (!colorDocument) {
        return;
    }

    colorDocument.colorModel = [[ColorModel alloc] initColorModelWithRedValue:self.redSlider.value
                                                                   greenValue:self.greenSlider.value
                                                                    blueValue:self.blueSlider.value];
    
    [colorDocument saveToURL:colorDocument.fileURL
            forSaveOperation:UIDocumentSaveForOverwriting
           completionHandler:^(BOOL success) {
        
               if (success) {
                   
                   [self showAlertViewControllerWithTitle:@"Success"
                                                  message:@"Saved file"];

               } else {
                   
                   [self showAlertViewControllerWithTitle:@"Error"
                                                  message:@"Failed to save file"];
               }
           }];
}
复制代码

从其余App中打开

若是咱们直接从文件App中打开颜色文件, 你会发现咱们的App是打开了, 但不会工做.

那是由于咱们的App.color扩展名关联, 但咱们的编辑页面并无显示.

因为这个文件是在别的App里打开的, 因此咱们须要在AppDelegate里处理这个事情:

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    
    if (!url.isFileURL) {
        
        return NO;
    }
    
    DocumentBrowserController *documentBrowserController = (DocumentBrowserController *)self.window.rootViewController;
    
    if (!documentBrowserController) {
        return NO;
    }
    
    [documentBrowserController revealDocumentAtURL:url
                                    importIfNeeded:YES
                                        completion:^(NSURL * _Nullable revealedDocumentURL, NSError * _Nullable error) {
                                            
                                            if (error) {
                                                return;
                                            }
    
                                            [documentBrowserController presentColorControllerWithDocument:[[ColorDocument alloc] initWithFileURL:revealedDocumentURL]];
                                        }];
    
    return YES;
}
复制代码

自定义文档浏览器

在这里面咱们还能够自定义一下咱们的文档浏览器样式:

#pragma mark - Custom Document Browser Controller
- (void)customDocumentBrowserController {
    
    self.view.tintColor = [UIColor colorNamed:@"MarineBlue"];
    
    self.browserUserInterfaceStyle = UIDocumentBrowserUserInterfaceStyleLight;
    
    UIDocumentBrowserAction *documentBrowserAction = [[UIDocumentBrowserAction alloc] initWithIdentifier:@"com.cainluo.action"
                                                                                          localizedTitle:@"Lighter Color"
                                                                                            availability:UIDocumentBrowserActionAvailabilityMenu
                                                                                                 handler:^(NSArray<NSURL *> * _Nonnull urls) {
        
                                                                                                     ColorDocument *colorDocument = [[ColorDocument alloc] initWithFileURL:urls[0]];
                                                                                                     
                                                                                                     [colorDocument openWithCompletionHandler:^(BOOL success) {
                                                                                                         
                                                                                                         if (success) {
                                                                                                             
                                                                                                             colorDocument.colorModel = [colorDocument.colorModel lighterColorWithToAdd:60];
                                                                                                             
                                                                                                             [self presentColorControllerWithDocument:colorDocument];
                                                                                                         }
                                                                                                     }];
                                                                                                 }];
    
    documentBrowserAction.supportedContentTypes = @[@"com.cainluo.colorExtension"];
    
    self.customActions = @[documentBrowserAction];
    
    UIBarButtonItem *aboutButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"About"
                                                                        style:UIBarButtonItemStylePlain
                                                                       target:self
                                                                       action:@selector(openAbout)];
    
    self.additionalTrailingNavigationBarButtonItems = @[aboutButtonItem];
}

- (void)openAbout {
    
    [self showAlertViewControllerWithTitle:@"关于咱们" message:@"Color Document 1.0 by Cain Luo"];
}
复制代码

这个颜色值是设置在Assets.xcassets中.

动画控制器

咱们能够为演示文稿添加一个动画:

@property (nonatomic, strong) UIDocumentBrowserTransitionController *documentBrowserTransitionController;
复制代码
#pragma mark - UIViewControllerTransitioningDelegate
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                            presentingController:(UIViewController *)presenting
                                                                                sourceController:(UIViewController *)source {

    return self.documentBrowserTransitionController;
}
复制代码

咱们刚刚的那个present方法里就写好了对应的配置:

colorController.transitioningDelegate = self;
    
    self.documentBrowserTransitionController = [self transitionControllerForDocumentURL:colorDocument.fileURL];
复制代码

自定义活动

最后面咱们还能够添加多一个活动列表, 这个时候咱们就须要定义一个UIActivity的自雷, 而且将.color文件以字符串的形式复制到粘贴板上:

- (instancetype)initDocumentActivityWithColorDocument:(ColorDocument *)colorDocument {
    
    self = [super init];

    if (self) {
        
        self.colorDocument = colorDocument;
    }
    
    return self;
}

+ (UIActivityCategory)activityCategory {
    
    return UIActivityCategoryAction;
}

- (UIActivityType)activityType {
    return @"ColorBrowserCopy";
}

- (NSString *)activityTitle {
    
    return @"Color Copy";
}

- (UIImage *)activityImage {
    
    return [UIImage imageNamed:@"copy_activity_icon"];
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
    
    return YES;
}

- (void)performActivity {
    
    [self.colorDocument openWithCompletionHandler:^(BOOL success) {
        
        if (success) {
            
            NSString *string = [self.colorDocument stringRepresentation];
            
            if (string) {
                
                [UIPasteboard generalPasteboard].string = string;
                
                [self activityDidFinish:YES];
            }
        }
    }];
}
复制代码

最后咱们用一个代理方法设置对应的活动事件:

#pragma mark - Custom Activity
- (NSArray<__kindof UIActivity *> *)documentBrowser:(UIDocumentBrowserViewController *)controller
               applicationActivitiesForDocumentURLs:(NSArray <NSURL *> *)documentURLs {
  
    ColorDocument *colorDocument = [[ColorDocument alloc] initWithFileURL:documentURLs[0]];
    
    return @[[[DocumentActivity alloc] initDocumentActivityWithColorDocument:colorDocument]];
}
复制代码

最终效果

3

4

工程

https://github.com/CainLuo/iOS-11-Characteristic/tree/master/6.Document

最后

码字很费脑, 看官赏点饭钱可好

支付宝
相关文章
相关标签/搜索