简书:http://www.jianshu.com/u/5690b3ad0a6f
Blog:http://blog.zhangpeng.site
GitHub:https://github.com/fullstack-zhangpeng
ShowPDFDemo
一个显示PDF的Demo,可以显示出PDF上的加密印章。
Description
工作中,有时会遇上含加密印章的PDF文档,这时如果直接用UIWebView或者WKWebView打开,那加密的印章便不能显示。本Demo通过pdf.js解决此问题。
Demo
实现步骤
1.本Demo采用这时如果直接用UIWebView或者WKWebView完成,引入WebKit/WebKit.h
#import <WebKit/WebKit.h>
2.Demo中使用的宏
#define kScreenW [UIScreen mainScreen].bounds.size.width
#define kScreenH [UIScreen mainScreen].bounds.size.height
#define DOCUMENTS_DIRECTORY [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
3.搭建UI
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKUserContentController* wkUController = [[WKUserContentController alloc]init];
config.userContentController = wkUController;
// 注入JS对象名称AppModel,当JS通过AppModel来调用时,我们可以在WKScriptMessageHandler代理中接收到
// 此处是为了得到PDF加载完成或失败的反馈
[config.userContentController addScriptMessageHandler:self name:@"AppModel"];
// 改变页面内容宽度,适配屏幕大小
NSString *js = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
WKUserScript *wkUserScript = [[WKUserScript alloc] initWithSource:js
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:YES];
[wkUController addUserScript:wkUserScript];
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH - 64)
configuration:config];
webView.backgroundColor = [UIColor whiteColor];
webView.UIDelegate = self;
webView.navigationDelegate = self;
[self.view addSubview:webView];
4.下载PDF
NSString *urlStr = @"http://oshsanwqi.bkt.clouddn.com/jianLi_zhangpeng.pdf";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"从服务器获取到pdf数据");
//对从服务器获取到的数据data进行相应的处理:
dispatch_async(dispatch_get_main_queue(), ^{
NSString* path = [DOCUMENTS_DIRECTORY stringByAppendingPathComponent:@"contract.pdf"];
NSFileManager* fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:path]) {
[fm removeItemAtPath:path error:nil];
}
BOOL success = [data writeToFile:path atomically:YES];
if (success) {
NSLog(@"保存成功");
NSURL *baseURL = [NSURL fileURLWithPath:[self getHtmlBasePath]];
NSString *path = [self getHtmlPath];
NSString *htmlStr = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:nil];
[self.webView loadHTMLString:htmlStr baseURL:baseURL];
}
});
}];
[sessionDataTask resume];
5.适配 iOS 8
在iOS8上,html及js文件的路径为temp目录下,ios9及以上则在bundle里
- (NSString*)getHtmlBasePath {
NSString *basePath = @"";
if ([[[UIDevice currentDevice]systemVersion]floatValue]<9.0) {
basePath = NSTemporaryDirectory();
}else{
basePath = [[NSBundle mainBundle] bundlePath];
}
return basePath;
}
- (NSString*)getHtmlPath{
//在iOS8上,html及js文件的路径为temp目录下,ios9及以上则在bundle里
NSString* path = @"";
if ([[[UIDevice currentDevice]systemVersion] floatValue] < 9.0) {
path = [self copyHtmlToTemp];
}else{
path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@".html"];
}
return path;
}
//在iOS8上,html及js文件要放到temp目录下才能正常访问,ios9及以上不用
- (NSString*)copyHtmlToTemp {
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@".html"];
NSString* compatibilityJSPath = [[NSBundle mainBundle] pathForResource:@"compatibility" ofType:@".js"];
NSString* customviewJSPath = [[NSBundle mainBundle] pathForResource:@"customview" ofType:@".js"];
NSString* minimalCSSPath = [[NSBundle mainBundle] pathForResource:@"minimal" ofType:@".css"];
NSString* pdfJSPath = [[NSBundle mainBundle] pathForResource:@"pdf" ofType:@".js"];
NSString* pdfWorkerJSPath = [[NSBundle mainBundle] pathForResource:@"pdf.worker" ofType:@".js"];
NSString* tempPath = NSTemporaryDirectory();
NSString* htmlTempPath = [tempPath stringByAppendingPathComponent:@"index.html"];
NSString* compatibilityJSTempPath = [tempPath stringByAppendingPathComponent:@"compatibility.js"];
NSString* customviewJSTempPath = [tempPath stringByAppendingPathComponent:@"customview.js"];
NSString* minimalCSSTempPath = [tempPath stringByAppendingPathComponent:@"minimal.css"];
NSString* pdfJSTempPath = [tempPath stringByAppendingPathComponent:@"pdf.js"];
NSString* pdfWorkerJSTempPath = [tempPath stringByAppendingPathComponent:@"pdf.worker.js"];
NSFileManager* fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:htmlTempPath]) {
[fm copyItemAtPath:htmlPath toPath:htmlTempPath error:nil];
}
if (![fm fileExistsAtPath:compatibilityJSTempPath]) {
[fm copyItemAtPath:compatibilityJSPath toPath:compatibilityJSTempPath error:nil];
}
if (![fm fileExistsAtPath:customviewJSTempPath]) {
[fm copyItemAtPath:customviewJSPath toPath:customviewJSTempPath error:nil];
}
if (![fm fileExistsAtPath:minimalCSSTempPath]) {
[fm copyItemAtPath:minimalCSSPath toPath:minimalCSSTempPath error:nil];
}
if (![fm fileExistsAtPath:pdfJSTempPath]) {
[fm copyItemAtPath:pdfJSPath toPath:pdfJSTempPath error:nil];
}
if (![fm fileExistsAtPath:pdfWorkerJSTempPath]) {
[fm copyItemAtPath:pdfWorkerJSPath toPath:pdfWorkerJSTempPath error:nil];
}
return htmlTempPath;
}
6.读取PDF
在WKWebView的代理中读取PDF
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[self loadPDF];
}
- (void)loadPDF {
NSString* path = [DOCUMENTS_DIRECTORY stringByAppendingPathComponent:@"contract.pdf"];
NSData* data = [NSData dataWithContentsOfFile:path
options:NSDataReadingMappedAlways
error:nil];
NSString *paraStr = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
NSString *js = [NSString stringWithFormat:@"loadMyJS('%@')",paraStr];
//NSLOG(@"%@",method);
[self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"%@", error);
NSLog(@"当前手机系统版本较低,不支持查看,请升级系统或者到PC端查看。");
}
}];
}
7.在WKScriptMessageHandler中监听PDF是否读取成功
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"AppModel"]) { //和customview.js文件交互,js调oc的代码
// 打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull类型
if ([message.body[@"code"] isEqualToString:@"00000"]) {
NSLog(@"%@", message.body[@"msg"]);
}
}
}
8.PDF是否读取成功是在customview.js中通知控制器的
function handlePages(page)
{
//create new canvas
var viewport = page.getViewport(1);
var canvas = document.createElement( "canvas" );
canvas.style.display="block";
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
//render page
page.render({canvasContext: context, viewport: viewport});
//add canvas to body
document.body.appendChild(canvas);
//render new page
pageNum++;
if(pdfDoc!=null && pageNum<=numPages){
pdfDoc.getPage(pageNum).then(handlePages);
// PDF 加载失败
}else{
console.log("pdf load complete");
// PDF 加载完毕,body的内容可以根据具体的业务需求进行修改
window.webkit.messageHandlers.AppModel.postMessage({
code: "00000",
msg: "pdf load complete"
});//和wkWebView交互
}
}
网友评论