📱 继承 JWebViewController 实现业务
import UIKit class ViewController: JWebViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let userInfo = ["name": "wb", "sex": "male", "phone": "12333434"] let jsonData = try? JSONSerialization.data(withJSONObject: userInfo, options: .prettyPrinted) let jsonText = String.init(data: jsonData!, encoding: String.Encoding.utf8) //添加getUserInfo脚本,返回用户信息 addSyncJSFunc(functionName: "getUserInfo", parmers: [jsonText!]) //添加shareAction脚本,获得分享参数 addAsyncJSFunc(functionName: "shareAction", parmers: ["name", "sex", "phone", "shareBack"]) { [weak self] (dict) in print(dict["name"]!) print(dict["sex"]!) print(dict["phone"]!) //执行shareBack脚本,告诉H5分享结果 self?.actionJsFunc(functionName: dict["shareBack"] as! String, pars: [true as AnyObject], completionHandler: nil) } //开始加载H5 startUrl(URL.init(string: "http://192.168.2.1/js.html")!) } }
讲解 JWebViewController
构造JKWkWebViewHandler
类,存储信息
class JKWkWebViewHandler: NSObject { fileprivate var name:String! fileprivate var parmers:[String]! fileprivate var action:(([String:AnyObject]) -> Void)? }
添加JS,使用JKWkWebViewHandler
存储
public func addAsyncJSFunc(functionName: String, parmers: [String], action: @escaping ([String:AnyObject]) -> Void) { var obj = self.mAsyncScriptArray.filter { (obj) -> Bool in return obj.name == functionName }.first if obj == nil { obj = JKWkWebViewHandler() obj!.name = functionName obj!.parmers = parmers obj!.action = action self.mAsyncScriptArray.append(obj!) } } public func addSyncJSFunc(functionName: String, parmers: [String]) { var obj = self.mSyncScriptArray.filter { (obj) -> Bool in return obj.name == functionName }.first if obj == nil { obj = JKWkWebViewHandler() obj!.name = functionName obj!.parmers = parmers self.mSyncScriptArray.append(obj!) } }
创建JS脚本,使用iOSApp
对象封装,异步回调传回本地的函数window.webkit.messageHandlers.xxx
直接封装在JS函数中。
这样有一个好处,H5调用JS,直接iOSApp.xxx(XXX)
就行了,不需要写window.webkit.messageHandlers.xxx
这些代码。
这对于H5来说,跟平时写的JS脚本没有什么区别,方便了调用。
对于 Native 来说,帮H5做了JS的回调的封装,并通过处理器回调得到自己想要的参数,通过这个封装,两端都只需关注业务层就行了,继承JWebViewController
,可以专心写业务逻辑。
private func createScript() -> String { var result = "iOSApp = {" for item in self.mAsyncScriptArray { let pars = createParmes(dict: item.parmers) let str = "\"\(item.name!)\":function(\(pars)){window.webkit.messageHandlers.\(item.name!).postMessage([\(pars)]);}," result += str } for item in self.mSyncScriptArray { let pars = createParmes(dict: item.parmers) let str = "\"\(item.name!)\":function(){return JSON.stringify(\(pars));}," result += str } result = (result as NSString).substring(to: result.count - 1) result += "}" print("++++++++\(result)") return result }
构造JS,实现传参给H5页面
public func actionJsFunc(functionName: String, pars: [AnyObject], completionHandler: ((Any?, Error?) -> Void)?) { var parString = "" for par in pars { parString += "\(par)," } if parString.count > 0 { parString = (parString as NSString).substring(to: parString.count - 1) } let function = "\(functionName)(\(parString));" wkWebView?.evaluateJavaScript(function, completionHandler: completionHandler) }
注入JS脚本到WKWebViewConfiguration
中
let configuretion = WKWebViewConfiguration() configuretion.preferences = WKPreferences() configuretion.preferences.javaScriptEnabled = true configuretion.userContentController = WKUserContentController() if self.mAsyncScriptArray.count != 0 || self.mSyncScriptArray.count != 0 { // 在载入时就添加JS // 只添加到mainFrame中 let script = WKUserScript(source: createScript(), injectionTime: .atDocumentStart, forMainFrameOnly: true) configuretion.userContentController.addUserScript(script) } //异步需要回调,所以需要添加handler for item in self.mAsyncScriptArray { configuretion.userContentController.add(self, name: item.name) } let wkWebView = WKWebView(frame: self.view.bounds, configuration: configuretion)
合适的时候释放JS的处理程序中,注意不释放的话,控制器不会调用DEINIT,发生内存泄露。
override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) //释放handler for item in self.mAsyncScriptArray { wkWebView?.configuration.userContentController.removeScriptMessageHandler(forName: item.name) wkWebView?.configuration.userContentController.removeAllUserScripts() } }
Github:github.com/jackyshan/J…