本文转自标哥的技术博客
首先,我们要获取HTML内容,并通过正则表达式来匹配出所有的<img src="..."/>
的标签:
NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
NSString *html = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSRegularExpression regex = [NSRegularExpression regularExpressionWithPattern:@"<img\ssrc[^>]/>" options:NSRegularExpressionAllowCommentsAndWhitespace error:nil];
NSArray *result = [regex matchesInString:html options:NSMatchingReportCompletion range:NSMakeRange(0, html.length)];
接下来,我们需要一个字典来存储HTML原始的URL和与之关联的本地URL。由于使用原始URL的md5值作为文件名字,因此本地路径也就唯一确定了。这里就将图片都放到Document下。
NSMutableDictionary *urlDicts = [[NSMutableDictionary alloc] init];
NSString *docPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
然后,我们需要遍历所有匹配到的<img src="..."/>
标签,并提取出Src属性值,也就是我们要的原始URL。将并该URL存储下来,以便下一步替换。
for (NSTextCheckingResult *item in result) {
NSString *imgHtml = [html substringWithRange:[item rangeAtIndex:0]];
NSArray *tmpArray = nil;
if ([imgHtml rangeOfString:@"src=\""].location != NSNotFound) {
tmpArray = [imgHtml componentsSeparatedByString:@"src=\""];
} else if ([imgHtml rangeOfString:@"src="].location != NSNotFound) {
tmpArray = [imgHtml componentsSeparatedByString:@"src="];
}
if (tmpArray.count >= 2) {
NSString *src = tmpArray[1];
NSUInteger loc = [src rangeOfString:@"\""].location;
if (loc != NSNotFound) {
src = [src substringToIndex:loc];
NSLog(@"正确解析出来的SRC为:%@", src);
if (src.length > 0) {
NSString *localPath = [docPath stringByAppendingPathComponent:[self md5:src]];
// 先将链接取个本地名字,且获取完整路径
[urlDicts setObject:localPath forKey:src];
}
}
}
}
下一步,我们需要将HTML中所有的原始src的url值替换成我们app的沙盒中的图片路径,如果该路径中未存在,则需要去下载图片,否则不需要重复下载。如下:
// 遍历所有的URL,替换成本地的URL,并异步获取图片
for (NSString *src in urlDicts.allKeys) {
NSString *localPath = [urlDicts objectForKey:src];
html = [html stringByReplacingOccurrencesOfString:src withString:localPath];
// 如果已经缓存过,就不需要重复加载了。
if (![[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
[self downloadImageWithUrl:src];
}
}
下载图片后,还需要将图片存储到该原始url对应的本地路径,也就是Document下,其文件名为原始url的md5值,其他也就可以得出去唯一路径。这里只贴出存储代码,关于如何下载图片,查看demo。
NSData *data = UIImagePNGRepresentation(image);
NSString *docPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString *localPath = [docPath stringByAppendingPathComponent:[self md5:src]];
if (![data writeToFile:localPath atomically:NO]) {
NSLog(@"写入本地失败:%@", src);
}
难点
这里有几处难点:
如何匹配<img src="..."/>
来查找图片链接
在匹配到以后,如何获取src的值
在得到src的值以后,如何在iOS原生获取图片后让webview加载
这里使用了正则表达式来匹配查找<img src="..."/>
,匹配结果可能有多个,遍历数组就可以处理所有的图片链接:
NSRegularExpression(pattern: "<img\ssrc[^>]*/>", options: .AllowCommentsAndWhitespace
存储图片到沙盒
通过获取到HTML中图片的链接后,我们需要通过ios原生的方式来发起请求,加载图片,在加载完成后,我们需要将图片存储到沙盒中document下:
func saveImageData(data: NSData, name: String) ->String {
let docPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as NSString
let path = docPath.stringByAppendingPathComponent(name)
// 若已经缓存过,就不需要重复操作了
if NSFileManager.defaultManager().fileExistsAtPath(path) {
return path
}
do {
try data.writeToFile(path, options: NSDataWritingOptions.DataWritingAtomic)
} catch {
print("save image data with name: (name) error")
}
return path
}
验证是否成功
首先我们可以看到test.html中只有两个img标签:
1
2
3
4
5
<img src="http://www.jhjcqc.com/ueditor/php/upload/image/20151014/1444783819412910.jpg" />
<img src="http://www.jhjcqc.com/ueditor/php/upload/image/20151014/1444783847836404.jpg" />
在我们替换路径完成后,我们加载webview,然后打印出webview所加载的HTML内容中这两个<img>
标签的src是否变化,结果如下:
1
2
3
4
5
<img src="/Users/huangyibiao/Library/Developer/CoreSimulator/Devices/09692E07-2E79-4070-9537-CFD9F3141B0D/data/Containers/Data/Application/73F6D429-E0FD-4BD4-B0A5-85C1BD179840/Documents/5353c07f4c2ea0471b9f3ee36dedcaac" />
<img src="/Users/huangyibiao/Library/Developer/CoreSimulator/Devices/09692E07-2E79-4070-9537-CFD9F3141B0D/data/Containers/Data/Application/73F6D429-E0FD-4BD4-B0A5-85C1BD179840/Documents/54edea1f2edd444aaba9d0321d786962" />
根据效果图,我们可以看到图片是显示出来了,这就说明替换成功后仍然可以加载出来图片,实验成功。
源代码
想要下载源代码,请移步github下载,内有Swift版的工程和ObjC版的工程:https://github.com/CoderJackyHuang/iOSLoadWebViewImage