美文网首页
H5的iOS外壳(WKWebview)

H5的iOS外壳(WKWebview)

作者: d60e80cd17d5 | 来源:发表于2019-05-31 17:32 被阅读0次

    根据实际使用遇到的问题分成3个部分

    • 加载本地html文件
    • h5和iOS原生交互
    • WKWebview中post请求总是失败的问题

    加载本地html文件

    代码

    guard let directorPath = Bundle.main.path(forResource: "dist", ofType: nil),
                let h5Bundle = Bundle(path: directorPath),
                let h5Path = h5Bundle.path(forResource: "index", ofType: "html"),
                let path = h5Path.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed),
                let url = URL(string: "file://"+path)
            else{
                    alert(title: "严重错误", message: "无法加载h5")
                    return
            }
            let request = URLRequest(url: url)
            webview.load(request)
    

    首先在mainBundle中去找dist文件夹
    得到这个路径后,将dist作为一个Bundle加载
    在dist中去找index.html文件
    预防遇到编码问题用了addingPercentEncoding方法
    因为是本地文件,所以路径前需要加上file://

    文件引入方式

    注意dist文件夹加入的方式,可以整个文件夹放进本项目中,也可以不放在本项目中。引入使用folder references


    引入项目.jpg

    对应target设置


    设置.jpg
    将文件夹作为folder references引入,这样,引入文件只有这一个,不会让其内部的js,css,ttf,html等都被加进来,导致Copy Bundle Resources中引入过多文件

    h5和iOS原生交互

    WKWebview和js通过WKScriptMessageHandler协议交互

    iOS中代码

    let msgHandlerName = "ANY_WORD"
    
    添加

    viewDidLoad中
    让self(ViewController)可以处理msgHandlerName这个名字的消息
    前提:ViewController必须遵守协议WKScriptMessageHandler

    webview.configuration.userContentController.add(self, name: msgHandlerName)
    
    移除

    deinit中

    webview.configuration.userContentController.removeScriptMessageHandler(forName: msgHandlerName)
    
    遵守协议

    可以根据功能分类,定义多个name,分别处理
    这里body规则,需要和h5统一规定,我这里的规则是,将方法名和参数通过逗号隔开,连成一整个字符串

    extension ViewController: WKScriptMessageHandler{
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            guard message.name == msgHandlerName else{
                return
            }
            if let msgBody = message.body as? String{
                switch (msgBody){
                case "takePhoto":
                    takePhoto()
                case let x where x.hasPrefix("callSb"):
                    let arr = x.split(separator: ",")
                    if arr.count>1{
                        let phoneNum = String(arr[1])
                        callSb(phoneNum)
                    }else{
                        toast("没有接收到电话号码")
                    }
                default:
                    alert(title: "调用原生功能失败", message: "iOS中没有定义\(msgBody)方法")
                    break
                }
            }
        }
    }
    

    js 调用iOS原生(js代码)

    if (isAndroid()) {
                window.android.takePhoto();
              } else {
                window.webkit.messageHandlers.ANY_WORD.postMessage("takePhoto");
              }
    

    js就是通过 window.webkit.messageHandlers. msgHandlerName.postMessage("方法名,参数1,参数2")
    的格式调用iOS原生方法
    msgHandlerName为开始在iOS中add的messageHandlerName

    iOS调用js方法(iOS代码)

    let callJS="callJSMethod(1)"
    self.webview.evaluateJavaScript(callJS) 
    

    其中callJSMethod必须为js中已经定义的方法
    定义方式可以是在js源码中,也可以是之前通过evaluateJavaScrip方法定义的js方法
    tip: evaluateJavaScrip方法可以在js方法执行完后调用iOS中的completionHandler


    callJS.jpg

    WKWebview中post请求总是失败的问题

    WKWebview中h5发送post请求失败是当前WKWebview本身不支持的问题
    解决方案:使用了第三方库IMYWebLoader
    查了github上一些库,觉得这个第三方库最合我思路,使用方式也简单

    • 通过pod添加这个库
    pod 'IMYWebLoader'
    
    • 因为这个库是OC实现的,所以需要添加swift和OC桥接
      在桥接的.h文件中引入这个库
    #import <IMYWebLoader/IMYWebLoader.h>
    

    就能在Swift中使用OC代码了

    • 在代码中引入
    webview.configuration.userContentController.imy_installHookAjax()
    

    相关文章

      网友评论

          本文标题:H5的iOS外壳(WKWebview)

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