美文网首页codeER.tec网页的东西iOS
iOS极简模式实现Webview网页图片原生预览

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

作者: 小小提莫酱 | 来源:发表于2017-06-13 16:59 被阅读1610次
    温暖.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支持。

    相关文章

      网友评论

      • vision_colion:赞,建议出一份oc的
        vision_colion:@小小提莫酱 哦,对的,看到开头的js去了,看差了,以为是swift:joy:
        小小提莫酱:Swift吧?有机会写一份放GitHub上:smiley:
      • 图样图破森:LZ,咨询一下,如果加载的富文本,该如何去处理呢?
        小小提莫酱:同样的处理、web可以直接加载的,这里都能处理
      • 饥渴的狗崽子:谢谢您的火花:+1:
      • 鸟人扎墨客:感谢,帮了大忙了,sdwebimage 版本有点低,我没有pod install ,直接导入你的代码
        鸟人扎墨客:@不吃鱼的提莫酱 不过,我直接拽的你的代码,需求已经实现了
        鸟人扎墨客:@不吃鱼的提莫酱 4.0.3好像是
        小小提莫酱:你需要SDWebImage版本是多少?我更新一下
      • 2c938cc9a694:很不错,用到了,谢谢
      • 小小提莫酱:v0.0.2版本更新记录

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

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

        【新增】: 提供图片快速预览、手势拖放动画、手势缩放、长按保存、页码选择等最新功能。
      • Tatinic:支持 LZ,想法不错
        小小提莫酱:谢谢支持...:smile:

      本文标题:iOS极简模式实现Webview网页图片原生预览

      本文链接:https://www.haomeiwen.com/subject/glhtqxtx.html