javascript에서 swift native를 call하려면 기본적으로 필요한 것이 있다.
viewDidLoad에서 아래 코드를 작성한다.
var webView: WKWebView!
var config: WKWebViewConfiguration!
let contentController = WKUserContentController();
config = WKWebViewConfiguration();
config.userContentController = contentController;
config.preferences.javaScriptEnabled = true;
contentController.add(self, name: "abc"); //abc는 javascript에서 swift native 로 콜하는 함수. 등록을 하지 않으면 감지할 수 없다.
//javascript에서는 webkit.messageHandlers.abc.postMessage(""); 이렇게 해줘야 호출할 수 있다. 중간에 abc가 함수명이며 swift native에서 감지할 수 있다.
webView = WKWebView(frame: self.view.frame, configuration: config);
webView.uiDelegate = self;
webView.navigationDelegate = self;
self.view.addSubview(webView);
위 코드는 UIViewController에 WKWebView를 멤버변수로 두고 동적으로 생성하는 코드이다. 인터페이스 빌더에서 생성하는 방법도 있긴 한데, 인터페이스 빌더를 통해서 WKWebView를 만들면 WKUserContentController를 세팅하는 방법이 없다.(아니면 내가 못찾았던지...)
그리고 WKScriptMessageHandler를 상속받으면 다음의 메소드를 구현할 수 있다.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
이 메소드를 통해 javascript가 swift native로 함수를 call하는 것을 감지할 수 있다.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("message name : " + message.name);
print("message body : " + String(describing: message.body));
}
위의 예제대로 할 경우 message.name에는 "abc"가 온다.
만약 contentController.add(self, name: "abc"); 이 부분이 없으면 감지가 안된다.
message.body에는 webkit.messageHandlers.abc.postMessage(""); 의 postMessage로 넘겨준 파라미터가 오는데, 이 파라미터는 문자열만 넘길 수 있고 파라미터의 숫자는 하나이다.
안드로이드는 내 맘대로 파라미터를 여러개 만들 수 있지만, 그지같은 swift는 단 하나의 파라미터로 고정되어 있다. 그래서 보통은 javascript에서 JSON string 형태로 넘기고 swift에서 다시 JSON object로 변경한다.
추가로 javascript의 console.log를 xcode의 콘솔창에서 보고 싶으면 아래의 코드를 추가한다.
contentController.add(self, name: "native_console_log"); //javascript 감지 함수를 추가한다. viewDidLoad에 추가.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
#if DEBUG || TEST || STAGE
let js = "var console = { log: function(message) { webkit.messageHandlers.native_console_log.postMessage(JSON.stringify(message)) } }"
webView.evaluateJavaScript(js)
#endif
}
위는 WKNavigationDelegate의 메소드 중 하나이다. console.log를 webkit.messageHanlders. native_console_log로 변경하는 코드이다.
swift native에서 javascript에 있는 함수를 콜하려면 다음과 같이 하면 된다.
webView.evaluateJavaScript(script) { (result, error) in
if error != nil {
print("javascript call error : \(script) : \(error?.localizedDescription)");
}
}
error가 nil이 아닐 경우에는 자바스크립트 에러가 발생했다는 것이다. 근데 가끔 정상 호출(처리)됐는데도 에러 나는 경우가 있는데....왜인지 모르겠음. 자바스크립트는 오류나면 그냥 액션을 안하는게 일반적인 현상인데....액션은 제대로 다 됐는데 에러가 오는 경우가 있다.
암턴 webView.evaluateJavaScript(script)의 파라미터는 전부 문자열로 해야하는데 다음과 같이 만들면 된다.
var script = "sc_func(\'\(param1)\',\'\(param2)\')"
sc_func은 javascript에 있는 함수 이름이다. sc_func은 파라미터를 두개(param1, param2) 갖고 있다.
위와 같은 방식으로 전체를 문자열로 만들어야 한다.
그리고 파라미터에 '\' 역슬러쉬 같은 특수 문자가 들어가는 경우 다음의 처리를 해줘야 한다.
func replaceCRNLQuotes(_ ori: String) -> String {
var dest = ori;
dest = dest.replacingOccurrences(of: "\'", with: "\\\'");
dest = dest.replacingOccurrences(of: "\"", with: "\\\"");
dest = dest.replacingOccurrences(of: "\n", with: "\\\n");
dest = dest.replacingOccurrences(of: "\r", with: "\\\r");
dest = dest.replacingOccurrences(of: "\t", with: "\\\t");
dest = dest.replacingOccurrences(of: "\\n", with: "\\\\n");
dest = dest.replacingOccurrences(of: "\\r", with: "\\\\r");
dest = dest.replacingOccurrences(of: "\\t", with: "\\\\t");
return dest;
}
특수문자와 역슬러쉬를 두개 더 붙여서 기존의 문자와 합쳐줘야 한다. 예를 들어 ':' 일 경우 '\\:' 이런식으로.
이러면 호출될 것이다.
댓글 없음:
댓글 쓰기