macOS/iOS WKWebview 下载文件

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代码中,代码直接可用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vim插件自动补齐_给VIM添加REPL

REPL: 读取-求值-输出”循环(英语:Read-Eval-Print Loop,简称REPL)是一个简单的,交互式的编程环境。python作为一个动态语言,REPL在开发过程中起到了很大的作用。可是一直以来用vim写python没有一个很好的&…

Linux ping 详细介绍(win也适用)

多数情况下,能否访问某台电脑或服务器,很自然的使用ping xxx.xxx.xxx.xxx,这是最简单的ping形式,同时看到ping几个包之后就停止(windows)了,linux 会一直ping下去,直到按ctrlc或其他组合键。在windows平台或linux平台&…

巨一自动化工业机器人_工业机器人和自动化设备连接器

来源:大比特商务网 作者:Ann Thryft随着工业物联网(IIOT)不断扩大,给工厂带来了更多电子设备。 这些设备往往暴露在恶劣环境中,包括灰尘、油、液体和极端温度等。 同时,特别是随着协作机器人装配在工厂生产线上&#x…

pvrect r语言 聚类_R语言常用统计方法包+机器学习包(名称、简介)

上期帮大家盘点了一下R中常用的可视化包,这期将简要盘点一下关于统计分析与机器学习的R包,并通过简要介绍包的特点来帮助读者深入理解可视化包。本文作者为“食物链顶端”学习群中的小伙伴,感谢他们的分享。话不多说我们一起来看看吧&#xf…

rap2检测哪些接口在使用_Apifox for Mac(接口调试管理工具)

Apifox 是一款用于接口文档定义、Mock 数据、接口自动化测试等等方面的工具,它的功能高效好用,接口云端同步,实时更新。成熟的团队/项目权限管理,满足各类企业的需求。有需要的朋友赶快来使用吧!Apifox 软件介绍软件开…

layui根据name获取对象_layui表格行合并;解决侧边固定栏合并

实现效果图:适配分页&#xff1b;全选&#xff1b;后台嵌套数据&#xff1a;获取数据后&#xff1b;渲染前操作&#xff1a;,done:function(res){if(res.data){for(var i 0;i<res.data.length;i){var trObj $([lay-id"table"] .layui-table-box).find([data-ind…

abap al设置单元格可编辑 oo_利用WPS做业务系统的超级编辑器

业务系统中的数据很笼统的分可以分为两大类&#xff0c;一个是结构化的&#xff0c;通常用关系型数据库来存储管理&#xff1b;一个是非结构化的&#xff0c;在这类数据中&#xff0c;可能最多、价值密度最大的就是文档。如何更便捷高效的生成或分析文档&#xff0c;就是业务系…

pyecharts怎么绘制散点图_pyecharts可视化和wx的结合

前言最近在研究 pyecharts 的用法&#xff0c;它是 python 的一个可视化工具&#xff0c;然后就想着结合微信来一起玩不多说&#xff0c;直接看效果&#xff1a;条形图.gif环境配置pip install pyechartspip install snapshot_seleniumpip install echarts-countries-pypkgpip …

jekenis父子结构项目打包_全栈之DevOps系列 - 发布 Python 项目 开源/私有 包

DevOps目前并没有权威的定义&#xff0c;普遍认为&#xff0c;DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理&#xff0c;从而更快、更频繁地交付更稳定的软件。作者以 dukepy 系列项目中 dkimageapp 子项目&#xff08;关于图像处理…

如何计算_振动筛处理能力如何计算呢

振动筛在生活中的应用可谓设计到方方面面&#xff0c;大到煤炭开采筛分。小到果汁饮料&#xff0c;这些都离不开振动筛或者震动筛的身影。下面和道联合机械讲解一下如何计算振动筛的处理量&#xff0c;从而选购好的振动筛。振动筛的处理能力计算公式主要如下&#xff1a;1、处理…

springsession分布式登录被覆盖_拉勾 分布式 学习小结

分布式和集群分布式一定是集群&#xff0c;但是集群不一定是分布式&#xff08;可能是复制的&#xff09;集群是多个实例一起工作&#xff0c;分布式将一个系统拆分之后那就是多个实例分布式应用结构&#xff1a;Hash算法适用于在加密&#xff0c;数据存储和查找方面有hash表&a…

python调用dll函数_关于从加载的DLL调用函数的Python基本问题

我是在搜索和尝试各种各样的例子后提出这个问题的&#xff0c;但我似乎无法从加载的DLL调用函数。我想如果有人能给我举一个例子&#xff0c;我就能理解我做错了什么&#xff0c;并取得一些进展。在首先&#xff0c;使用Python 3.3.3可以加载DLL&#xff0c;如下所示&#xff1…

c++ 舞伴配对问题_R绘图:配对样本差异表达作图ggpubr

R绘图往期回顾&#xff1a;R绘图&#xff1a;唱一半的歌&#xff0c;画一半的图 gghalvesR绘图&#xff1a;gggibbous&#xff0c;基于ggplot2的Moon chartsR绘图&#xff1a;ggeconodist&#xff0c;基于ggplot2的另类箱图R语言学习系列之“多变的热图”蚂蚁金服在线可视化引擎…

输入引脚时钟约束_最强干货分享 | 时钟树例外(exclude pin、stop pin、non_stop pin、float pin)...

《最强干货分享时钟树例外(exclude pin、stop pin、non_stop pin、float pin)》研究生毕业之前曾发过这篇推文&#xff0c;现在在原来的基础上进行了修正&#xff0c;又添加了一些内容&#xff0c;几乎是压箱底的&#xff0c;现在拿出来分享一下&#xff0c;如果觉得好的话麻烦…

mysql vb_vb连接mysql

环境&#xff1a;xpvb6mysql-5.6.13-win32mysql-connector-odbc-5.2.5-win32一、首先要下载mysql&#xff0c;其次要下载mysql的odbc驱动。odbc驱动的安装很简单&#xff0c;双击就可执行。mysql不用安装&#xff0c;解压就行。但它的服务的启动比较麻烦&#xff0c;需要用到cm…

mac mysql not found_mac下mysql提示command not found解决

原标题&#xff1a;mac下mysql提示command not found解决问题描述输入mysql -u root -p会出现&#xff1a;zsh: command not found: mysql的提示&#xff0c;此时需要配置环境变量。解决方法一1 .打开终端,输入&#xff1a; cd ~2.输入&#xff1a;sudo vim .bash_profile回车执…

mysql数据库删除列数据_MySQL数据库-数据表、以及列的增删改查

1、创建一个表CREATE(创建)TABLE(表)ENGINE(引擎)ENGINEINNODB(引擎)还有很多类引擎&#xff0c;这里只是简单的提一下INNODB引擎&#xff0c;INNODB引擎支持事务(回滚)&#xff0c;也就是一个事务执行时如果没有完成数据可以回滚CHARSET(字符编码)CREATE TABLE(创建表)--创建表…

mysql 分区 性能更差_用案例分析MySQL 5.7分区表性能下降的根本原因

前言&#xff1a;希望通过本文&#xff0c;使MySQL5.7.18的使用者知晓分区表使用中存在的陷阱&#xff0c;避免在该版本上继续踩坑。同时通过对源码的分享&#xff0c;升级MySQL5.7.18时分区表性能下降的根本原因&#xff0c;向MySQL源码爱好者展示分区表实现中锁的运用。问题描…

java 数组 截取_Java成长孵化园---认识java(day09)

1、APIApplication Programming Interface应用编程接口一切可以调用的东西&#xff0c;都是API2、基础APIObject、String、StringBuilder/StringBuffer、正则表达式、基本类型的包装类、BigDecimal/BigInteger、Date、SimpleDateFormat3、java.lang.Objectlang包&#xff1a;la…

mysql id还原_一次线上DB问题排查(MySQL、事务、MVCC)

背景在司机数据库中&#xff0c;有一张用于存储司机车型的表&#xff0c;暂且称之为表t。该表结构如下所示&#xff1a;MySQL [comp_epower]> show create table t \G; *************************** 1. row *************************** Table: Create Table: CREATE TABLE …