호댕의 iOS 개발

WKWebView로 웹과 통신하기 (+ Web Inspector) 본문

Software Engineering/iOS

WKWebView로 웹과 통신하기 (+ Web Inspector)

호르댕댕댕 2024. 1. 4. 21:42

앱 개발을 하다보면 웹뷰로 구현이 되어 있는 부분을 종종 마주하게 된다. 

특히 커머스 앱처럼 콘텐츠의 업데이트가 빠르게 되는 경우 앱의 업데이트 없이도 콘텐츠를 변경할 수 있기 때문에 웹뷰는 유용하게 사용된다.

 

하지만 이전에는 특정 URL을 웹뷰로 띄워보는 정도의 간단한 사용만 해보았고, 회사에서도 이미 커스텀되어 있는 웹뷰 관련 객체를 단순히 이용만 하여 웹뷰에 대한 구체적인 사용방법 등은 알지 못했다. 

그러다 이번에 웹뷰 관련 작업을 하면서 웹뷰에 대해 좀 더 공부를 해보게 되었고 이를 정리하게 됐다.

 

일단 웹뷰를 사용하고 있다면 현재는 WKWebView 혹은 SFSafariViewController를 사용할 것이다. 

이전에 사용하던 UIWebView는 iOS 12.0 이후로는 Deprecated 됐기 때문이다.

 

SFSafariViewController 또한 WKWebView를 기반으로 되어 있기 때문에 오늘은 WKWebView에 대해 좀 더 자세히 살펴보고자 한다. 

 

SFSafariViewController와 WKWebView

WKWebView를 자세히 알아보기 전에 WKWebView SFSafariViewController는 언제 사용하면 좋은지 간단하게 정리해보자

 

Discover WKWebView enhancements - WWDC20 - Videos - Apple Developer

 

Discover WKWebView enhancements - WWDC20 - Videos - Apple Developer

WKWebView is the best way to present rich, interactive web content right within your app. Explore new APIs that help you convert apps...

developer.apple.com

 

SFSafariViewController

위 WWDC 영상을 보면 SFSafariViewController의 경우 인앱 웹 브라우저가 필요하나, 깊이있는 커스터마이즈는 필요하지 않을 때 사용한다고 소개하고 있다. 

 

SFSafariViewController를 사용하면 Safari 브라우저에서 사용하는 콘텐츠 차단기 / Reader / 자동 완성 등의 기능을 사용할 수 있다. 

이를 구현하기 위해선 SFSafariViewController의 인스턴스를 생성할 때 로드할 URL만 넣어주고 이를 화면에 띄워주기만 하면 된다. 

SFSafariViewController(url: url)

 

정리해보면, 단순히 웹에 있는 콘텐츠를 Native 앱에서 띄워주고 싶을 때 간편하게 사용 가능한 웹뷰이다. 

 

WKWebView

더 높은 수준의 커스터마이즈가 필요하고 단순히 웹에서 띄워주는 콘텐츠를 보기만 하진 않는다면 이때 WKWebView를 사용하는 것이 적합하다. 

(물론 단순히 콘텐츠를 보여주기 위한 간단한 웹뷰에도 사용이 가능하다)

 

WKWebView의 경우 load 함수를 통해 콘텐츠를 불러오며 파라미터로 URLRequest를 받는다. 

https://developer.apple.com/documentation/webkit/wkwebview/1414954-load

 

load(_:) | Apple Developer Documentation

Loads the web content that the specified URL request object references and navigates to that content.

developer.apple.com

func load(_ request: URLRequest) -> WKNavigation?

 

WKWebView는 어떻게 사용할까?

더 높은 수준의 커스터마이즈가 필요할 때 WKWebView를 사용할 수 있다고 했는데 그럼 어떻게 사용하면 좋을까?

 

웹과 Native 앱 간 통신

만약 Native App의 특정 토큰 값을 전달받아서 처리하고 싶은 경우를 생각해보자. 

그럼 아래 그림과 같은 플로우가 필요할 것이다. 

 

 

// 웹뷰를 구성하는 코드
let userController: WKUserContentController = WKUserContentController()
userController.add(self, name: "getToken") // 웹에서 getToken을 통해 Message를 전달함으로 이를 등록

let preferences = WKWebpagePreferences()
preferences.preferredContentMode = .mobile // 웹뷰의 컨텐츠를 어떤 식으로 보여줄 것인지

let configuration = WKWebViewConfiguration()
configuration.userContentController = userController
configuration.defaultWebpagePreferences = preferences

let webView = WKWebView(frame: .zero, configuration: configuration)

 

이런 통신을 위해선 일단 WKUserContentController의 add 메서드를 통해 MessageHandler를 등록해줘야 한다. 

wkWebView.configuration.userContentController

WKUserContentController는 요렇게 접근이 가능하다. 

 

이는 NotificationCenter에 Observer를 추가하는 것과 거의 유사한 것 같았다. 

 

이렇게 등록을 해놨다면 웹에서 MessageHandler를 통해 getToken을 호출할 것이다. 

// 웹 코드입니다.
(window as any).webkit.messageHandlers.getToken.postMessage(null);

 

이렇게 메세지를 요청하면 이제 WKWebView의 WKScriptMessageHandler를 통해 이를 받고 처리할 수 있다. 

 

extension WebViewController: WKScriptMessageHandler {
    func userContentController(
        _ userContentController: WKUserContentController,
        didReceive message: WKScriptMessage
    ) {
        if message.name == "getToken" {
            let token = "123123"
            wkWebView.evaluateJavaScript(
                "javascript:tokenCallback('getToken', '','\(123123)');" // 웹의 tokenCallBack 함수 호출
            )
        }
    }
}

메세지가 오면 WKScriptMessageHandler의 userContentController(_:didRecieve:) 함수가 호출되고 여기서 정의해놓은 메세지 이름대로 도착을 했다면 evaluateJavaScript를 통해 웹의 함수를 호출하여 값을 전달해줄 수 있다. 

 

호출하는 JavaScript 코드는 String으로 선언하여 사용이 가능하고 해당 호출이 끝났을 때의 Action도 CompletionHandler를 통해 정의해줄 수 있다. 

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

 

이외에도 WKUIDelegate / WKNavigationDelegate를 통해 웹에서 window.close() 등의 함수를 호출했을 때의 제어를 해줄 수 있다. 

 

+ Web Inspector 사용하기

이렇게 웹뷰를 사용할 때에는 디버깅을 하기 위해 사파리를 활용하면 된다.

 

1. 맥의 Safari에서 개발자용 메뉴 활성화하기 

일단 맥에서 사파리를 열고 cmd + , 단축키를 통해 사파리 설정을 연다 > 고급 > 메뉴 막대에서 개발자용 메뉴 보기 체크

 

2. 테스트할 아이폰에서 Safari Web Inspector 활성화하기

아이폰 설정 > Safari > 고급 > 웹 속성 활성화

3. 테스트 폰에서 디버깅할 웹뷰 열기

4. 맥 Safari에서 디버깅할 페이지 선택하기

 

여기를 누르면 콘솔이나 어떤 요소로 구성이 되어있는지 등을 확인할 수 있다. 

 


이번 글에선 웹과 Native 앱이 어떻게 통신을 할 수 있고, 어떻게 디버깅하면 좋을지에 대해 살펴봤다. 

물론 이전에 비해 조금 더 깊이있는 사용방법을 알아봤지만 이것 외에도 WKUIDelegate / WKNavigationDelegate에 대해선 자세히 확인해보지는 못했다. 

 

추후 해당 부분에 대해서도 조금 더 공부해보고 정리를 해봐야겠다.

 

 

Comments