Iphone 使用QuickLook framework或UiDocumentInteractionController显示加密文件

Iphone 使用QuickLook framework或UiDocumentInteractionController显示加密文件,iphone,ios,ipad,quicklook,uidocumentinteraction,Iphone,Ios,Ipad,Quicklook,Uidocumentinteraction,我在本地存储了一个加密的word/excel/pdf文件,需要在iPad应用程序中预览。我知道QLPreviewController或UiDocumentInteractionController可用于预览这些文件。我很会用这个 - (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index { return

我在本地存储了一个加密的word/excel/pdf文件,需要在iPad应用程序中预览。我知道QLPreviewController或UiDocumentInteractionController可用于预览这些文件。我很会用这个

- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index {

    return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documents objectAtIndex:index] ofType:nil]];
}
-(id)previewController:(QLPreviewController*)控制器PreviewWitematindex:(NSInteger)索引{
返回[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:[documents objectAtIndex:index],类型为:nil]];
}
但文件是加密的,当我解密它时,我会得到NSData对象。我如何在这两种方式中加载NSData

此外,我知道我可以很好地将NSData存储为本地文件并在预览中加载。但是存在一个限制,即不将未加密的文件存储在本地

如果有人已经做到了这一点,可以帮助我在这里将非常感谢

谢谢 AJ

一种方法可能是

使用Temp Dir,将文件保存在Temp中,从该Temp文件生成NSURL,然后显示并删除该Temp Dir


谢谢。

由于您使用的是
快速查看
,因此您的选择有限。您必须给
快速查看
一个
NSURL
,这意味着它必须位于文件系统(或Internet)上。幸运的是,这应该不是什么大问题。iOS设备使用硬件级加密。当您的文件被加密时,只有您的应用程序具有解密该文件的密钥。因此,您的文件仍将被加密,但它也将由您的应用程序读取,并且仅由您的应用程序读取

以下是您要做的:

  • 将文件解密为一个
    NSData
    对象,这是您已经完成的

  • 将文件写入无法上传到iCloud或iTunes备份的位置。
    tmp
    目录可能是最佳选择。代码如下所示:

    NSData * data = // Your decrypted file data.
    NSString * fileName = // Whatever you want to name your file.
    NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
    NSURL * url = [NSURL URLWithString:path];
    NSError * error = nil;
    
    BOOL success = [data writeToURL:url
                            options:NSDataWritingFileProtectionComplete
                              error:&error];
    if (success) {
        // Give the URL to Quick Look.
    }
    else {
        // An error happened. See the 'error' object for the details.
    }
    
    此时,您就有了一个NSURL,可以与
    快速查看
    一起使用。完成解密后,不要忘记删除该文件

  • 关于磁盘加密,有几点需要注意:

  • 它仅在iOS 4.0+上受支持

  • 它可能无法在“旧”设备上工作

  • 用户必须具有活动密码

  • 如果使用
    NSDataWritingFileProtectionComplete
    ,则锁定设备时无法访问该文件。如果在应用程序锁定时需要访问该文件,则应改用
    nsdatawritingfileprotectioncompleteinlessopen
    nsfileprotectioncompleteintilfirstureauthentication
    。这仍然会给你很大的保护,即使设备被盗或越狱。不过,请注意,这些加密选项仅在iOS 5.0上可用+


  • 有关磁盘加密的更多详细信息,请查看在进行一些挖掘之后,我发现
    qlviewcontroller
    正在下面使用
    UIWebView
    ,并调用
    loadRequest:
    加载请求的文件

    实现所需的另一种方法是在
    UIWebView
    上创建一个私有类别, 并使用方法swizzling覆盖
    loadRequest:
    方法,并调用
    loadData:MIMEType:textcencodingname:baseURL:
    方法

    请注意

    1) 在内存不足的情况下(即大文件),黑屏显示 如果与您有关,则会出现“加载文档时出错”。(修订) 未经检查的QLPreviewController知道如何处理这些场景 很好,请出示文件)

    2) 我不确定苹果会不会去 批准这种黑客行为,尽管没有使用私有API 在这里

    代码:


    实际上,将文件写入tmp目录仍然是不安全的。另一种选择是将UIWebView与NSURLProtocol结合使用,并允许动态解密此数据。

    是。那将是我最后的选择。谢谢罗布的回复。这些信息确实有帮助。我确实有一个后续问题。我这样做是为了在我的应用程序中为文件提供脱机功能。你认为我通过自己加密和解密文件来增加冗余吗。相反,您是否认为它足够安全,我只需使用磁盘加密并将文件存储在应用程序的“我的文档”文件夹中。还有,存储这些文件的最佳位置是什么。我指的是文档或tmp文件夹。再次感谢。很抱歉,您已经回答了存储它们的最佳位置。我还尝试使用NSDataWritingFileProtectionComplete属性将文件写入模拟器上应用程序的tmp文件夹。我可以转到文件系统中的文件夹并打开文档。我假设在越狱设备上也会有类似的行为,在这里我可以访问设备的文件系统,我可以遍历到temp文件夹并访问文档。这是正确的假设吗。感谢您将要使用的目录,您有一些选择。如果希望iCloud同步文件,请使用/Documents。如果您不希望iCloud同步文件,也不关心文件是否偶尔被清除,请使用/Library/Caches。如果您想保证您的文件不会被iCloud同步,请使用/Library/Private Documents.Now进行加密。要进行磁盘加密,您必须具备我在回答中提到的四个条件。我不知道你的文件有多敏感。如果安全性是一个巨大的问题,或者您必须部署在较旧的设备上,那么请继续并保持冗余。否则,磁盘加密就足够了。通过使用磁盘加密,无法直接从文件系统读取文件。解密它的唯一方法是窃取应用程序的密钥,我不知道是否有人已经这么做了。安全的关键在于窃取数据的努力必须大于数据的价值。
    @implementation UIWebView (QLHack)
    
        - (void)MyloadRequest:(NSURLRequest *)request
        {
            // Check somehow that it's the call of your QLPreviewController           
            // If not, just call the original method.
    
            if (!insideQLPreviewController)
            {
                 // Call original implementation
                 [self MyloadRequest:request];     
            }
            else
            {
                 // Load the real data you want
                 [self loadData:data MIMEType:mimeType textEncodingName:nil baseURL:someURL];
            }
    
        }
    
        + (void)load 
        {
            method_exchangeImplementations(class_getInstanceMethod(self, @selector(loadRequest:)), class_getInstanceMethod(self, @selector(MyloadRequest:)));
        }
    
    @end