WKWebview 下载文件需要通过JS注入的方式来下载。js下载的数据是base64编码的,回到给原生后,原生需要反编码后才是原始文件的数据。
具体步骤:

  1. 配置WKWebview的js回调句柄(标识)
  2. 创建WKWebview并添加到视图上
  3. 实现WKScriptMessageHandler的(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message,处理下载的数据
  4. 实现WKNavigationDelegate的 (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler,注入js下载代码

配置WKWebview的js回调句柄(标识)并创建

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKPreferences *preference = config.preferences;
preference.javaScriptEnabled = YES;
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
[wkUController addScriptMessageHandler:self name:@"onBlobData"];
config.userContentController = wkUController;
self.webView = [[WKWebview alloc] initWithFrame:self.bounds configuration:config];

关键代码 [wkUController addScriptMessageHandler:self name:@“onBlobData”]; onBlobData 就是我们定义给js调回来的接口或标识

#实现WKScriptMessageHandler 代理
重点实现函数didReceiveScriptMessage,这里需要捕获我们上一步定义的标识事件“onBlobData”,并处理对应的数据

-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{if ([message.name isEqualToString:@"onBlobData"]) {NSString * content = message.body;content = [content stringByReplacingOccurrencesOfString:@"data:text/xml;base64," withString:@""];// 踢出头部信息[self saveFile:content];}
}

content 的值如下:

data:text/xml;base64,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

其中前面的’data:text/xml;base64,'表示文件的数据:数据内容格式;编码方式。对于不同的文件有不同的内容格式,可根据具体已知要下载的文件类型存取或进一步判别这个头数据来处理。取数据时要去除这个头部信息之后再反编码,直接存文件即可。

存文件

存文件的时候我们可以存到我们指定的位置,一般情况下是弹框让用户来选定存放位置。

- (void)saveFile:(NSString *)content {NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];NSString *filename = [NSString stringWithFormat:@"下载文件_%@.txt",dateString];NSSavePanel *panel = [NSSavePanel savePanel];[panel setAllowsOtherFileTypes:YES];[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"txt", nil]];[panel setNameFieldStringValue:filename];[panel setExtensionHidden:YES];[panel setCanCreateDirectories:YES];[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){if (result == NSFileHandlingPanelOKButton){NSString *filePath = [[panel URL]path];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{NSData *data =[[NSData alloc] initWithBase64EncodedString:content options:0];//base64 反编码// Generate the file path[data writeToFile:filePath atomically:YES];//存到指定文件(直接写入)});}}];
}

js下载代码注入

实现WKNavigationDelegate代理,并在decidePolicyForNavigationAction 函数中捕获要下载的bloburl,后进行下载

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{NSLog(@"decidePolicyForNavigationAction :%@",navigationAction.request);if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {NSString *loadUrl = navigationAction.request.URL.absoluteString;if ([loadUrl containsString:@"blob:"] && [[loadUrl substringWithRange:NSMakeRange(0, 5)] isEqualToString:@"blob:"]) {NSString *jsFormat = [NSString stringWithFormat:@"var xhr = new XMLHttpRequest();"@"xhr.open('GET', '%@', true);"@"xhr.responseType = 'blob';"@"xhr.onload = function(e) {"@"if (this.status == 200) {"@"var blob = this.response;"@"var reader = new FileReader();"@"reader.readAsDataURL(blob);"@"reader.onloadend = function() {"@"window.webkit.messageHandlers.onBlobData.postMessage(reader.result);" //通过onBlobData 调回给oc代码@"}"@"}"@"};"@"xhr.send();",loadUrl];NSString * strJSCode = [NSString stringWithFormat:@"%@", jsFormat];[webView evaluateJavaScript:strJSCode completionHandler:^(id _Nullable data, NSError * _Nullable error) {NSLog(@"blob:%@",strJSCode);}];}decisionHandler(WKNavigationActionPolicyCancel);NSLog(@"WKNavigationActionPolicyCancel");} else {decisionHandler(WKNavigationActionPolicyAllow);NSLog(@"WKNavigationActionPolicyAllow");}
}

重点说明xhr.open(‘GET’, ‘%@’, true); 第二个参数需要替换为捕获到的blob url,有些文章中介绍时使用‘(blob)’,就有人照抄代码,调用了没有任何结果回调,且还不知道是注入的代码不对还是请求不成功,文中通过stringWithFormat将loadurl格式化到js代码中,代码直接可用。),有些文章中介绍时使用‘(blob)’,就有人照抄代码,调用了没有任何结果回调,且还不知道是注入的代码不对还是请求不成功,文中通过stringWithFormat将loadurl格式化到js代码中,代码直接可用。

macOS/iOS WKWebview 下载文件相关推荐

  1. h5 ios Safair下载文件自动添加.html导致文件乱码问题,ios不能使用接口播放视频的问题

    需求:h5 页面 下载pdf,doc,docx,xlsx,xls 文件的功能 在安卓手机和 ios上的uc浏览器是可以正常的 下载或者预览的 但是在ios的Safair 下载时会被自动添加html尾缀 ...

  2. php ios 不能下载文件,iOS大厅不能下载公告

    各位飞智iOS用户们: 最新进展时间:20170119 16:45 本次维护结束 1.影之刃2.疯狂贪吃蛇.弓箭手大作战.崩坏学园2.镇魔曲.怪兽大作战.啪啪游戏厅仅支持64位机型(iphoneSE/ ...

  3. iOS中下载大型文件的原理解析二

    在iOS中下载大型文件,需要使用NSURLConnection 的代理方法: (void)touchesBegan:(NSSet)touches withEvent:(UIEvent *)event ...

  4. ubuntu appimage文件怎么安装_iOS 13描述文件怎么下载?iOS 13描述文件安装注意事项...

    ​北京时间6月4号凌晨1点,苹果将于圣何塞会议中心正式召开WWDC19全球开发者大会.对于此次大会,相信绝大部分用户最期待的还是iOS 13移动系统. 发布会结束之后,苹果也会第一时间给开发者用户推送 ...

  5. 钉H5微应用在IOS下载文件问题

    钉钉H5微应用在IOS下载文件问题 最近做的这个项目是钉钉的H5微应用,这个项目是脱胎于PC端的HR系统项目,里面有离职请假转正等流程,在离职流程发起的时候,需要上传附件,附件是可以上传excel.w ...

  6. 微信小程序-下载文件并打开/下载视频播放视频/下载音频文件-Android和IOS调试终版

    下载文件并预览: 调接口下载文件,接口返回的是.bin类型的临时文件,直接调用uniapp原生接口openDocument可能出现打不开的情况或者可能打开文件乱码异常,所以我们需要获取一下文件类型fi ...

  7. nodeJS IOS手机和平板端在微信中下载文件时,弹出框中文件名乱码解决方案(Content-disposition:attachment; filename)

    今天做项目的时候遇见一个问题.下载文件时在谷歌,Edge和火狐中文件名是正确显示的.但是在IOS端(这里我只是测试了平板和手机,苹果电脑的safari没有测试)微信弹窗中会出现%E4%BA%BF%E6 ...

  8. 如何为ios酷我音乐盒下载导出的音乐文件(使用Java程序设计)

    这个工具已经准备第二版,读者了解编程软件,可以直接使用,请阅读和使用这个场地 http://blog.csdn.net/jzj1993/article/details/44459983 本文所涉及内容 ...

  9. iOS之网络下载文件

    文件下载 文件下载在我们日常开发中经常使用到,比如:图片,音频,视频等 简单的小文件下载 get异步下载 - (void)viewDidLoad {[super viewDidLoad];NSStri ...

最新文章

  1. Datawhale组队学习周报(第012周)
  2. 《Head First Python》笔记 第四章 持久存储
  3. Linux驱动修炼之道-内存映射
  4. java包装模式_在Java8中包装设计模式
  5. [luoguP2801] 教主的魔法(二分 + 分块)
  6. centos7 dotnet command not found
  7. 单片机六位抢答器c语言程序,八路电子抢答器(基于51单片机的8路抢答器设计C语言程序)...
  8. 百面机器学习——svm使用信息熵寻找最优划分
  9. 初中级前端开发工程师如何提升个人能力?
  10. Linux 命令查询工具
  11. c语言while语句求奇数和,C语言 100以内奇数和 while语句
  12. 基于MATLAB的车牌识别系统
  13. 我心中的Android REST Client--9gag
  14. Objective-C——initialize方法调用原理分析
  15. mysql latch和缓存关系_latch:cachebufferschains等待事件导致的latch争用的原理原因与...
  16. 如何用nginx部署静态网站
  17. 没有备份电脑照片怎么恢复?分享3种找回照片方法
  18. Jrebel JetBrains License Server! 免费 Jrebel 激活服务器(自建)
  19. java基础 面试题
  20. Django 数据库常用字段类型

热门文章

  1. Mysql迁移Postgresql
  2. 哈夫曼树的正确打开方式
  3. 模拟电路学习总结(附加Multisim仿真备注)
  4. 云计算帮助中小企业免费ERP软件更加辉煌
  5. 搜索图片、文字出处网站
  6. 总结自适应手机meta
  7. 毕业生解约、二次派遣、改派办理程序
  8. yolov5 超大图片检测套路(附代码)
  9. 记录MySQL获取系统当前年份月份日期
  10. C++课程设计——猜谜语小游戏