금융권에서 애용하는, 우리의 WKWebView

Uno·2024년 3월 19일
2

Tip-Swift

목록 보기
26/26
post-thumbnail

금융권에서 애용하는 WebView

금융권 iOS 앱 개발을 희망한다면, 다음과 같은 내용을 많이 봤을지 모른다.

  • Hybrid App 개발 경험 및 지식 보유자
  • Vue.js / React.js Framework 사용경험
  • WKWebView 개발 경험
  • 보안 솔루션 적용 경험
    ... 등

물론 예외도 있다. 카카오뱅크는 네이티브 100%로 구현된 앱으로 유명하다.

Web으로 개발하는 이유는 다양하다.

  • Web 하나만 만들면, Web이 켜지는 플랫폼에 모두 적용이 된다.
    (One Source Multi Platform)
  • 수정사항이 있을 때, Platform에 종속되지 않고 빠르게 배포가 가능하다.

현실적인 이유는 다음과 같다.

  • 과거에 이미 JSP 혹은 관련 Web Framework로 만들어버렸다. 이것을 리엔지니어링하는 것은 리스크가 너무 크다. 그래서 일단 Web으로 둔다.
  • 회사 내 앱 개발자의 수가 너무나도 적다. 앱 개발자를 두긴 하더라도 실제로 개발하는 경우도 있지만, 소수이고 보통은 외주인력 앱개발자가 앱을 만든다.
  • 만약 네이티브로 만들고 싶더라도, 윗선에 리엔지니어링에 대한 설득이 쉽지 않다.

WebView로 여러 서비스를 운영해보면서 느낀점은,
Hybrid도 구조를 처음부터 잘 잡아서 구성하면 괜찮다는 점이다. 돈을 아끼기 위해서 하이브리드 앱을 도입하거나, 옛날 기술이라서 그냥 도입한다면 사실 그냥 보기 싫은 레거시일 뿐이다.

Hybrid의 좋은 구조에 대해서는 다른 글에서 설명하고자 한다.

어째든, 그래서 Hybrid앱도 잘 다뤄야하고 그 첫걸음이 iOS에 있어서는 WKWebview를 아는 것이다.


개요

WKWebView이 어떤 기능을 제공하는지 알고 있어야, 요구사항의 일정 산정부터 개발가능 여부에 대한 커뮤니케이션이 가능하다. 까먹을 때쯤 목차라도 봐두면서, 나중에 찾아갈 수 있도록 인지해두자.

공식문서 내용 요약

An Object that displays interactive web content, such as for an in-app browser.
상호작용이 가능한 웹 컨텐츠를 보여주기 위한 객체

공식문서에서, WebView를 사용하기 적합한 경우를 다음과 같이 설명하고 있다.

  • Native로 개발하는 것보다 WebView를 보여주기에 적합한 경우는, 앱의 컨텐츠의 변동이 잦을 때 추천한다.

개인적인 생각은 다음과 같다.

  • 기존 웹 사이트 기능을 빠르개 앱내 통합하거나, 다른 웹 기반 서비스를 앱내 사용하는 경우

WKWebView Delegate Protocol

WKWebView는 Delegate Pattern을 사용하여, 웹 콘텐츠의 로딩, 사용자 인터페이스 이벤트, 네비게이션 액션 등을 관리하고 커스터마이징할 수 있게 해준다.

  • WKUIDelegate
    - 설명: Web 컨텐츠와 iOS Native 중 UI와 상호작용에 관련된 기능이 포함된 Protocol
    - 사용 예시
    - alert() / confirm() 이벤트 리스너 역할: iOS의 System Alert창을 노출하고 싶을 때
    - window.open() 이벤트 리스너 역할: 새 창 열기 호출 시, 필요한 로직이 있는 경우(Javascript에서 호출한 경우 이벤트 핸들링)
  • WKNavigationDelegate
    - 설명:웹에 있는 링크 동작을 제어하거나, 리다이렉션처리, SSL/TLS와 같은 인증처리를 담당하는 Protocol
    - 사용 예시
    - window.location.href(새로운 URL 이동 시 = 네이비게이션), 이벤트 핸들링: 네비게이션을 하는데, 특정 URL은 차단하고 싶을 때(혹은 허용하고 싶을 때)
    - 페이지 로드 상태를 핸들링: 로딩 시작 -> 로딩 완료(혹은 실패) 에 대해서 특정 로직을 수행하고 싶을 때,
    - 리디렉션 처리
    - 인증요청 처리

WKWebView 코드 구조

@available(iOS 8.0, *)
open class WKWebview: UIView {
	@NSCopying open var configuration: WKWebViewConfiguration { get } 
	weak open var naivgaitonDelegate: WKNavigationDelegate?
	weak open var uiDelegate: WKUIDelegate?
	open var backForwardList: WKBackForwardList { get }
	
	public init(frame: CGRect, configuration: WKWebViewConfiguration)
	...
}
  • 기본적으로 UIView를 상속받아서 구현하고 있다.
  • WKWebViewConfiguration에서 다양한 설정값들을 설정을 할 수 있다.
    - Javascript 코드 동작 On/Off
    - Web <-> Native 간 메시지 전달
    - ProcessPool 관리를 통해서, 리소스 관리하기
    - 웹 사이트에서 사용하는 데이터 저장소 설정
    - 미디어 재생 설정 ex) allowsInlineMediaPlayback
  • navigationDelegate & uiDelegate는 프로토콜 델리게이트 패턴 적용을 위해 참조변수로 선언되어 있다.
  • backForwardList를 통해서 이전까지 라우팅된 기록 그리고 현재 화면을 조회할 수 있다.

정리

위 내용들은 공식문서의 내용을 가져와서 나의 언어로 바꾼 내용이다. 다만 내용은 방대하지만 위 내용으로 추린 이유는,
내가 한 번이라도 혹은 자주 작업했던 컴포넌트들을 위주로 정리를 했다.

  • WKWebView는 iOS에서 WebView를 생성하기 위한 가장 기본이 되는 객체이다.
  • 이 객체를 통해서 Web과 상호작용하여, Web Contents를 보여줄 수 있고, 여기에 네이티브 기능을 함께 사용할 수도 있다.
  • WKWebView 와 그와 관련된 객체들이 상당히 다양한 개념을 제공하고 있으므로, 틈틈이 봐두자.

참고 코드

Javascript Message 수신하기 예제코드

import WebKit

class ViewController: UIViewController, WKScriptMessageHandler {
    
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let config = WKWebViewConfiguration()
        config.userContentController.add(self, name: "jsInterface")
        
        webView = WKWebView(frame: self.view.frame, configuration: config)
        self.view.addSubview(webView)
        
        if let url = URL(string: "https://your-web-page.com") {
            webView.load(URLRequest(url: url))
        }
    }
    
    // WKScriptMessageHandler 메서드 구현
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "jsInterface" {
            print("JavaScript에서 메시지 수신: \(message.body)")
            // 여기에서 JavaScript 메시지 처리 로직 구현
        }
    }
}

웹뷰 인증 요청하기 예제 코드

func webView(_ webView: WKWebView, 
             didReceive challenge: URLAuthenticationChallenge, 
             completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // 사용자 이름과 비밀번호를 통한 HTTP 기본 인증 처리
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
        let user = "username"
        let password = "password"
        let credential = URLCredential(user: user, password: password, persistence: .forSession)
        completionHandler(.useCredential, credential)
    } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        // SSL/TLS 인증서를 검증하는 코드
        if let serverTrust = challenge.protectionSpace.serverTrust {
            let credential = URLCredential(trust: serverTrust)
            completionHandler(.useCredential, credential)
        } else {
            completionHandler(.cancelAuthenticationChallenge, nil)
        }
    } else {
        // 다른 유형의 인증 요청에 대한 처리
        completionHandler(.cancelAuthenticationChallenge, nil)
    }
}

UIDelegate 사용 예제

import WebKit

class ViewController: UIViewController, WKUIDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view.addSubview(webView)

        let myURL = URL(string:"https://www.example.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }

    // WKUIDelegate 메서드를 구현하여 사용자 정의 UI 동작을 제공할 수 있습니다.
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        // 새 창을 여는 동작을 처리하는 코드
        return nil
    }
}

alert() or confirm() 핸들링
1. 웹에서 alert() or confirm()을 호출한다.

<script>
    function showConfirm() {
        var result = confirm("이 작업을 계속하시겠습니까?");
        if (result) {
            // 사용자가 "확인"을 클릭한 경우
            alert("작업을 계속합니다.");
        } else {
            // 사용자가 "취소"를 클릭한 경우
            alert("작업을 취소합니다.");
        }
    }
</script>
<button onclick="showConfirm()">확인 창 보기</button>
  1. 네이티브에 전달하여, 화면을 UIAlertController를 구성한다.
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
    let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { _ in completionHandler(true) }))
    alertController.addAction(UIAlertAction(title: "취소", style: .cancel, handler: { _ in completionHandler(false) }))
    present(alertController, animated: true, completion: nil)
}

참고자료

profile
iOS & Flutter

0개의 댓글