[iOS] WKWebView (2) - 웹 뷰 사용하기
이전 글에서 WKWebView (1) 사용하기에 대해 작성했었는데요~
이번에는 이어서 WebView에서 JavaScript 코드를 어떻게 호출하고 JavaScript에서 어떻게 네이티브 앱 코드를 호출하는지 어떻게 JavaScript로부터 이벤트를 받아서 실행하는지에 대해 알아보겠습니다.
WKUserContentController - 웹, 네이티브 소통하기
우선 JavaScript 코드를 네이티브에서 호출하거나 네이티브 코드를 JavaScript에서 호출하는 방법을 알기 위해서는 이 객체에 대해서 알아야 합니다. 먼저, Apple 문서의 설명을 보면 이 객체를 다음과 같이 설명하고 있습니다.
JavaScript 코드와 네이티브 웹 뷰 사이의 상호작용을 관리하고 네이티브 웹 뷰에서 콘텐츠를 필터링하기 위한 개체라고 합니다.
즉, Apple 개발자 문서만 봐도 WKUserContentController는 사이에서 중재 역할을 하고 있습니다. 이 객체를 사용하면 할 수 있는 것들을 다음과 같은 것들이 있따고 합니다.
- JavaScript 코드를 웹 페이지에 주입하는 것
- JavaScript 코드를 네이티브 웹 뷰에서 호출하는 것
- 필터를 등록해서 특정 컨텐츠를 띄우는 것을 막는 것
이런 것들이 WKUserContentController를 이용해서 가능하다고 합니다.
그렇다면 WKUserContentController를 사용해서 어떻게 이러한 동작들을 하는지 알아볼게요...!!
먼저, WKUserContentController는 이전 포스팅에서 알아본 WKWebViewConfiguration에 userContentController 프로퍼티에 주입하여 사용할 수 있는 객체입니다.
let configuration = WKWebViewConfiguration()
let contentController = WKUserContentController()
configuration.userContentController = contentController
let webView = WKWebView(frame: .zero, configuration: configuration)
이렇게 사용해서 WKUserContentController를 WKWebView에 할당하는 것이 가능합니다.
그렇다면 이제 JavaScript 코드를 네이티브에서 호출하는 방법과 JavaScript에서 네이티브 코드를 호출하는 방법에 대해 알아볼게요 :)
먼저 JavaScript 코드를 네이티브에서 호출하는 방법입니다. 크게 2가지가 있는 것으로 공부했는데요.
우선, 첫번째는 JavaScript 소스를 처음 WebView를 로드해 올 시점에 할당하는 방법입니다.
let configuration = WKWebViewConfiguration()
let contentController = WKUserContentController()
let userScript = WKUserScript(source: "javascript source", injectionTime: .atDocumentEnd, forMainFrameOnly: false)
contentController.addUserScript(userScript)
configuration.userContentController = contentController
let webView = WKWebView(frame: .zero, configuration: configuration)
let url = URL(string: "https://www.apple.com")
let request = URLRequest(url: url!)
webView.load(request)
이렇게 load하기 이전 시점에 WKContentController에 WKUserScript를 주입하는 방법입니다.
두번째는 evaluateJavaScript(_:completionHandler:) 메소드를 이용하는 방법입니다.
지금 이 메소드를 호출하게 되면, WebView에서 직접적으로 JavaScript 코드를 호출합니다. completionHandler에서는 JavaScript 코드가 성공했으면 결과를 받아서 콜백함수로 실행할 수 있고 실패했으면 Error 값을 받아서 처리할 수 있습니다.
let webView = WKWebView(frame: .zero)
let javaScriptSource = "if (true) { print("Call JavaScript Function") }"
webView.evaluateJavaScript(javaScriptString) { object, error in
print(object)
print(error)
}
다음과 같이 호출하면 JavaScript 코드를 직접적으로 네이티브에서 호출할 수 있습니다.
지금까지는 JavaScript 코드를 네이티브에서 호출하는 방법이였습니다..!!
그렇다면 지금부터는 JavaScript에서 네이티브에 메세지를 전달하는 방법을 알아볼게요 :)
우선, WKScriptMessageHandler라는 프로토콜을 채택해서 사용해야합니다.
그리고 WKUserContentController에 저희가 JavaScript로부터 받아서 사용할 메세지의 이름을 등록해주어야 해당 메세지가 날라왔을 때, 제대로 전달해서 사용할 수 있습니다.
class SomeWebView: WKWebView {
func setupContentController() {
let contentController = self.configuration.userContentController
contentController.add(self, name: "MessageName")
}
}
extension SomeWebView: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// JavaScript에서 메세지를 보낼 때, 보내는 message 이름
let messageName = message.name
// JavaScript에서 메세지를 보낼 때, 같이 보내는 Parameter Any 타입
let body = message.body
}
}
이렇게 네이티브에서 JavaScript의 호출을 받아서 메소드를 처리하는 것이 가능합니다.
지금까지 JavaScript에서 네이티브의 코드를 호출하는 방법, 네이티브에서 JavaScript의 코드를 호출하는 방법을 알아보았습니다 :)
다음은 Alert 액션을 받아서 네이티브에서 처리하는 방법을 알아볼게요!
여기는 훨씬 간단합니다...!! 저도 사용한 적은 없지만 공부하는 김에 같이 알아보았어요
WKUIDelegate - Alert 액션 네이티브에서 처리하기
WKUIDelegate를 이용하면 웹에서 표현되는 새로운 창을 열 때와 같은 이벤트를 받아서 네이티브 앱에서 띄워주는 동작들이 가능하게 됩니다. 기존에 Alert를 띄워주는 것이 WebView 내에서 웹의 요소로 띄워주는 것이었다면 네이티브 앱에서 이 이벤트를 가로채서 UIAlertViewController 등으로 대체해서 띄워주는 것이 가능하게 됩니다..!!
여기서는 간단하게 두 가지의 메소드를 살펴보겠습니다~~!! (다른 window들을 받아서 표현하는 것도 있어요..!!)
첫번째는 webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:) 입니다.
이 메소드는 JavaScript에서 Alert 메세지를 받았을 때, 호출되는 메소드에요..!!
두번째는 webView(_:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:) 입니다.
이 메소드는 Cancel, OK에 관한 이벤트에 대한 핸들링이 가능하게 됩니다.
마지막 completionHandler에 Bool 값을 넣어서 실행함에 따라 핸들링이 가능하게 됩니다.
class SomeWebView: WKWebView {
func setupWebView() {
self.uiDelegate = self
}
}
extension SomeWebView: WKUIDelegate {
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "CC_COMMON_CONFIRM".localized, style: .default) { _ in
completionHandler()
}
alertController.addAction(confirmAction)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "COMMON_CONFIRM_CANCLE".localized, style: .cancel) { _ in
completionHandler(false)
}
let confirmAction = UIAlertAction(title: "CC_COMMON_CONFIRM".localized, style: .default) { _ in
completionHandler(true)
}
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
}
}
이렇게해서 웹으로부터 window를 띄우는 액션들을 받아서 네이티브에서 처리하는 것이 가능합니다...!!
오늘은 이렇게 WKWebView (2)번째 시리즈에 대해 작성해보았습니다~ :)
도움이 되었으면 좋겠습니다.
혹시 잘못된 점이나 더 알고싶은 점이 있으면 알려주세요...!!