iOS极简模式实现Webview网页图片原生预览

温暖.jpg

前言

最近的几个项目中都需要加载大量的HTML,需要将HTML中的图片在点击时实现原生预览。由于HTML的来源很复杂,包括有后台框架编辑的、第三方提供的、网络抓取的等等。所以只能采取获取HTML之后前端注入JS事件来触发图片点击事件,获取当前页面的所有图片地址。由于实现的原理很简单(两行代码),就不需要使用JavaScriptCore或者其他第三方框架了。

实现效果

HTMLImage.gif
框架整体介绍
  • 该框架为一个通用HTML图片预览框架,旨在提供一种简单快捷的调用方式来native预览网页图片。
  • 同时支持UIWebView与WKWebView。
  • 支持网页图片自定义过滤规则。过滤“头像、广告”之类的小图标。
  • 支持用户自定义核心抓取图片JS、自定义解析规则。
  • 支持配置参数确定是否仅抓取正文(conent)部分图片。
  • SDK支持解析懒加载类型HTML网页(ps:简书更新以后图片加载就是采用的滚动加载模式)

实现原理

  • HTML加载完成之后注入图片点击的JS。
  • 截取JS的点击事件并拆分出所有图片URL和当前点击图片URL。
  • 通过OPTION配置项、配置相关业务参数。
  • 自动解析懒加载类型HTML网页、允许用户自定义懒加载核心属性。
注入图片点击JS需要完成的功能
  • 点击图片能够响应图片的点击事件。
  • 能够获取当前点击图片的URL。
  • 能够获取当前HTML中的所有图片URL。
  • 能够将图片点击事件与网页自带点击事件区分开来。
  • 能够将当前点击图片URL与所有图片URL区分开来。
截取JS的点击事件解析URL
  • 根据标识符判断点击是否执行图片预览功能
  • 根据分隔符拆分当前点击图片URL与所有图片URL。
  • 根据分隔符将所有图片URL合并成图片数组。
  • 具体业务过滤不合法图片URL(eg:包含logo等)。
核心JS代码实现
// 通知 iPhone UIWebView 加载 url 对应的资源
//PhoneGap处理方式
function loadURL(url) {
    var iFrame;
    iFrame = document.createElement("iframe");
    iFrame.setAttribute("src", url);
    iFrame.setAttribute("style", "display:none;");
    iFrame.setAttribute("height", "0px");
    iFrame.setAttribute("width", "0px");
    iFrame.setAttribute("frameborder", "0");
    document.body.appendChild(iFrame);
    // 发起请求后这个 iFrame 就没用了,所以把它从 dom 上移除掉
    iFrame.parentNode.removeChild(iFrame);
    iFrame = null;
}
function zwPreviewImageClickAction(){
    var imgs=document.getElementsByTagName('img');
    var length=imgs.length;
    var allSrc='';
    for(var i=0;i<length;i++){
        var img=imgs[i];
        var imaSrc = '';
        if (img.src.length){
            imaSrc = img.src;
        }else{
            imaSrc = img.getAttribute('data-original-src');
        }
        if (allSrc.length) {
            allSrc = allSrc+'^^^'+imaSrc;
        }else{
            allSrc = imaSrc;
        }
    }
    for(var i=0;i<length;i++){
        var img=imgs[i];
        img.onclick=function(){
//            window.location.href='zw-image-preview:'+allSrc + '###'+this.src;
            loadURL("zw-image-preview:"+allSrc+ '###'+this.src);
        }
    }
}
zwPreviewImageClickAction();
截取JS事件并解析URL
  1. UIWebView在shouldStartLoadWithRequest代理方法中
  2. WKWebView在decidePolicyForNavigationAction代理方法中
if ([request.URL.scheme isEqualToString:@"zw-image-preview"]) {
        NSString *urlPath = [request.URL.absoluteString substringFromIndex:[@"zw-image-preview:" length]];
        NSArray *mixURLArray = [urlPath componentsSeparatedByString:@"###"];
        //图片地址合集
        NSString *allImageURL = [mixURLArray firstObject];
        //当前实际点击图片的地址
        NSString *indexImageURL = [mixURLArray lastObject];
    }

实际项目中遇到的问题

  • HTML来源与展示界面比较复杂,无法统一WebView界面。导致以上代码需要重复调用多次。
  • HTML的格式比较奇葩,鬼知道后台使用的什么转换器。
  • 图片地址命名会出现与分隔符冲突等等。
  • HTML中混杂了小图标(logo、头像等)需要过滤。
封装JS与URL解析

为了避免重复调用,快速实现功能。对上述功能做了简单的封装。

  • UIWebView实现以下两行代码即可
-(void)webViewDidFinishLoad:(UIWebView *)webView{
    self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if ([self.htmlSDK zw_handlePreviewImageRequest:request]) {
        return NO;
    }
    return YES;
}
  • WKWebView实现以下两行代码
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    decisionHandler(WKNavigationActionPolicyAllow);
    [self.htmlSDK zw_handlePreviewImageRequest:navigationAction.request];
}
效果展示
normalPreview.gif
SDK源码解析
  • 加载HTML中的所有图片,包括推广广告图、logo、用户评论头像等等。参照上图:包括了简书的logo、下文的推广链接图。
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
  • 仅加载标准正文content中的所有图片(例如简书中正文文章中所有图片),增加了过滤条件OPTION_StandardCoreJS。
self.htmlSDK = [ZWHTMLSDK zw_loadStandardBridgeJSWebview:webView];
  • 如果以上还是不能满足需求,需要过滤更多的HTML图片信息,则需要自定义option过滤器。eg:仅加载正文HTML图片、过滤掉所有图片URL包含有logo、avaters的图片。
ZWHTMLOption *option = [[ZWHTMLOption alloc] init];
  option.getAllImageCoreJS = OPTION_StandardCoreJS;
  option.filterURL = @[@"logo",@"avaters"];
  self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView withOption:option];
  • 需要加载执行自定义的JS
ZWHTMLOption *option = [[ZWHTMLOption alloc] init];
  option.zwPreviewJS = @"自定义的JS";
  self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView withOption:option];

图片预览显示

  • 按照上面两行代码实现调用即可预览显示。SDK内部已经封装了图示的显示模式。
//预览视图、已集成SDK中
ZWPreviewImageView *showView = [ZWPreviewImageView showImageWithArray:allImageArray withShowIndex:index];
[showView showRootWindow];
  • 如果用户需要自定义(嫌弃>_<)图片浏览器,只需要实现调用以下的block。allImageArray:过滤后所有URL数组。index:当前操作图片的序号。
self.htmlSDK.blockHandlePreview = ^(NSArray *allImageArray, NSInteger index) {
        //自定义图片预览
    };

如何使用SDK

强烈建议您使用pod导入,节省导入依赖的时间。

  • 使用cocoaPods导入(搜索不到请更新本地仓库)
pod 'ZWHTMLImage',       '~> 0.0.2'
  • 直接将文件ZWHTMLImage拖入工程中

依赖ZWPhotoPreview图片显示框架。

#import "ZWHTMLSDK.h"

关于图片保存权限

  • 长按保存功能需要用户info.plist中配置权限
Privacy - Photo Library Additions Usage Description

源码

源码放在GitHub上,欢迎指正,记得star哦!

v0.0.2版本更新记录

  • 【新增】: 支持懒加载类型网页图片的读取功能。

  • 【修改】: 重新构造图片预览功能、更新图片预览框架ZWPhotoPreview最新版本。

  • 【新增】: 提供图片快速预览、手势拖放动画、手势缩放、长按保存、页码选择等最新功能。

v0.0.1版本更新记录

  • 【新增】: 提供简便的HTML图片放大预览功能。
  • 【新增】: 提供简便的HTML图片过滤功能、用户自定义过滤参数。
  • 【新增】: cocoapods支持。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容