前提是前端用的Vue写的代码,普通HTML看下一篇。
先看交互效果:
上图是一个Swift加载的web界面,按钮”下一步“触发app端的一个事件,在此事件中app调用前端的alert方法出现弹框。看起来很简单的过程,我跟前端人员硬是调了两天。
先看Swift端的代码:
// 定义协议SwiftJavaScriptDelegate 该协议必须遵守JSExport协议
@objc protocol SwiftJavaScriptDelegate: JSExport {
// js调用App方法,传递图片image参数
func idCardImage(_ frontImage: String,_ backImage: String,_ jsFuncName:String)
}
// 定义一个模型 该模型实现SwiftJavaScriptDelegate协议
@objc class SwiftJavaScriptModel: NSObject, SwiftJavaScriptDelegate {
weak var controller: UIViewController?
weak var jsContext: JSContext?
// js调用App方法,传递图片image参数
func idCardImage(_ frontImage: String,_ backImage: String,_ jsFuncName:String) {
let a = self.jsContext?.objectForKeyedSubscript("payResult")
a?.call(withArguments: [])
}
}
写一个跟JS交互的协议,idCardImage方法将暴露给JS端。
class CCWKWebViewController: CCBaseVC {
var webView: UIWebView!
var jsContext: JSContext!
var completedCallBack:(()->())?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setWebView()
}
func setWebView(){
webView = UIWebView(frame: self.view.bounds)
view.addSubview(webView)
webView.delegate = self
webView.scalesPageToFit = true
// 测试加载本地Html页面
let path = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "dist 14")
let url = URL.init(fileURLWithPath: path!)
let request = URLRequest(url: url)
webView.loadRequest(request)
}
func setContext(){
self.jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let model = SwiftJavaScriptModel()
model.controller = self
model.jsContext = self.jsContext
// 这一步是将SwiftJavaScriptModel模型注入到JS中,在JS就可以通过WebViewJavascriptBridge调用我们暴露的方法了。
self.jsContext.setObject(model, forKeyedSubscript: "WebViewJavascriptBridge" as NSCopying & NSObjectProtocol)
// 注册到网络Html页面 请设置允许Http请求
let curUrl = self.webView.request?.url?.absoluteString //WebView当前访问页面的链接 可动态注册
self.jsContext.evaluateScript(curUrl)
self.jsContext.exceptionHandler = { (context, exception) in
print("exception:", exception as Any)
}
}
}
加载web并配置jsContext,setContext是将JSContext协议方法注入到JS中,后面JS调用App端方法失败,就从这里找原因。
再看Vue端的代码,
mounted(){
window.payResult = this.payResult
},
methods: {
callApp(){
WebViewJavascriptBridge.idCardImage("123","456","payResult");
},
payResult:function() {
alert('你好');
},
}
其中,callApp方法就是按钮下一步触发的方法,WebViewJavascriptBridge.idCardImage("123","456","payResult"),意思是调用App端暴露出来的idCardImage(param,param,param)方法,这里的方法名必须跟app端的一致,不然找不到方法,”123“, ”456“, "payResult" 是传给app端的三个参数,看app端代码:
// js调用App方法,传递图片image参数
func idCardImage(_ frontImage: String,_ backImage: String,_ jsFuncName:String) {
let a = self.jsContext?.objectForKeyedSubscript("\(jsFuncName)")
a?.call(withArguments: [])
}
第三个参数传的是JS那边的方法,该方法是需要app端调用的,所以就是js调用idCardImage()方法传给app参数”123“,”456“,”payResult“字符串接收后在app端解析出js方法,然后通过call(withArguments:)方法调用js的payResult方法弹出alert。