美文网首页OC-开发案例收集
iOS 调起第三方程序打开文件

iOS 调起第三方程序打开文件

作者: 路小白同学 | 来源:发表于2018-08-30 15:22 被阅读0次

    场景:
    1.使用airdrop分享文件
    2.使用其它app打开本app里面的文件,例如:图片,视频,pdf文件等等,
    3.保存到本地文件夹

    如果你有上面的任何一种需求那么看这篇文章就阔以了~。
    本文按照以下三点讲解:
    1.调起分享界面
    2.如何可以把我们的app显示到分享界面
    3.copy到我们app后如何处理

    一.调起分享界面
    这个比较简单,使用系统的UIDocumentInteractionController类,弹出后系统回自动识别能copy的app,回自己展示到弹出的面板上,系统自动处理了,很方便,不需要我们做多余的操作,比较简单,直接上代码:

    
    
     NSString *imageZipPath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"zip"];
            [self setupDocumentControllerWithURL:[NSURL fileURLWithPath:imageZipPath]];
    
            BOOL ret = NO;
            ret = [self.docInterCtrl
                   presentOpenInMenuFromRect:self.view.bounds
                   inView:self.view
                   animated:YES];
            if (!ret)
            {
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:Promt message:@"no app can open this file"preferredStyle:UIAlertControllerStyleAlert];
                
                UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"cancle"  style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                    
                }];
                
                [alertController addAction:cancelAction];
                
                [self presentViewController:alertController animated:YES completion:nil];
            }
    
    
    
    
    
    
    
    - (void)setupDocumentControllerWithURL:(NSURL *)url
    {
        if (self.docInterCtrl == nil) {
            self.docInterCtrl =
            [UIDocumentInteractionController interactionControllerWithURL:url];
            self.docInterCtrl.delegate = self;
        } else {
            self.docInterCtrl.URL = url;
        }
    }
    
    

    注意事项:把UIDocumentInteractionController声明为一个强指针strong类型的实例,声明为局部的话回过早释放,会发生崩溃。
    还可预览文件,这个需要事项相应的代理,比较简单,就不多说了。

    二.如何可以把我们的app显示到分享界面

    如果想我们的app可以打开别的app的文件,并展示到分享面板上,要配置一下info.plist文件,告诉系统哪些类型的文件需要使用UIDocumentInteractionController来打开。
    总结一下:

    <key>CFBundleDocumentTypes</key>
    
    <array>
    
    <dict>
    
    <key>CFBundleTypeName</key>
    
    <string>com.myapp.common-data</string>
    
    <key>LSHandlerRank</key>
    
    <string>Default</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>
    
    

    大概也就那么多,需要的直接粘贴就可以。

    三.保存到本地文件夹
    别的app的文件用我们的app打开,系统回将该文件copy到Documents/Inbox文件夹下,只需要对这个文件夹做处理及可以了。
    我的做法是对Inbox文件夹做一个监听,文件夹有变动做某些操作即可。
    监听文件夹使用的是苹果官方给出的类DirectoryWatcher

    DirectoryWatcher.h

    #import <Foundation/Foundation.h>
    
    @class DirectoryWatcher;
    
    @protocol DirectoryWatcherDelegate <NSObject>
    @required
    - (void)directoryDidChange:(DirectoryWatcher *)folderWatcher;
    @end
    
    @interface DirectoryWatcher : NSObject
    {
        id <DirectoryWatcherDelegate> __weak delegate;
        
        int dirFD;
        int kq;
        
        CFFileDescriptorRef dirKQRef;
    }
    
    @property (nonatomic, weak) id <DirectoryWatcherDelegate> delegate;
    
    + (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id<DirectoryWatcherDelegate>)watchDelegate;
    - (void)invalidate;
    
    @end
    
    

    DirectoryWatcher.m

    
    #import "DirectoryWatcher.h"
    
    #include <sys/types.h>
    #include <sys/event.h>
    #include <sys/time.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    #import <CoreFoundation/CoreFoundation.h>
    
    @interface DirectoryWatcher (DirectoryWatcherPrivate)
    
    - (BOOL)startMonitoringDirectory:(NSString *)dirPath;
    - (void)kqueueFired;
    
    @end
    
    @implementation DirectoryWatcher
    
    @synthesize delegate;
    
    - (instancetype)init
    {
        self = [super init];
        delegate = NULL;
        
        dirFD = -1;
        kq = -1;
        dirKQRef = NULL;
        
        return self;
    }
    
    - (void)dealloc
    {
        [self invalidate];
    }
    
    + (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id)watchDelegate
    {
        DirectoryWatcher *retVal = NULL;
        if ((watchDelegate != NULL) && (watchPath != NULL))
        {
            DirectoryWatcher *tempManager = [[DirectoryWatcher alloc] init];
            tempManager.delegate = watchDelegate;
            if ([tempManager startMonitoringDirectory: watchPath])
            {
                // Everything appears to be in order, so return the DirectoryWatcher.
                // Otherwise we'll fall through and return NULL.
                retVal = tempManager;
            }
        }
        return retVal;
    }
    
    - (void)invalidate
    {
        if (dirKQRef != NULL)
        {
            CFFileDescriptorInvalidate(dirKQRef);
            CFRelease(dirKQRef);
            dirKQRef = NULL;
            // We don't need to close the kq, CFFileDescriptorInvalidate closed it instead.
            // Change the value so no one thinks it's still live.
            kq = -1;
        }
        
        if(dirFD != -1)
        {
            close(dirFD);
            dirFD = -1;
        }
    }
    
    @end
    
    
    #pragma mark -
    
    @implementation DirectoryWatcher (DirectoryWatcherPrivate)
    
    - (void)kqueueFired
    {
        assert(kq >= 0);
        
        struct kevent   event;
        struct timespec timeout = {0, 0};
        int             eventCount;
        
        eventCount = kevent(kq, NULL, 0, &event, 1, &timeout);
        assert((eventCount >= 0) && (eventCount < 2));
        
        // call our delegate of the directory change
        [delegate directoryDidChange:self];
        
        CFFileDescriptorEnableCallBacks(dirKQRef, kCFFileDescriptorReadCallBack);
    }
    
    static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info)
    {
        DirectoryWatcher *obj;
        
        obj = (__bridge DirectoryWatcher *)info;
        assert([obj isKindOfClass:[DirectoryWatcher class]]);
        assert(kqRef == obj->dirKQRef);
        assert(callBackTypes == kCFFileDescriptorReadCallBack);
        
        [obj kqueueFired];
    }
    
    - (BOOL)startMonitoringDirectory:(NSString *)dirPath
    {
        // Double initializing is not going to work...
        if ((dirKQRef == NULL) && (dirFD == -1) && (kq == -1))
        {
            // Open the directory we're going to watch
            dirFD = open([dirPath fileSystemRepresentation], O_EVTONLY);
            if (dirFD >= 0)
            {
                // Create a kqueue for our event messages...
                kq = kqueue();
                if (kq >= 0)
                {
                    struct kevent eventToAdd;
                    eventToAdd.ident  = dirFD;
                    eventToAdd.filter = EVFILT_VNODE;
                    eventToAdd.flags  = EV_ADD | EV_CLEAR;
                    eventToAdd.fflags = NOTE_WRITE;
                    eventToAdd.data   = 0;
                    eventToAdd.udata  = NULL;
                    
                    int errNum = kevent(kq, &eventToAdd, 1, NULL, 0, NULL);
                    if (errNum == 0)
                    {
                        CFFileDescriptorContext context = { 0, (__bridge void *)(self), NULL, NULL, NULL };
                        CFRunLoopSourceRef      rls;
                        
                        // Passing true in the third argument so CFFileDescriptorInvalidate will close kq.
                        dirKQRef = CFFileDescriptorCreate(NULL, kq, true, KQCallback, &context);
                        if (dirKQRef != NULL)
                        {
                            rls = CFFileDescriptorCreateRunLoopSource(NULL, dirKQRef, 0);
                            if (rls != NULL)
                            {
                                CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
                                CFRelease(rls);
                                CFFileDescriptorEnableCallBacks(dirKQRef, kCFFileDescriptorReadCallBack);
                                
                                // If everything worked, return early and bypass shutting things down
                                return YES;
                            }
                            // Couldn't create a runloop source, invalidate and release the CFFileDescriptorRef
                            CFFileDescriptorInvalidate(dirKQRef);
                            CFRelease(dirKQRef);
                            dirKQRef = NULL;
                        }
                    }
                    // kq is active, but something failed, close the handle...
                    close(kq);
                    kq = -1;
                }
                // file handle is open, but something failed, close the handle...
                close(dirFD);
                dirFD = -1;
            }
        }
        return NO;
    }
    
    @end
    

    将这两个文件夹导入使用既可。

    eg:

    #import "DirVC.h"
    #import "DirectoryWatcher.h"
    @interface DirVC ()<DirectoryWatcherDelegate>
    @property (nonatomic, strong) DirectoryWatcher                *indoxWatcher;
    @end
    
    @implementation DirVC
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
        self.indoxWatcher = [DirectoryWatcher watchFolderWithPath:[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/Inbox"]] delegate:self];
    }
    
    #pragma mark - 文件夹变动监听代理
    - (void)directoryDidChange:(DirectoryWatcher *)folderWatcher
    {
        
    }
    @end
    

    这样就能监听相应文件夹的变化了,不过Inbox文件夹操作文件的时候有点问题,建议将文件copy到自己建的文件夹做相应的操作。
    如此就可以了,如果有更好的方法,欢迎私信交流~。

    相关文章

      网友评论

        本文标题:iOS 调起第三方程序打开文件

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