iOS端做文档预览,其实iOS在早期设计的时候,就已经考虑到了预览的功能,所以在iOS系统的早期,就有<QuickLook>框架支持我们实现该功能 ,并且逐渐有了QLPreviewController(并不是一个视图控制器,而是继承NSObject的一个对象)和UIDocumentInteractionController这两个类可以支持我们实现预览,但是这两个类默认是支持分享功能的,不符合我们的app的要求(我们要求文档有权限管理),所以这两个都被pass了,在这个过程中,我们发现webView或者WKWebView也可以实现文件预览,而且文件预览或者展示UI易于操作,所以我们选择了使用 网页浏览器来完成这个功能.
首先说一下webView吧,由于iOS8系统时,iOS已经发布了新版的WKWebView,性能更好,更省内存,所以我们后来用的是WKWebView,这里先简单讲一下webiView,webView用起来很简单:
这个是WebView加载文档的简单应用,本地沙盒目录下的也一样,这个不是重点,我们的重点在WKWebView上,因为iOS8 以下的用户(有苹果官网统计的数据,17年 june月的的时候,iOS 9以下的只占3%了,), 我们这个暂时舍弃了,但是如果大家兼容,也是可以的.
统计数据的链接 : https://developer.apple.com/support/app-store/
下面我们来讲WKWebView ,WKWebView在开发的时候,要分两种类型.iOS8和iOS8以上版本的客户端,需要单独处理
因为WKWebView有一个loadFileUrl的方法,是在iOS9之后才出现的,iOS8这个方法不能用,那能不能直接使用loadRequest方法呢,实践证明,loadRequest在WKWebView不太管用(也可能是我没有摸索到,但是我是多次尝试,都没成功,但是loadFile在iOS9之上,是妥妥的管用的)
所以,为了处理这个问题,我们这样处理的
iOS8 以上的设备:
iOS8以上的设备,可以直接使用loadFileURL的加载和展示,没有什么重要的可以讲的,现在针对的是iOS8 怎么使用WKWebView呢?
通过翻墙查资料,发现了一个牛人的实现原理,先上代码,
//将文件移动到tmp目录 浏览完再移动回去
- (NSURL *)fileURLForBuggyWKWebView8:(NSURL *)fileURL {
NSError *error = nil;
if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) {
return nil;
}
// Create "/temp/www" directory
NSURL *temDirURL = QDTempDirectoryURL;
if (![QDFileManager fileExistsAtPath:[temDirURL path]]) {
[QDFileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error];
}
NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent];
// Now copy given file to the temp directory
[QDFileManager moveItemAtURL:fileURL toURL:dstURL error:&error];
if (error) {
NSLog(@"后调整失败 ");
}
self.tempfilePath = dstURL;
// [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error];
// Files in "/temp/www" load flawlesly :)
return dstURL;
}
之前的牛人是将文件copy(我的代码是移动的,我认为移动应该会比copy更快吧,因为我们的文档有的时候是接近1g的视频文件,)到 沙盒目录下的 "/temp/www" 文件夹,然后再通过LoadRequest来实现,发现WKWebView居然生效了,这样的话 ,我理解的是/temp/www默认应该是存储的WKWebView的网络缓存,然后当加载这个的时候,系统认为是网页请求的时候在优先加载缓存,所有就可以读取了这个文档.然后这个文件就解决了.
ps : 你如果和我一样 是使用的移动文档的话,要记得处理这几个情况
- 用户浏览的时候,移动过去,浏览结束,记得将文档移动回去
2.当用户浏览的时候 项目出现了崩溃 或者被用户强退 或者用户退出后台被系统杀死怎么办?
要将文档移动到沙盒目录的时候,对文件做个标示(比如文件名加个后缀,展示给用户的时候记得过滤一下),然后在应用启动的时候,在appDelegate的启动方法中,去'temp/www'的目录下做一个判断,判断是否存在这种前缀的文档,如果存在,移回原来的目录,就ok了,
此外.如果你们的产品和我们一样,对文档有权限要求,比如,不允许选择,复制,粘贴,等操作,我们可以通过js注入WKWebView的方法让禁止用户交互,代码如下
//禁止长按弹出 UIMenuController 相关
//禁止选择 css 配置相关
NSString*css = @"body{-webkit-user-select:none;-webkit-user-drag:none;}";
//css 选中样式取消
NSMutableString*javascript = [NSMutableString string];
[javascript appendString:@"var style = document.createElement('style');"];
[javascript appendString:@"style.type = 'text/css';"];
[javascript appendFormat:@"var cssContent = document.createTextNode('%@');", css];
[javascript appendString:@"style.appendChild(cssContent);"];
[javascript appendString:@"document.body.appendChild(style);"];
[javascript appendString:@"document.documentElement.style.webkitUserSelect='none';"];//禁止选择
[javascript appendString:@"document.documentElement.style.webkitTouchCallout='none';"];//禁止长按
//javascript 注入
WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:YES];
WKUserContentController*userContentController = [[WKUserContentController alloc] init];
[userContentController addUserScript:noneSelectScript];
WKWebViewConfiguration*configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = userContentController;
//控件加载
[self.webView.configuration.userContentController addUserScript:noneSelectScript];
[self.view addSubview:self.webView];
[self.webView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.bottom.equalTo(self.view);
}];
以上是我的个人见解,有问题请大家指出,谢谢大家.