UIWebView保存网页中的图片(转载)
现在H5混合原生开发的方式越来越流行,也就要用到UIWebView控件。在开发过程中,我们可能会遇到一个需求,要求我们保存网页上的图片,当用户点击图片的时候,就可以让用户选择是否下载图片。
在系统自带的Safari浏览器已经实现了该功能,但是iOS开发中我们如果调用UIWebView加载图片,会发现无法使用Safari保存图片的功能的。这就需要我们自己去实现。
要保存网页中的图片,关键是要获取手指点击位置的图片的url地址,这就需要从js调用oc的方法。下面介绍两种方法来实现图片保存功能,但是这两种方法都只适用于图片地址用如下形式表示才可以获取:
1
|
 |
如果图片是通过js动态生成的,就无法使用下面的方法获取。
方法1、获取点击位置的图片的src属性
实现原理:
该方法主要是获取手指点击的位置,然后获取该位置的标签的src属性,如果是img标签,那么就可以获取到url。如果是其他标签,就无法获取到url属性。
实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@interface ViewController ()@property (weak, nonatomic) IBOutlet UIWebView *webView; @end @implementation ViewController - (void)viewDidLoad { self.webView.delegate = self; [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@ "http://image.baidu.com/wisebrowse/index?tag1=%E7%BE%8E%E5%A5%B3&tag2=%E5%85%A8%E9%83%A8&tag3=&pn=0&rn=10&from=index&fmpage=index&pos=magic#/home" ]]]; UILongPressGestureRecognizer * longPressed = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)]; longPressed.delegate = self; [self.webView addGestureRecognizer:longPressed]; } - (void)longPressed:(UITapGestureRecognizer*)recognizer{ //只在长按手势开始的时候才去获取图片的url if (recognizer.state != UIGestureRecognizerStateBegan) { return ; } CGPoint touchPoint = [recognizer locationInView:self.webView]; NSString *js = [NSString stringWithFormat:@ "document.elementFromPoint(%f, %f).src" , touchPoint.x, touchPoint.y]; NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:js]; if (urlToSave.length == 0) { return ; } NSLog(@ "获取到图片地址:%@" ,urlToSave); } //可以识别多个手势 -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } |
分析:
上述代码的核心功能实现就是如下两行代码:
1
2
|
NSString *js = [NSString stringWithFormat:@ "document.elementFromPoint(%f, %f).src" , touchPoint.x, touchPoint.y]; NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:js]; |
第一行代码是通过js获取点击位置的标签的src属性,第二行代码是接受向webview注入第一行的js代码后返回的src属性。
如果点击位置是图片,那么久可以通过img.src拿到图片的url地址,如果不是就返回空值。
效果展示:
打开的网页如下所示:
长按不同图片输出结果如下:
可以看到获取到了正确的图片地址
方法二、遍历Dom树获取src属性
该方法的实现比较复杂,但是灵活性更高,不仅仅适用于保存图片。而是适用于任何从js调用oc方法的场景。
1、NSObject类扩展
首先我们来给nsobject加一个类扩展,是为了可以给方法传递任意个参数,因为默认系统的performSelector方法最多只能传递两个参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#import "NSObject+Extension.h" @implementation NSObject (Extension) - (id)performSelector:(SEL)selector withObjects:(NSArray *)objects { // 方法签名(对方法的描述) NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector]; if (signature == nil) { [NSException raise:@ "严重错误" format:@ "(%@)方法找不到" , NSStringFromSelector(selector)]; } /*NSInvocation : 利用一个NSInvocation对象通过调用方法签名来实现对方法的调用(方法调用者、方法名、方法参数、方法返回值) 如果仅仅完成这步,和普通的函数调用没有区别,但是关键在于NSInvocation可以对传递进来的selector进行包装,实现可以传递无限多个参数 普通的方法调用比如:[self performSelector: withObject: withObject:]顶多只能传递两个参数给selector*/ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = self; //调用者是自己 invocation.selector = selector; //调用的方法是selector // 设置参数,可以传递无限个参数 NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的参数个数 paramsCount = MIN(paramsCount, objects.count); //防止函数有参数但是不传递参数时,导致崩溃 for (NSInteger i = 0; i < paramsCount; i++) { id object = objects[i]; if ([object isKindOfClass:[NSNull class]]) continue ; //如果传递的参数为null,就不处理了 [invocation setArgument:&object atIndex:i + 2]; // +2是因为第一个和第二个参数默认是self和_cmd } // 调用方法 [invocation invoke]; // 获取返回值 id returnValue = nil; if (signature.methodReturnLength) { // 有返回值类型,才去获得返回值 [invocation getReturnValue:&returnValue]; } return returnValue; } @end |
2、向webview注入js
在webview的代理方法webViewDidFinishLoad注入如下js代码
上面的方法是遍历Dom树,从中找到img标签,然后给每个img标签加上点击事件,让图片的url变
为"jscallbackoc://saveImage_*\"+this.src;形式,我们先不着急为什么这样做,先记住这里就好了,下面会给大家解释为什么这么做。
3、切割跳转url
在点击图片的时候,上面的注入的js代码就会起作用了,那么点击图片,就会触发绑定在该图片的时间,开始跳转,然后执行如下js代码
1
|
document.location.href=\"jscallbackoc: //saveImage_*\"+this.src;\ |
此时就会生成新的图片跳转url为:jscallbackoc://saveImage_*www.baidu.com
我们在webview的如下代理方法中,可以捕获到该url,然后切割处理
1
|
(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType |
我们捕获到跳转url后,就开始做切割处理,把他转换成oc方法,先看代码
需要注意的一点就是跳转url的格式必须如下所示:
1
|
jscallbackoc: //sendMessage_number2_number3_*100$100$99 |
其中jscallbackoc使我们自定义的协议名字,你可以改成任意的。但是其他的部分格式必须按照上面所示
协议名格式: 协议名://
方法名: 方法签名1:方法签名2:方法签名3(方法签名用冒号连接)
参数: 参数1$参数2$参数3(多个参数用$连接)
协议名和方法名直接连接,方法名和参数用*连接
不建议把上面的冒号和$改成其他符号,比如你改成问号(?),如果原来的src的url里面包括?,那么就会出现错误。
假设被点击的图片的src地址是:www.baidu.com。那么js代码`` document.location.href=\"jscallbackoc://saveImage_\"+this.src;``生成的图片跳转url就是jscallbackoc://saveImage_www.baidu.com
经过上面的方法切割之后,得到了方法名:saveImage和参数:www.baidu.com。
然后把方法名和参数传入最后一行的该方法,就可以执行oc代码了:
1
|
[viewController performSelector:NSSelectorFromString(methodName) withObjects:params]; |
此时只要在OC代码里面实现方法-(void)saveImage:(NSString *)imageURL就可以被执行了。
4、拦截跳转url
我们在webview的代理方法中,可以捕获到点击图片后的跳转url,然后做处理
在如上方法中我们做了判断,如果跳转过来的url包含了前缀"jscallbackoc://,就说明使我们自定义的方法,我们需要做拦截处理,转换为oc方法,但是其他跳转url就不做任务处理。
5、验证结果
我们分别点击网页上的不同图片,输出结果如下:
可以看到oc的方法-(void)saveImage:(NSString *)imageURL被执行了。
6、完整代码
总结:
方法1比较简洁,但是仅仅只能获取图片。
方法二比较繁琐,但是使用范围更广,不光可以保存图片,还可以执行任意的oc代码。
UIWebView保存网页中的图片(转载)的更多相关文章
- Delphi保存网页中的图片
WEBBrowser已经打开了URL V = WEBBrowser.Document.body.createControlRange(); V1 = WEBBrow ...
- (转载)SQL中导入图片
SQL中导入图片 分类: 论坛精贴 2006-05-10 12:07 398人阅读 评论(0) 收藏 举报 sqlimage服务器insertlogingo 1.建立过程CREATE PROCEDUR ...
- asp自动解析网页中的图片地址,并将其保存到本地服务器
程序实现功能:自动将远程页面的文件中的图片下载到本地. 程序代码 <% '将本文保存为 save2local.asp '测试:save2local.asp?url=http://ent.sina ...
- [Android]ListView的Adapter.getView()方法中延迟加载图片的优化
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4139998.html 举个例子吧,以好友列表为例 ListVi ...
- Servlet从本地文件中读取图片,并显示在页面中
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpSer ...
- Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果
版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/1873 ...
- ios中,长按Webview中的图片
我们所要解决的问题如题目所示:ios中,长按Webview中的图片,将图片保存到本地相册. 解决方案:对load的html网页,执行js注入,通过在webview中执行js代码,来响应点击事件,通过j ...
- javamail邮件中插入图片
转载 http://duanmumu.blog.163.com/blog/static/1911133502012715104016481/ // TODO Auto-generated method ...
- CSS中背景图片定位方法
转自:http://www.ruanyifeng.com/blog/2008/05/css_background_image_positioning.html 作者: 阮一峰 日期: 2008年5月 ...
随机推荐
- 哪些HTML5特性值得期待
首先大家可以看一下<HTML5程序设计(第二版)>最后一章关于HTML5未来展望.地址:http://www.ituring.com.cn/article/1690?q=html5%E6% ...
- DDD 主题交流会总结及计划
思维碰撞才能更加进步 2015年5月16日(上周六),我们举行了一次 DDD 主题的交流会,参会者主要是 ENode 群友.以及部分园友,为什么要搞这次交流会?原因很简单,就是希望可以提供对 DDD ...
- 附录D 安装ZooKeeper
D.1 安装ZooKeeper D.1.1 下载ZooKeeper ZooKeeper是Apache基金会的一个开源.分布式应用程序协调服务,是Google的Chubby一个开源的实现.它是 ...
- Understanding delete
简述 我们都知道无法通过delete关键字针对变量和函数进行操作,而对于显示的对象属性声明却可以进行,这个原因需要深究到js的实现层上去,让我们跟随 Understanding delete 来探究一 ...
- typeof的一些兼容性问题
typeof存在一些兼容性的问题,在IE6,7,8中的DOM和BOM元素及其对象上的方法的判定会出现误差,在safari上对NodeList实例 的判定,对ExpReg实例的判断(早期的chrome, ...
- 优化JS加载时间过长的一种思路
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 去年公司在漳州的一个项目中,现场工程人员反映地图部分出图有点 ...
- SQL Server SQL性能优化之--pivot行列转换减少扫描计数优化查询语句
原文出处:http://www.cnblogs.com/wy123/p/5933734.html 先看常用的一种表结构设计方式: 那么可能会遇到一种典型的查询方式,主子表关联,查询子表中的某些(或者全 ...
- 使用AutoMapper进行对象间映射
在开发过程中,难免遇到下面这种情况:两个(或多个)对象所拥有的大多数属性是重复的,我们需要在对象间进行映射(即将一个对象的属性值赋给另一个对象.通常我们可以进行如下操作: A a=new A(); a ...
- CSS padding margin border属性详解
图解CSS padding.margin.border属性W3C组织建议把所有网页上的对像都放在一个盒(box)中,设计师可以通过创建定义来控制这个盒的属性,这些对像包括段落.列表.标题.图片以及层. ...
- C# Winform 拦截关闭按钮触发的事件
用户关闭软件时,软件一般会给“是否确认关闭”的提示. 通常,我们把它写在FormClosing 事件中,如果确定关闭,就关闭:否则把FormClosingEventArgs 的 Cancel 属性设置 ...