Swift-WKWebView与JS交互处理H5页面问题

上篇文章完成了简书文章列表数据的瀑布流显示。这篇文章将介绍展示点击单个item文章的的详情显示。本来我也想用之前解析HTML源码的方式原生显示详情,但是发现详情不同于列表数据有规律性,正则去匹配的话相当麻烦,所以作罢,用H5直接展示。原生毕竟是网页的内容,会有很多无用信息,如广告内容、跳转APP、登陆注册信息等。所以要注入js隐藏它们或者禁用js事件等。
因为WKWebView的性能明显优于UIWebView,所以本文我们选用WKWebView。至于怎么初始化WKWebView就不多讲了,因为要注入JS代码有时候要返回一些信息给weView,所以必须使用WKWebViewConfiguration这个东西,初始化后有调用添加和移除方法来完成js与WKWebView的交互。

//初始化
var webView:WKWebView = {
        let configuration = WKWebViewConfiguration.init()
        let preferences = WKPreferences.init()
        preferences.javaScriptCanOpenWindowsAutomatically = true
        preferences.minimumFontSize = 40.0
        configuration.preferences = preferences
        let webView =  WKWebView.init(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT - 49 - (IsFullScreen ? 34 : 0)), configuration:configuration)
        return webView
    }()

注入JS代码相应时间后如若要回调某些信息一定要在js代码中和swift代码中都添加方法,在释放webview的时候需要移除removeScriptMessageHandler。

//比如js中添加方法hidOpenInApp
function hidOpenInApp(){
   var divs = document.getElementsByClassName("meta");
   for (var i = 0;i < divs.length; i ++){
        var div = divs[i].innerHTML;
        //替换字符串“App中阅读”为空字符串,达到隐藏的目的
        document.getElementsByClassName("meta")[i].innerHTML = div.replace(/App中阅读/g, "")
   }
   if (divs.length > 1){
       window.webkit.messageHandlers.hidOpenInApp.postMessage(divs.length);
   }
}
hidOpenInApp();

//swif中viewWillAppear中要相应添加同名方法
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        self.webView.configuration.userContentController.add(self, name: "hidOpenInApp")
}
//swif中viewDidDisappear中要移除同名方法
override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(true)
        self.webView.configuration.userContentController.removeScriptMessageHandler(forName: "hidOpenInApp")
}

至于在哪里注入?首先肯定是要在网页加载完后注入js,但是对于动态网页,就算走了didFinish的方法,也可能没有完全加载出来,没加载出来去操作document自然是没效果的。很多时候就算WebView上滑的时候也就scrollView.contentOffset.y的值发生变化的时候会加载新内容,这个时候就需要监听scrollView.contentOffset.y值的变化,达到某个值的时候再注入JS代码。

    //MARK: - --- webview加载完成
    //网页一次性加载完显示的内容,属性能被检测的情况下直接在didFinish方法中注入
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.topIndicator?.stopAnimating()
        //如果不是列表传来的URL不做js注入
        if self.urlStr != "\(self.webView.url!)" {return}
        //加载项目内 js文件,注入js代码
        let doc = ReadData("InjectionCode", "js")
        print(doc)
        self.webView.evaluateJavaScript(doc, completionHandler: { (htmlStr, error) in
            if error != nil {
                print(error!)
            }else if (htmlStr != nil){
                print(htmlStr!)
            }
        })
    }
// =============================================================
/** 读取项目本地文件数据 */
func ReadData(_ fileName:String, _ type:String) -> String {
    let path = Bundle.main.path(forResource: fileName, ofType: type)
    let url = URL(fileURLWithPath: path!)
    let data = try! Data(contentsOf: url)
    return String.init(data: data, encoding: .utf8)!
}

上面注入hidOpenInApp方法的地方应该是在scrollView的代理方法scrollViewDidScroll中,至于scrollView.contentOffset.y > 1000这个值是我认为设定,不一定是视图刚出现时的偏移量

//MARK: - --- 监听滑动偏移量
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        //print(scrollView.contentOffset.y)
        
        //如果不是列表传来的URL不做js注入
        if self.urlStr != "\(self.webView.url!)" {return}
        
        //隐藏“App中阅读”字样
        if scrollView.contentOffset.y > 1000 {
            if self.appWordsHid == true {return}
            let doc =
            """
                function hidOpenInApp(){
                    var divs = document.getElementsByClassName("meta");
                    for (var i = 0;i < divs.length; i ++){
                        var div = divs[i].innerHTML;
                        //替换字符串“App中阅读”为空字符串,达到隐藏的目的
                        document.getElementsByClassName("meta")[i].innerHTML = div.replace(/App中阅读/g, "")
                    }
                    if (divs.length > 1){
                        window.webkit.messageHandlers.hidOpenInApp.postMessage(divs.length);
                    }
                }
                hidOpenInApp();
            """
            self.webView.evaluateJavaScript(doc, completionHandler: { (htmlStr, error) in
                if error != nil {
                    print(error!)
                }else if (htmlStr != nil){
                    print(htmlStr!)
                }
            })
        }
        
    }

大致的注入方法知道了,就是分析HTML源码,注入JS代码,达到想要的效果。

1.隐藏

因为demo没做登陆,故跟账号有关的都会隐藏,还有打开简书APP类似的字样和弄能也会隐藏屏蔽,下面列举了一些。


图1

图2
//隐藏视图
function hidViews(){
    //隐藏顶部信息
    document.getElementsByClassName("header-wrap")[0].style.display = "none";
    //隐藏“打开APP”
    document.getElementsByClassName("app-open")[0].style.display = "none";
    //隐藏打开简书APP按钮
    document.getElementsByClassName("open-app-btn")[0].style.display = "none";
    //隐藏底部
    document.getElementById("footer").style.display = "none";
    //隐藏喜欢按钮
    document.getElementsByClassName("like-btn")[0].style.display = "none";
    //输出正文内容
    let mainBody = document.getElementsByClassName("collapse-free-content")[0].outerHTML
    window.webkit.messageHandlers.hidViews.postMessage(mainBody);
};
hidViews();

2.创建标签

因为上面图1的②框选部分点击会跳转,而分析源码会a就算去掉href的内容也同样达不到屏蔽跳转的效果,我就尝试“曲线救国”,创建div标签覆盖在上面,可以达到屏蔽跳转事件的效果。

//移除头部作者信息的href属性(想禁止a标签的跳转,无果)
//var bObj = document.getElementsByClassName("article-info")[0].getElementsByClassName("info")[0];
//bObj.href = "javascript:void(0);";
//bObj.onclick = "js_method();return false;";
//bObj.removeAttribute("href")

//创建一个定位的覆盖层间 接阻止a标签的跳转
function createView(){
    var div = document.getElementsByClassName("article-info")[0];
    div.style.position = "relative";
    var childDiv = document.createElement("div");
    childDiv.id = "cover-div";
    //childDiv.style.background = "red";
    childDiv.style.position = "absolute";
    childDiv.style.top = "0";
    childDiv.style.left = "0";
    childDiv.style.right = "0";
    childDiv.style.bottom = "0";
    //childDiv.innerHTML=" i am a append div !"
    div.appendChild(childDiv);
    window.webkit.messageHandlers.createView.postMessage("Success");
}
createView();

要更好的达到自己预期的效果,熟悉前端的JS、HTML、CSS都能达到事半功倍的效果。只需要明白在哪个地方注入JS,哪个地方回调,其余就是前端的知识了。
如果想要了解详详细步骤的可以戳下面👇GitHub链接下载demo,里面都有详细的注释,下载下来跑一遍打打断点不明白的一下就懂了。
本文GitHub源码
如果还有什么不懂,可以在下方评论区留言,谢谢阅读。
上篇文章:瀑布流展示/切换简书列表数据

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

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_x阅读 15,968评论 3 119
  • 今天是周二,节后第一天上班,路上那叫一个忙呀。车连着车,车挨着车,一辆接一辆,车水马龙、川流不息、水泄不通...
    寒梅hm阅读 223评论 0 3
  • 莫愁湖畔莫愁女,满眼哀伤泪迷离。可恨心中出征人,今世可曾有归期?
    十三度空间阅读 263评论 0 0