반응형
아래 작성된 방법은 WebView 가 로드될 때 실행되는 것을 기준으로 하였으며 네이티브 앱에서 버튼을 누르거나 특정 동작을 할 때 Javascript 로 값을 전달하고 싶은 경우에는 아래 블로그에 나온 방법(
evaluateJavascript
)을 참고합니다.
evaluateJavascript
참고 블로그
[SWIFT] 웹뷰와 자바스크립트 연동 (Native JavaScript 통신 방법)
1. Swift → Javascript
1) Javascript의 test() 함수 실행할 때
import UIKit
import WebKit
class ViewController: UIViewController() {
var webview: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
let userScript = WKUserScript(source: "test()", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let contentController = WKUserContentController()
contentController.addUserScript(userScript)
webConfiguration.userContentController = contentController
webview = WKWebView(frame: .zero, configuration: webConfiguration)
view = webview
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "https://www.test.com") else { return }
let request = URLRequest(url: url)
webview.load(request)
}
}
2) Swift 내의 .js
파일을 Javascript로 전달할 때
import UIKit
import WebKit
class ViewController: UIViewController() {
var webview: WKWebView!
override func loadView() {
var content = ""
if let path = Bundle.main.path(forResource: "Script", ofType: "js") {
do {
content = try String(contentsOfFile: path)
} catch {
print("error")
}
}
let webConfiguration = WKWebViewConfiguration()
let userScript = WKUserScript(source: content, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let contentController = WKUserContentController()
contentController.addUserScript(userScript)
webConfiguration.userContentController = contentController
webview = WKWebView(frame: .zero, configuration: webConfiguration)
view = webview
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "https://www.test.com") else { return }
let request = URLRequest(url: url)
webview.load(request)
}
}
2. Javascript → Swift
- WKScriptMessageHandler를 채택하고 메세지를 받고 난 이후의 동작을 지정해줍니다.
- WKUserContentController() 에
scriptHandler
라는 이름으로 추가합니다. - JS에서
webkit.messageHandlers.scriptHandler.postMessage
를 이용해 값을 전달합니다.
ViewController.swift
import UIKit
import WebKit
class ViewController: UIViewController() {
var webview: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
let contentController = WKUserContentController()
contentController.add(self, name: "scriptHandler")
webConfiguration.userContentController = contentController
webview = WKWebView(frame: .zero, configuration: webConfiguration)
view = webview
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: Key.url) else { return }
let request = URLRequest(url: url)
webview.load(request)
}
}
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// message.name = "scriptHandler" -> 위에 WKUserContentController()에 설정한 name
// message.body = "searchBar" -> 스크립트 부분에 webkit.messageHandlers.scriptHandler.postMessage(<<이부분>>)
if let body = message.body as? String, body == "searchBar" {
guard let url = URL(string: Key.searchUrl) else { return }
let safariVC = SFSafariViewController(url: url)
present(safariVC, animated: true, completion: nil)
}
if message.body is Array<Any> {
print(message.body)
}
}
}
Script.js
var search = document.querySelector('.btn-search');
search.addEventListener('click', function(){ scriptHandler("searchBar"); });
var menubar = document.querySelector('.slide-navi');
menubar.addEventListener('click', function(){ scriptHandler("menuBar"); });
function scriptHandler(message) {
if (message == "searchBar") {
event.preventDefault();
try {
webkit.messageHandlers.scriptHandler.postMessage(message);
} catch(error) {
alert(error);
}
}
if (message == "menuBar") {
var menu = document.querySelectorAll('.slide-navi > li > a');
var data = [];
for (var i = 0; i < menu.length; i++) {
data.push({'title': menu[i].innerHTML, 'url': menu[i].getAttribute('href')});
}
console.log(data);
try {
webkit.messageHandlers.scriptHandler.postMessage(data);
} catch(error) {
alert(error);
}
}
}
3. WKWebview의 alert 띄우기를 Swift 에서 제어하기
- viewDidLoad() 에서
webview.uiDelegate = self
설정합니다. - WKUIDelegate 를 채택하고 runJavaScriptAlertPanelWithMessage 파라미터를 가진 함수를 정의 합니다.
ViewController.swift
import UIKit
import WebKit
class ViewController: UIViewController() {
var webview: WKWebView!
override func loadView() {
var content = "alert('test')"
let webConfiguration = WKWebViewConfiguration()
let userScript = WKUserScript(source: content, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let contentController = WKUserContentController()
contentController.addUserScript(userScript)
webConfiguration.userContentController = contentController
webview = WKWebView(frame: .zero, configuration: webConfiguration)
view = webview
}
override func viewDidLoad() {
super.viewDidLoad()
webview.uiDelegate = self
guard let url = URL(string: Key.url) else { return }
let request = URLRequest(url: url)
webview.load(request)
}
}
extension ViewController: WKUIDelegate {
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: Key.alertTitle, style: .cancel) { _ in
completionHandler()
}
alertController.addAction(cancelAction)
DispatchQueue.main.async {
self.present(alertController, animated: true, completion: nil)
}
}
}
반응형
'Swift' 카테고리의 다른 글
SQLite 데이터 값이 제대로 들어가지 않을 때 unsafeBitCast 사용하기 (0) | 2019.02.04 |
---|---|
Tabbar 안에 StoryBoard 여러개 관리하는 방법 (0) | 2019.01.23 |
@IBDesignable , @IBInspectable in Custom Object (0) | 2018.11.11 |
sizeToFit 함수와 center 속성을 함께 사용하는 경우에 작성 순서 (0) | 2018.11.11 |
클래스 내에 멤버 변수를 사용할 때 초기화 시점에 따른 메모리 차지 (0) | 2018.11.11 |