在UIWebView中调用Swift方法
在UIWebView中和Swfit代码交互
App中内嵌网页,有时候需要调用Native功能。
为了支持iOS和Android双平台,网页中调用native函数的代码的大概是下面的样子
1 | …… |
因为默认情况下,Android的时把一个java对象设置给javascript context的nativeObj对象。
Swift中使用JavaScriptCore和UIWebView交互
- 使用block实现
实现方法如下:
1 | extension WebViewController: UIWebViewDelegate { |
- 使用JSExport实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36@objc protocol BackProtocol: JSExport{
//使用_生成和javascript的方法一样的签名
func func1(_ str: String) -> Void
}
//不要忘记派生自NSObject类
class JSExportObj: NSObject, BackProtocol{
var funcAction: (()-> Void)?
public func func1(_ link_key: String) {
funcAction?()
}
}
extension WebViewController: UIWebViewDelegate {
//实现UIWebView委托方法
func webViewDidFinishLoad(_ webView: UIWebView) {
//获取JSContext上下文
if let context = self.webView!.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext{
//创建一个临时对象
let obj = JSExportObj()
//设置临时对象的回掉函数,这里使用weak修饰符来避免循环引用造成内存泄漏
obj.funcAction = {
[weak self] in
DispatchQueue.main.async {[weak self] in
……
}
}
context.setObject(jsValueNote, forKeyedSubscript: "nativeObj" as (NSCopying & NSObjectProtocol)!)
}
}
}
内存泄漏
上下文如果持有self对象,那么self对象将无法释放。造成内存泄漏。
这是因为iOS采用引用计数来管理内存,而javascript采用gc来管理内存。
奇怪的是,即使在viewcontroller中把webview设置为nil,仍然无法释放。这估计是因为iOS中的 js VM 继续持有了JSContext,没有及时释放。