적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

초보 iOS 개발자의 일상/개발 업무

[Swift iOS] WKUserContentController 하이브리드 앱 웹 뷰 연동하기

hongssup_ 2021. 4. 14. 17:12
반응형

WKUserContentController란?

네이티브 앱(iOS)에서 WKWebview를 통해 JavaScript와의 통신을 할 때 도와주는 클래스로, 이게 어떻게 왜 쓰이는지 살펴보기 위해 하이브리드 앱에 대해 먼저 알아보자. 

 

하이브리드 앱이란?

스마트폰 어플리케이션에도 종류가 있다! 웹 앱, 하이브리드 앱, 네이티브 앱 이렇게 크게 세 가지로 나뉜다.

 

웹 앱

: 웹 방식이지만 앱을 사용하는 것 같은 착각이 들게 하는 방식으로, 웹페이지와 같은 Web을 스마트폰 화면 크기로 줄인 것. 

장점 단점
- PC나 스마트폰 등 단말기 기종에 관계없이 사용이 가능
- 상대적으로 쉬운 웹 언어로 개발하기 때문에 비용과 시간적인 면에서 저렴하고 유지보수가 쉽다. 
- 카메라, 음성 검색 등의 스마트폰 기능은 사용할 수 없고 기능상 제약이 많다. 
- 애플 스토어 등록 및 판매가 불가

 

네이티브 앱

: 모바일 기기에 최적화된 언어로 개발된 앱으로, 일반적으로 이야기하는 어플리케이션.

유튜브, 인스타그램, 카카오톡 등이 대표적인 네이티브 앱

(안드로이드 앱은 안드로이드 SDK를 이용해 Java 언어로 만들고, 아이폰 앱은 iOS SDK를 이용해 Swift언어로 만듬.)

장점 단점
- 실행 속도가 빠르고 안정적이며 성능이 높다. 
- 센서 제어를 통해 카메라, 음성인식과 같은 스마트폰의 기능을 활용할 수 있다. 
- 제작이 어려워 개발 기간이 길고 비용이 많이든다.
- 안드로이드 / 아이폰 버전을 따로 만들어야 한다. 

 

하이브리드 앱 

: 위의 두가지 장점을 모두 지닌, 네이티브 앱으로 접근이 가능하지만 실제로는 내부에서 웹뷰를 띄워 실행시키는 형태로 만들어진 앱. 

네이버, 다음, 크롬 등이 대표적인 하이브리드 앱.

장점 단점
- 카메라, 음성인식과 같은 스마트폰의 기능을 활용할 수 있다. 
- 웹(HTML)으로 개발하기 때문에 개발 및 유지보수가 간단하다. (안드로이드/아이폰 상관없고, 배포 후에도 웹에서 수정/보완 가능)
- 상대적으로 네이티브 앱보다 속도가 느리다. 

 

▶︎ 이러한 하이브리드 앱을 개발하는 경우,

웹 뷰(WKWebView)를 실행할 때 네이티브(iOS)와 웹(JS) 간의 통신을 도와주는 것이 바로 WKUserContentController

Apple Developer 사이트를 살펴보면, 

WKUserContentController

: An object for managing interactions between JavaScript code and your web view, and for filtering content in your web view.

class WKUserContentController : NSObject

사용법? 

웹 뷰를 생성하기 전, 웹 뷰 셋업할 때 WKUserContentController()를 생성해주고, 

이를 WKWebViewConfiguration의 프로퍼티인 userContentController에 할당해주어라. 

우선 웹 뷰 띄우기는 WKWebView 사용해서 웹 뷰 띄우기 참고!

 

1. WKUserContentController()로 JavaScript 코드에서 불러올 메세지 핸들러 추가해주기 (웹에서 네이티브 호출할 때)

func add(WKScriptMessageHandler, name: String)

add 함수로 간편하게 불러올 수 있는데, 다음과 같이 사용이 가능하다. 

let contentController = WKUserContentController()
contentController.add(self, name: "doSomething")

2. WKWebViewConfiguration에 userContentController로 할당해주기

let config = WKWebViewConfiguration()
//config.preferences.javaScriptEnabled = true
//config.preferences.javaScriptCanOpenWindowsAutomatically = true
config.userContentController = contentController

 3. WKWebView 생성

mWebWK = WKWebView(frame: .zero, configuration: config)
//mWebWK.uiDelegate = self
//mWebWK.navigationDelegate = self
mWebWK.translatesAutoresizingMaskIntoConstraints = false
        
let url = URL(string: "url")!
let request = URLRequest(url: url)
mWebWK.load(request)
        
view.addSubview(mWebWK)

4. extension으로 WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler 프로토콜 상속해주기

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print("message: \(message.name), body: \(message.body)")
    if (message.name == "doSomething") {
        //js에서 받아온 데이터 (보내주는 데이터가 있다면)
        let body = message.body
    	//js로 값 넘겨줄 때
        mWebWK.evaluateJavaScript("sendInfo", completionHandler: nil)
    }
}

 

일반적으로 네이티브에서 JS함수 호출할 때는 보통 evaluateJavaScript 사용.

func evaluateJavaScript(_ javaScriptString: String, 
      completionHandler: ((Any?, Error?) -> Void)? = nil)

 

 

js -> ios 호출만 할 때 예시

더보기

Javascript

function() {
if (a) {
    var t = u();
    if (t.android)
        window.android.toDoStartRecord();
    else if (t.iphone) {
        var n = {
            action: "toDoStartRecord"
        };
        window.webkit.messageHandlers.LoungeBridge.postMessage(n)
    }
}

Swift iOS

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if (message.name == "LoungeBridge") {
        let body = message.body as? [String:Any] ?? [:]
        print("Message Body = \(body)")
        let action = body["action"] as? String ?? ""
        if (action == "toDoStartRecord") {
            //do something
        }
    }
}

 

js -> ios 호출 및 전달하는 값이 있을 때 예시

더보기

Javascript

function(e) {
if (a) {
    var t = u();
    if (t.android)
        window.android.setJwtToken(e);
    else if (t.iphone) {
        var n = {
            action: "setJwtToken"
        };
        n.param = e,
        window.webkit.messageHandlers.LoungeBridge.postMessage(n)
    }
}

Swift iOS

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if (message.name == "LoungeBridge") {
        let body = message.body as? [String:Any] ?? [:]
        print("Message Body = \(body)")
        let action = body["action"] as? String ?? ""
        if (action == "setJwtToken") {
            let param = body["param"] as? String ? ""
        }
    }
}

혹시나 제 글이 도움이 되셨다면 하트 한번 눌러주시면 감사하겠습니다 🥰

iOS 개발자분들 모두 화이팅입니다👍🏻

728x90
반응형