H5的iOS外壳(WKWebview)

根据实际使用遇到的问题分成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 

就能在Swift中使用OC代码了

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

你可能感兴趣的:(H5的iOS外壳(WKWebview))