There are questions remain, We'll search for the answers together. But one thing we known for sure,the future is not set!

【原创文章】详解IOS Swift中wkwebview与javascript交互的几个问题

APP 百蔬君 6533℃ 已收录 0评论

现在的APP一般启动的使用都会首先打开广告页面,然后再跳转到首页。如果广告页和首页是同一个webview,那么存在一个问题,那就是在首页点击后退,会退到广告页面,这显然是不行的。如果禁用了网页滑动进行返回,那么这个问题就不存在了,但是如果这个广告页打开相关产品之后,在产品页有一个返回健,那么就必须处理这个问题了,不然将从产品页返回到广告页。

我解决这个问题的思路就是重新初始化webview,那么javscript的javascript:history.go(-1);这个功能就会失效。

那么怎么从广告页重新初始化打开相关链接呢?这就是我们今天的主题,swift native与wkwbview中的javascript进行交互。

一,Native中开启wkwebview对javascript支持

为了支持从javascript脚本中可以调用native中的函数,首先需要开启wkwebview对javascript的支持。具体设置如下:

let config = WKWebViewConfiguration()// 创建配置
let per = WKPreferences()
per.javaScriptEnabled = true//允许javascript
per.javaScriptCanOpenWindowsAutomatically = true//允许JS自动调动window.open方法打开一个新的webView;
config.preferences = per//将per设置到配置文件

从上面配置可以看出来,开启javascript功能归WKPreferences()管理。
然后开启js向webview发送信息的方法。具体设置如下:

let userContent = WKUserContentController() // 创建UserContentController(提供JavaScript向webView发送消息的方法)
userContent.add(self as WKScriptMessageHandler, name: "appModel")// 添加消息处理,注意:self指代的对象需要遵守WKScriptMessageHandler协议,结束时需要移除
config.userContentController = userContent// 将UserConttentController设置到配置文件

可以看出对于native与js交互的信息交互归WKUserContentController() 管理。

这里有一个关键点,那就是appModel,这个我称为标识符,它就是与javascript交互的唯一标示,需要与html文件中的标示一致,这样native才能识别相关信息。

二,HTML中调用messageHandlers的方法

html中的相关代码为

var  fileurl="https://www.nkbaishu.com"
window.webkit.messageHandlers.appModel.postMessage(fileurl);

一般而言,我想都是响应click事件,然后激活上面的代码,关于这个语句有几点需要注意。
第一,从元素中直接调用js函数

<div onclick="clickadv()"></div>
<script language="javascript">
 function clickadv(){
     	try {
               window.webkit.messageHandlers.appModel.postMessage(fileurl);
      }
      catch(err){
             window.open(fileurl);
      }
}

比如上面的代码,封装一个clickadv函数,然后赋给div的onclick事件,这个代码是能够实现功能。

第二,直接把click写到js代码中去,我把上面的代码修改了,给div添加了一个id,然后在js代码中获取id,执行click事件。

代码如下:

<div id="clickdiv"></div>
<script language="javascript">
       var listbox = document.getElementById("clickdiv");
	listbox.onclick=function(){
     	try {
               window.webkit.messageHandlers.appModel.postMessage(fileurl);
      }
      catch(err){
             window.open(fileurl);
      }
}

这个代码就十分完美了,在浏览器中只要点击id为“clickdiv”的div,在pc端执行try句块,失败,转而执行catch句块,所以在pc端不会报错;在app端则直接执行try句块,就会发送相关信息给wkwebview。

第三,有一点需要注意,上面的onclick="clickadv()"事件和 id="clickdiv"不能写在body中,写在body中在pc端是可以实现功能,响应click事件,但是在wkwebview中不行,它不是html中的元素,这样将无法激活messageHandlers!开始我写在body中总是无法收到js的消息,折腾了我好久,NND。

三,Native中对javascript脚本发送的信息进行处理调用

做好了上面的工作之后,基本工作可以了,现在我们需要在native中添加处理这些信息的函数

extension ViewController:WKScriptMessageHandler {//用于与JS交互
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if (message.name == "appModel"){
               if let myValue = message.body as? String{
                  print(myValue)
               }
         }
     }
}

注意:ViewController需要和你的class类名一致!
这样就可以与js交流信息了。就我个人而言,我想把它放到类中,不想写扩展,那么可以这样干

class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate, WKUIDelegate {}

把WKScriptMessageHandler添加到上面的class中,然后把userContentController函数丢到这个class类中就好了。

这个message.body的内容就可以是我们的广告页产品的url了,获取到这个url,就可以重新初始化我们的webview,并webview.load(url)了,这样就成功解决从产品页退回到广告页的问题了。

四,HTML中对返回键即javascript:history.go(-1);失效的处理

在这里干脆还多一句嘴,从产品页返回广告页体验是不好,但是如果点击“后退”按钮没有任何反应,这个也是不好的。那么我们可以这样处理。

之所以这里的“后退”失效,是因为他的Refer为空,那么我们可以在产品页加一个referrer的判断,如果为空就返回首页,这样逻辑就比较合理了。

 <script type="text/javascript">
if (document.referrer === '') 
{
var obj = document.getElementById("backlink");
obj.href="/";
}
</script>

backlink是返回按钮的id。

五,HTML广告页面中div被选中时闪烁,并且背景成深灰色问题

在app中的广告页面,当点击广告图片的时候,页面闪烁,整个背景变成了一个半透明的灰色背景,把div的轮廓明显呈现了出来,体验非常不好。这个问题的实质其实是手机上面的特有的touch问题,我们可以禁止页面被touch,这是h5设计的必修课吧。
把下面的代码添加到css中

div {
-webkit-touch-callout: none;
-webkit-user-select: none;
-webkit-tap-highlight-color:transparent;
//-webkit-tap-highlight-color: rgba(0,0,0,0);
 } 

我干的就是禁止选择,禁止touch,tap时背景透明或者白色。这样用手点击页面时,这个深灰色背景就没有了。

再多说几句关于-webkit-tap-highlight-color,第一,这个属性只对ios有效,第二,关于他的4个0:rgba(0,0,0,0),4个0与rgba一一对应,r就是red,g就是green,b就是blue,a是alpha,rgb三个数的范围为0到255,a的值为0到1.对应中文意思就是红,绿,蓝和透明度。如果设置4个0,那么就是黑色的完全透明,就是禁用这个属性了。如果设置为(0,0,0,1),那么tap元素时就会呈现完全黑色底。如果设置为transparent,那么就是任何颜色都完全透明,相当于最后一个0位置的作用。

六,Native中对WKScriptMessageHandler内存泄露的处理

在这里还有很重要的一点,那就是对WKScriptMessageHandler内存泄露的处理,上面添加了handle之后,在我们的ViewController销毁的时候必须清除我们添加的这个handle,否则将内存泄露。

处理方法有2个。
第一个办法,移除handle,我们可以把这个移除代码放到viewWillDisappear重写函数中,

override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        //当前ViewController销毁前将其移除,否则会造成内存泄漏
        self.nwebview?.configuration.userContentController.removeScriptMessageHandler(forName: "appModel") //移除方法
    }

第二个办法,重写内存报警函数

override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

也可以二者结合,这样处理之后就ok了。

七,Native中wkwebview对html网页执行javascript脚本的方法

这个就比较简单了,我们一般等页面加载完成之后再来执行javascript代码。那么我们可以把代码放在 didFinish中处理。

比如,我们让每个页面都禁止或显示系统默认菜单,可以这样干

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
      webview.evaluateJavaScript("document.documentElement.style.webkitTouchCallout='none';", completionHandler: nil)
}

可见就是利用wkwebview的evaluateJavaScript方法来执行js代码,completionHandler参数可以省略。

好了,swift中关于wkwebview与javascript脚本的交互就介绍到这里了。

转载请注明:百蔬君 » 【原创文章】详解IOS Swift中wkwebview与javascript交互的几个问题

喜欢 (4)or分享 (0)
发表我的评论
取消评论

请证明您不是机器人(^v^):

表情