#pragma mark - WKWebviewDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
NSString *htmlStr = [Util changeImgSrc:[webView.URL absoluteString]];
// WLog(@"html == %@", htmlStr);
// 读取本地JS文件,把JS加到最后面
NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"DetalJavascript" ofType:@"html"];
NSString *jsHtml = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil];
htmlStr = [htmlStr stringByAppendingString:[NSString stringWithFormat:@"\n%@", jsHtml]];
WLog(@"%@", htmlStr);
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
// [NSKeyedArchiver archiveRootObject:htmlStr toFile:[NSString stringWithFormat:@"%@/index.html", docPath]];
[webView loadHTMLString:htmlStr baseURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@", docPath]]];
// [webView loadHTMLString:htmlStr baseURL:[NSURL fileURLWithPath:@"/"]];
// [webView loadHTMLString:htmlStr baseURL:nil];
decisionHandler(WKNavigationResponsePolicyAllow);
}
#pragma mark - 图片下载完成通知
-(void)imageDownloadSuccess:(NSNotification *)notify{
NSString *imgPath = [NSString stringWithFormat:@"%@",notify.object];
imgPath = [NSString stringWithFormat:@"�file://%@", imgPath];
NSString *imgName = [imgPath lastPathComponent];
if (imgPath) {
[self.bridge callHandler:@"imagesDownloadCompleteHandler" data:@[imgName,imgPath] responseCallback:^(id responseData) {
NSLog(@"调用完JS后的回调:%@",responseData);
}];
}
}
JS文件:
<script language="javascript">
// 以下是固定写法,你自己的JS文件中必须包含如下代码
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
// 注册相关的回调
setupWebViewJavascriptBridge(function(bridge) {
/* Initialize your app here */
//这句代码是注册一个名为'JS Echo'的方法,data是参数,responseCallback是返回,相当于return,供APP端调用
bridge.registerHandler('JS Echo', function(data, responseCallback) {
console.log("JS Echo called with:", data)
responseCallback(data)
})
bridge.registerHandler('imagesDownloadCompleteHandler', function(data,responseCallback) {
var imgName = data[0];
var imgPath = data[1];
//读取未替换的图片
var imgs = document.getElementsByTagName('img');
if (imgs) {
for (var i = 0, j = imgs.length; i < j; i++) {
if (imgs[i].src.indexOf(imgName) >= 0) {
imgs[i].src = imgPath;
}
}
}
})
//调用APP端原生的方法,方法名为'ObjC Echo',responseData是JS端接收到的返回值.
bridge.callHandler('ObjC Echo', 传入的参数 , function responseCallback(responseData) {
console.log("JS received response:", responseData)
})
})
</script>
工具类:
#import "Util.h"
#import <AFNetworking/AFNetworking.h>
#import <CommonCrypto/CommonDigest.h>
#import "UIImageView+AFNetworking.h"
@implementation Util
+ (Util *)shareTool
{
static Util *tool;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
tool = [[Util alloc] init];
});
return tool;
}
- (NSString *)token
{
if (nil == _token)
{
_token = [NSString stringWithFormat:@"%@", [NSKeyedUnarchiver unarchiveObjectWithFile:kUserTokenFile]];
}
return _token;
}
- (void)downloadImageWithUrl:(NSString *)src
{
// 注意:这里并没有写专门下载图片的代码,就直接使用了AFN的扩展,只是为了省麻烦而已。
UIImageView *imgView = [[UIImageView alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:src]];
[imgView setImageWithURLRequest:request
placeholderImage:nil
success:^(NSURLRequest *_Nonnull request, NSHTTPURLResponse *_Nullable response, UIImage *_Nonnull image) {
NSData *data = UIImagePNGRepresentation(image);
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSString *localPath = [docPath stringByAppendingPathComponent:[self md5:src]];
NSString *extension = [src pathExtension];
localPath = [localPath stringByAppendingString:[NSString stringWithFormat:@".%@", extension]];
if (![data writeToFile:localPath atomically:NO])
{
WLog(@"写入本地失败:%@", src);
}
else
{
[kNotificationCenter postNotificationName:kDownloadImageSuccessNotify object:localPath];
}
}
failure:^(NSURLRequest *_Nonnull request, NSHTTPURLResponse *_Nullable response, NSError *_Nonnull error) {
WLog(@"download image url fail: %@", src);
}];
if (self.imageViews == nil)
{
self.imageViews = [[NSMutableArray alloc] init];
}
[self.imageViews addObject:imgView];
}
- (NSString *)md5:(NSString *)sourceContent
{
if (self == nil || [sourceContent length] == 0)
{
return nil;
}
unsigned char digest[CC_MD5_DIGEST_LENGTH], i;
CC_MD5([sourceContent UTF8String], (int)[sourceContent lengthOfBytesUsingEncoding:NSUTF8StringEncoding], digest);
NSMutableString *ms = [NSMutableString string];
for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
{
[ms appendFormat:@"%02x", (int)(digest[i])];
}
return [ms copy];
}
/**
修改HTML里的<IMG src>
@param urlStr 原始链接
@return 修改之后的HTMLString
*/
+ (NSString *)changeImgSrc:(NSString *)urlStr
{
NSString *htmlStr = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:urlStr] encoding:NSUTF8StringEncoding error:nil];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>" options:NSRegularExpressionAllowCommentsAndWhitespace error:nil];
NSArray *result = [regex matchesInString:htmlStr options:NSMatchingReportCompletion range:NSMakeRange(0, htmlStr.length)];
NSMutableDictionary *urlDicts = [[NSMutableDictionary alloc] init];
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
[result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSTextCheckingResult *item = (NSTextCheckingResult *)obj;
NSString *imgHtml = [htmlStr 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];
WLog(@"正确解析出来的SRC为:%@", src);
if (src.length > 0)
{
NSString *extension = [src pathExtension];
NSString *localPath = [docPath stringByAppendingPathComponent:[[self shareTool] md5:src]];
localPath = [localPath stringByAppendingString:[NSString stringWithFormat:@".%@", extension]];
localPath = [NSString stringWithFormat:@"�file://%@", localPath];
// 先将链接取个本地名字,且获取完整路径
[urlDicts setObject:localPath forKey:src];
}
}
}
}];
// 遍历所有的URL,替换成本地的URL,并异步获取图片
for (NSString *src in urlDicts.allKeys)
{
NSString *localPath = [urlDicts objectForKey:src];
htmlStr = [htmlStr stringByReplacingOccurrencesOfString:src withString:localPath];
localPath = [localPath stringByReplacingOccurrencesOfString:@"file://" withString:@""];
// 如果已经缓存过,就不需要重复加载了。
if (![[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
[[self shareTool] downloadImageWithUrl:src];
}
}
return htmlStr;
}
@end