|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "[iOS] WKWebView을 이용한 iOS 앱과 웹페이지 간의 통신 (1) - WKWebView과 Javasciprt Bridge" |
| 4 | +tags: [iOS, WKWebView, Javascript] |
| 5 | +--- |
| 6 | +{% include JB/setup %} |
| 7 | + |
| 8 | +iOS 앱과 웹페이지 간의 통신은 WKWebView을 이용하여 쉽게 구현할 수 있습니다. 웹페이지는 iOS 앱으로 데이터를 전달하면, iOS 앱은 웹페이지의 JavaScript 함수를 호출할 수 있습니다. |
| 9 | + |
| 10 | +### 웹페이지 -> iOS |
| 11 | + |
| 12 | +웹에서 iOS 앱으로 데이터를 전달하는 방법은 서로 약속한 이름을 가진 `window.webkit.messageHandlers`의 객체를 이용하는 방법이 있습니다. |
| 13 | + |
| 14 | +```js |
| 15 | +window.webkit.messageHandlers.actionHandler.postMessage({ |
| 16 | + "action": "hello", |
| 17 | + "message": "Hello from JavaScript!" |
| 18 | +}); |
| 19 | +``` |
| 20 | + |
| 21 | +<details><summary>Html Source Code</summary> |
| 22 | + |
| 23 | +<script src="https://gist.github.com/minsOne/c45f71e1ae8076a9f85325d7dd0f1e07.js"></script> |
| 24 | + |
| 25 | +</details> |
| 26 | + |
| 27 | +<br/>앱과 웹페이지 간의 약속한 이름인 `actionHandler` 객체를 `postMessage` 함수를 이용하여 iOS 앱으로 데이터를 전달합니다. |
| 28 | + |
| 29 | +iOS 앱은 `WKUserContentController`에 `actionHandler` 메시지 핸들러를 등록하고, `WKScriptMessageHandler` 프로토콜 메소드인 `func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)`를 구현합니다.<br/> |
| 30 | + |
| 31 | +```swift |
| 32 | +class ViewController: UIViewController, WKScriptMessageHandler { |
| 33 | + var webView: WKWebView? |
| 34 | + |
| 35 | + override func viewDidLoad() { |
| 36 | + super.viewDidLoad() |
| 37 | + |
| 38 | + // WKUserContentController 인스턴스 생성 |
| 39 | + let userContentController = WKUserContentController() |
| 40 | + userContentController.add(self, name: "actionHandler") // 메시지 핸들러 등록 |
| 41 | + |
| 42 | + // WKWebView에 WKUserContentController 설정 |
| 43 | + let configuration = WKWebViewConfiguration() |
| 44 | + configuration.userContentController = userContentController |
| 45 | + |
| 46 | + |
| 47 | + // WKWebView 인스턴스 생성 |
| 48 | + let webView = WKWebView(frame: view.bounds, configuration: configuration) |
| 49 | + self.webView = webView |
| 50 | + |
| 51 | + view.addSubview(webView) |
| 52 | + } |
| 53 | + |
| 54 | + // WKScriptMessageHandler 프로토콜 메서드 구현 |
| 55 | + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { |
| 56 | + print(message.name, message.body) |
| 57 | + |
| 58 | + guard |
| 59 | + message.name == "actionHandler", |
| 60 | + let messageBody = message.body as? [String: Any] |
| 61 | + else { return } |
| 62 | + |
| 63 | + print("Received message from JavaScript: \(messageBody)") // 웹으로부터 받은 메시지를 파싱하여 print를 호출하는 코드. |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +웹페이지에서 actionHandler 객체를 이용하여 전달한 데이터를 iOS 앱에서 수신하는 것을 아래 영상에서 확인할 수 있습니다. |
| 69 | + |
| 70 | +<br/><video src="{{ site.production_url }}/image/2024/05/01.mov" width="800px" controls autoplay loop></video><br/><br/><br/> |
| 71 | + |
| 72 | +### iOS -> 웹페이지 |
| 73 | + |
| 74 | +WKWebView에서는 `evaluateJavaScript` 메서드를 이용하여 웹페이지의 JavaScript 함수를 호출할 수 있습니다. |
| 75 | + |
| 76 | +위의 코드에서 action이 `hello` 인 경우, 웹페이지의 `javaScriptFunction` 함수를 호출하도록 코드를 수정해봅시다. |
| 77 | + |
| 78 | +```swift |
| 79 | +// WKScriptMessageHandler 프로토콜 메서드 구현 |
| 80 | +func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { |
| 81 | + guard |
| 82 | + message.name == "actionHandler", |
| 83 | + let messageBody = message.body as? [String: Any], |
| 84 | + let action = messageBody["action"] as? String |
| 85 | + else { return } |
| 86 | + |
| 87 | + print("Received message from JavaScript: \(messageBody)") // 웹으로부터 받은 메시지를 파싱하여 print를 호출하는 코드. |
| 88 | + |
| 89 | + if action == "hello" { |
| 90 | + let jsFunctionCall = "javaScriptFunction();" |
| 91 | + webView?.evaluateJavaScript(jsFunctionCall, completionHandler: nil) // WKWebView에서 JavaScript 코드 실행 |
| 92 | + } else if action == "log" { |
| 93 | + print("Called javascript function") |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +웹페이지에서 `javaScriptFunction` 함수를 호출되고 다시 action에 `log`로 앱으로 호출하는 코드를 아래 영상에서 확인할 수 있습니다. |
| 99 | + |
| 100 | +<br/><video src="{{ site.production_url }}/image/2024/05/02.mov" width="800px" controls autoplay loop></video><br/> |
| 101 | + |
| 102 | +### 정리 |
| 103 | + |
| 104 | +* 앱과 웹은 약속한 이름을 가진 객체와 함수의 이름을 사용하여 통신합니다. |
| 105 | + |
| 106 | +[예제 코드](https://github.com/minsOne/Experiment-Repo/tree/master/20240507) |
| 107 | + |
| 108 | +## 참고자료 |
| 109 | + |
| 110 | +* [아리의 iOS 탐구생활 - [iOS] 웹뷰를 사용할 때 자바스크립트로 양방향 통신하기](https://leeari95.tistory.com/82) |
| 111 | +* [모비두 - Web + Mobile 통신 구현 (Bridge)](https://docs.sauce.im/docs/web-mobile-%ED%86%B5%EC%8B%A0-%EA%B0%80%EC%9D%B4%EB%93%9C-bridge) |
| 112 | +* GitHub |
| 113 | + * [ClintJang/sample-swift-wkwebview-javascript-bridge-and-scheme](https://github.com/ClintJang/sample-swift-wkwebview-javascript-bridge-and-scheme) |
0 commit comments