iOS/swift
16. [iOS/Swift] 웹뷰(WKWebView)와 JavaScript 연동(상세) (Native <-> JavaScript)
drizzle0925
2021. 7. 6. 15:29
728x90
앱을 개발하다보면 Web에서 iOS로 iOS에서 Web으로 함수를 호출하고 싶을때가 있습니다.
그러기 위해서 준비된 기능이 Bridge 기능입니다.
Bridge 기능을 사용하는 방법에 대해서 알아보겠습니다.
JavaScript -> iOS 호출
Bridge 호출은 위한 JavaScript 작성
1. JavaScript 코드 작성
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>iOS JavaScript 연동</h1>
<button type="button" onClick="outputMessage('Hello World')">outputMessage</button>
<button type="button" onClick="buttonClick()">buttonClick</button>
<script>
// 현재 호출한 디바이스가 어떤 것인지 체크합니다.
var isMobile = {
Android: function () {
return navigator.userAgent.match(/Android/i) == null ? false : true;
},
iOS: function () {
return navigator.userAgent.match(/iPhone|iPad|iPod/i) == null ? false : true;
},
any: function () {
return (isMobile.Android() || isMobile.iOS());
}
};
// 입력 된 메세지를 전달하는 Bridge 함수
function outputMessage(message) {
if (isMobile.any()) {
if (isMobile.Android()) {
android.bridge.outLink(message);
} else if (isMobile.iOS()) {
webkit.messageHandlers.outputMessage.postMessage(message);
}
}
}
// Button 클릭 Bridge 함수
function buttonClick() {
if (isMobile.any()) {
if (isMobile.Android()) {
android.bridge.back(true);
} else if (isMobile.iOS()) {
webkit.messageHandlers.buttonClick.postMessage(true);
}
}
}
</script>
</body>
</html>
Bridge를 호출하는 부분을 잘봅니다
webkit.messageHandlers.outPutMessage.postMessage(message);
webkit.messageHandlers.buttonClick.postMessage(true);
굵게 표시한 부분이 앱에서 호출되었을때 키가 되는 부분입니다. 이 부분의 명칭이 서로 맞아야 정상적으로 함수를 호출할 수 있습니다.
2. WebView 초기화 및 Bridge 등록
Xcode를 켜서 앱 쪽에서 작업을 하도록 합니다.
iOS 11 이상부터는 스토리보드에서도 WKWebView를 직접 추가할 수 있게 되었지만, Bridge를 설정하기 위해서는 WKWebViewConfiguration을 WKWebView 초기화 시에 넣어주어야 되는데 해당 기능을 스토리보드에서는 지원하지 않아 코드로 웹뷰를 생성합니다.
Bridge 등록하기
let contentController = WKUserContentController()
// Bridge 등록
contentController.add(self, name: "outputMessage")
contentController.add(self, name: "buttonClick")
let configuration = WKWebViewConfiguration()
configuration.userContentController = contentController
WKWebView 초기화
webView = WKWebView(frame: self.view.frame, configuration: configuration)
3. 호출된 Bridge 처리하기
// 호출된 Bridge 처리하기
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
case "outputMessage":
print("outputMessage \(message.body)")
let message = message.body as? String
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "확인", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
case "buttonClick":
print("buttonClick \(message.body)")
let alert = UIAlertController(title: nil, message: " button 버튼 클릭", preferredStyle: .alert)
let action = UIAlertAction(title: "확인", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
default:
break;
}
}
최종완성 코드 (ViewController.swift)
//
// ViewController.swift
// webview
//
// Created by pples on 2021/07/06.
//
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
@IBOutlet var webView: WKWebView!
override func loadView() {
super.loadView()
let contentController = WKUserContentController()
// Bridge 등록
contentController.add(self, name: "outputMessage")
contentController.add(self, name: "buttonClick")
let configuration = WKWebViewConfiguration()
configuration.userContentController = contentController
webView = WKWebView(frame: self.view.frame, configuration: configuration)
webView.uiDelegate = self
webView.navigationDelegate = self
self.view = self.webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.google.com")
let request = URLRequest(url: url!)
webView.load(request)
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } //모달창 닫힐때 앱 종료현상 방지.
//alert 처리
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void){
let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler() }))
self.present(alertController, animated: true, completion: nil) }
//confirm 처리
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in completionHandler(false) }))
alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler(true) }))
self.present(alertController, animated: true, completion: nil) }
// href="_blank" 처리
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil { webView.load(navigationAction.request) }
return nil }
// 호출된 Bridge 처리하기
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
case "outputMessage":
print("outputMessage \(message.body)")
let message = message.body as? String
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "확인", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
case "buttonClick":
print("buttonClick \(message.body)")
let alert = UIAlertController(title: nil, message: " button 버튼 클릭", preferredStyle: .alert)
let action = UIAlertAction(title: "확인", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
default:
break;
}
}
}
결과화면
iOS -> JavaScript 호출
JavaScript 작성
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>iOS JavaScript 연동</h1>
<script>
// 현재 호출한 디바이스가 어떤 것인지 체크합니다.
var isMobile = {
Android: function () {
return navigator.userAgent.match(/Android/i) == null ? false : true;
},
iOS: function () {
return navigator.userAgent.match(/iPhone|iPad|iPod/i) == null ? false : true;
},
any: function () {
return (isMobile.Android() || isMobile.iOS());
}
};
// iOS에서 Web JavaScript를 호출
function messageAlert(message){
if(isMobile.any()){
if(isMobile.iOS()){
alert(message);
}
}
}
</script>
</body>
</html>
Swift
ViewController.swift
//
// ViewController.swift
// webview
//
// Created by pples on 2021/07/06.
//
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
@IBOutlet var webView: WKWebView!
override func loadView() {
super.loadView()
webView = WKWebView(frame: self.view.frame)
webView.uiDelegate = self
webView.navigationDelegate = self
self.view = self.webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.google.kr")
let request = URLRequest(url: url!)
webView.load(request)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("messageAlert('ios->web')")
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } //모달창 닫힐때 앱 종료현상 방지.
//alert 처리
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void){
let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler() }))
self.present(alertController, animated: true, completion: nil) }
//confirm 처리
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in completionHandler(false) }))
alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler(true) }))
self.present(alertController, animated: true, completion: nil) }
// href="_blank" 처리
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil { webView.load(navigationAction.request) }
return nil }
}
결과화면
728x90