UIWebView学习笔记
1. iOS 禁用webView加载网页的长按出现'拷贝'事件
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}
2. iOS webView长按图片,不出现'拷贝'(iOS9默认就是这种效果)
2.1 准备好JS文件
// js文件,如:acepack_details.js
function setImageClickFunction(){
var imgs = document.getElementsByTagName("img");
for (var i=0;i<imgs.length;i++){
imgs[i].style.webkitUserSelect='none';
}
}
2.2 注入JS
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"acepack_details" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil]];
3. webView作为tableView的tableHeaderView
- 在webView的回调方法里,一定要重新设置tableView的tableHeaderView,否则会出现意想不到的问题。
-(void)webViewDidFinishLoad:(UIWebView *)webView {
// 获取到webview的高度
CGFloat height = [[self.webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
self.webView.frame = CGRectMake(self.webView.frame.origin.x, self.webView.frame.origin.y, ScreenWidth, height);
// 一定要重新设置tableView的tableHeaderView,否则会出现意想不到的问题。
[self tableView].tableHeaderView = self.webView;
}
4. 替换webView中的img标签的图片
- 应用场景
- 获取页面中所有图片,图片浏览器
- 非WIFI环境下,加载本地图片
- (NSString *)replaceImageUrl:(NSString *) content {
// 匹配<img>标签
NSString *urlPattern = @"<img[^>]+?src=[\"']?([^>'\"]+)[\"']?";
NSError *error = [NSError new];
NSString *tmp = content;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:urlPattern options:NSRegularExpressionCaseInsensitive error:&error ];
// match 这块内容非常强大
NSUInteger count =[regex numberOfMatchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])];// 匹配到的次数
UIImage *img = [UIImage imageNamed:@"icon_app"];
// 用网络图片替换webView上显示的图片
NSString *tmpStr = @"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png";
// 用本地图片替换webView上显示的图片
tmpStr = [self htmlForJPGImage:img];
if(count > 0) {
NSArray* matches = [regex matchesInString:content options:NSMatchingReportCompletion range:NSMakeRange(0, [content length])];
for (NSTextCheckingResult *match in matches) {
NSInteger count = [match numberOfRanges]; // 匹配项
for(NSInteger index = 0;index < count;index++){
NSRange halfRange = [match rangeAtIndex:index];
if (index == 1) {
// 图片的src属性值
NSString *urlStr = [content substringWithRange:halfRange];
NSLog(@"=%@=",urlStr);
// 保存图片URL
[self.imgSrcArrayM addObject:[content substringWithRange:halfRange]];
// 替换src属性值
tmp = [tmp stringByReplacingOccurrencesOfString:urlStr withString: tmpStr];
}
}
}
}
return tmp;
}
// 编码图片
- (NSString *)htmlForJPGImage:(UIImage *)image {
NSData *imageData = UIImageJPEGRepresentation(image,1.0);
NSString *imageSource = [NSString stringWithFormat:@"data:image/jpg;base64,%@",[imageData base64Encoding]];
return imageSource;
}
5. webView注入JS代码
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"acepack_details" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil]];
6. webView执行JS代码
// 调用JS里的setImageClickFunction()函数
[self.webView stringByEvaluatingJavaScriptFromString:@"setImageClickFunction()"];
7. webView中的图片点击事件
7.1 准备好JS文件
// js文件,如:acepack_details.js
function setImageClickFunction(){
// 取出所有的img标签
var imgs = document.getElementsByTagName("img");
for (var i=0;i<imgs.length;i++){
var src = imgs[i].src;
// 绑定事件
imgs[i].setAttribute("onClick","clickme(src)");
}
}
function clickme(imagesrc){
var url="ClickImage:"+imagesrc;
document.location = url;
}
7.2 注入JS
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"acepack_details" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil]];
7.3 webView请求回调里,执行JS
// 调用JS里的setImageClickFunction()函数
[self.webView stringByEvaluatingJavaScriptFromString:@"setImageClickFunction()"];
7.4 拦截请求,处理图片的单击事件
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)_request navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[_request URL] absoluteString];
NSString *prefix = @"clickimage:";
if ([requestString hasPrefix:prefix]) {
DDLogVerbose(@"%@", requestString);
NSUInteger index = 0;
NSRange range = [requestString rangeOfString:prefix];
if (range.location != NSNotFound) {
NSString *tmpSrc = [requestString substringFromIndex:(range.location + range.length)];
index = [self.imgSrcArrayM indexOfObject:tmpSrc];
}
// 显示图片浏览器
[self networkImageShow:index];
}
return YES;
}
8. 长按webView上的图片,保存
8.1 注入JS
static NSString* const kTouchJavaScriptString=
@"document.ontouchstart=function(event){\
x=event.targetTouches[0].clientX;\
y=event.targetTouches[0].clientY;\
document.location=\"myweb:touch:start:\"+x+\":\"+y;};\
document.ontouchmove=function(event){\
x=event.targetTouches[0].clientX;\
y=event.targetTouches[0].clientY;\
document.location=\"myweb:touch:move:\"+x+\":\"+y;};\
document.ontouchcancel=function(event){\
document.location=\"myweb:touch:cancel\";};\
document.ontouchend=function(event){\
document.location=\"myweb:touch:end\";};";
[self.webView stringByEvaluatingJavaScriptFromString:kTouchJavaScriptString];
8.2 处理点击UIWebView上面的图片
#pragma mark - 处理点击UIWebView上面的图片
- (BOOL)handleWebViewClickImageWithUrl:(NSString *)url{
NSString *requestString = url;
NSArray *components = [requestString componentsSeparatedByString:@":"];
if ([components count] > 1 && [(NSString *)[components objectAtIndex:0]
isEqualToString:@"myweb"]) {
if([(NSString *)[components objectAtIndex:1] isEqualToString:@"touch"]) {
//NSLog(@"you are touching!");
//NSTimeInterval delaytime = Delaytime;
if ([(NSString *)[components objectAtIndex:2] isEqualToString:@"start"]) {
/*
@需延时判断是否响应页面内的js...
*/
_gesState = GESTURE_STATE_START;
NSLog(@"touch start!");
float ptX = [[components objectAtIndex:3]floatValue];
float ptY = [[components objectAtIndex:4]floatValue];
NSLog(@"touch point (%f, %f)", ptX, ptY);
NSString *js = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).tagName", ptX, ptY];
NSString *tagName = [self.webView stringByEvaluatingJavaScriptFromString:js];
_imgURL = nil;
if ([tagName isEqualToString:@"IMG"]) {
_imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", ptX, ptY];
}
if (_imgURL) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleLongTouch) userInfo:nil repeats:NO];
}
}
else if ([(NSString *)[components objectAtIndex:2] isEqualToString:@"move"])
{
//**如果touch动作是滑动,则取消hanleLongTouch动作**//
_gesState = GESTURE_STATE_MOVE;
NSLog(@"you are move");
}
else if ([(NSString *)[components objectAtIndex:2]isEqualToString:@"end"]) {
[_timer invalidate];
_timer = nil;
_gesState = GESTURE_STATE_END;
NSLog(@"touch end");
}
}
return NO;
}
return YES;
}
// 处理长按事件
- (void)handleLongTouch {
NSLog(@"%@", _imgURL);
if (_imgURL && _gesState == GESTURE_STATE_START) {
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"保存图片", nil];
sheet.cancelButtonIndex = sheet.numberOfButtons - 1;
[sheet showInView:[UIApplication sharedApplication].keyWindow];
}
}
// 弹出对话框
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (actionSheet.numberOfButtons - 1 == buttonIndex) return;
NSString *title = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:@"保存图片"]) {
if (_imgURL) {
NSLog(@"imgurl = %@", _imgURL);
}
NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:_imgURL];
NSLog(@"image url=%@", urlToSave);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlToSave]];
UIImage *image = [UIImage imageWithData:data];
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
// 回调
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (error) {
NSLog(@"Error");
} else {
NSLog(@"OK");
}
}
9. webView缓存
9.1 缓存的意义
- webView一般是加载UI比较复杂绚丽、可变、iOS原生控件不容易实现的界面,所以网页的元素一般都很复杂,对处于GPRS环境下的用户而言,流量是个大问题,所以需要缓存!
- 当用户处于断网状态下时,为了避免用户进入空白页面,应该把上次已经加载过的页面呈现给用户!
- webView的请求一般都是GET,POST请求一般是发大量数据给服务器处理(变动性比较大),因此一般只对GET请求进行缓存,而不对POST请求进行缓存。
9.2 为什么可以进行缓存?
- NSURLCache在每个UIWebView的的NSURLRequest请求中都会被调用。
- iOS 5之前:只支持内存缓存;从iOS 5开始:同时支持内存缓存和硬盘缓存。
9.3 怎么做到缓存?
- iOS设备上NSURLCache默认只能进行内存缓存。可以通过子类化NSURLCache来实现自定义的版本从而实现在DISK上缓存内容。
- 需要重写
cachedResponseForRequest
,这个会在请求发送前会被调用,从中我们可以判定是否针对此NSURLRequest返回本地数据。
- 如果本地没有缓存就调用下面这条语句:
return [super cachedResponseForRequest:request];
9.4 NSURLCache常用方法
- 全局缓存对象
NSURLCache *cache = [NSURLCache sharedURLCache];
- 设置内存缓存的最大容量(字节为单位,默认为512KB)
-(void)setMemoryCapacity:(NSUInteger)memoryCapacity;
- 设置硬盘缓存的最大容量(字节为单位,默认为10M)
-(void)setDiskCapacity:(NSUInteger)diskCapacity;
- 取得某个请求的缓存
-(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; ```
5. 清除某个请求的缓存
``` objc
-(void)removeCachedResponseForRequest:(NSURLRequest *)request;
- 清除所有的缓存
-(void)removeAllCachedResponses;
9.5 设置NSURLRequest缓存策略
- NSURLRequestUseProtocolCachePolicy // 默认的缓存策略(取决于协议)
- NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
- NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未实现
- NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
- NSURLRequestReturnCacheDataElseLoad // 有缓存就用缓存,没有缓存就重新请求
- NSURLRequestReturnCacheDataDontLoad // 有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)
- NSURLRequestReloadRevalidatingCacheData // 未实现