금융권 iOS 앱 개발을 희망한다면, 다음과 같은 내용을 많이 봤을지 모른다.
물론 예외도 있다. 카카오뱅크는 네이티브 100%로 구현된 앱으로 유명하다.
Web으로 개발하는 이유는 다양하다.
현실적인 이유는 다음과 같다.
WebView로 여러 서비스를 운영해보면서 느낀점은,
Hybrid도 구조를 처음부터 잘 잡아서 구성하면 괜찮다는 점이다. 돈을 아끼기 위해서 하이브리드 앱을 도입하거나, 옛날 기술이라서 그냥 도입한다면 사실 그냥 보기 싫은 레거시일 뿐이다.
Hybrid의 좋은 구조에 대해서는 다른 글에서 설명하고자 한다.
어째든, 그래서 Hybrid앱도 잘 다뤄야하고 그 첫걸음이 iOS에 있어서는 WKWebview
를 아는 것이다.
WKWebView이 어떤 기능을 제공하는지 알고 있어야, 요구사항의 일정 산정부터 개발가능 여부에 대한 커뮤니케이션이 가능하다. 까먹을 때쯤 목차라도 봐두면서, 나중에 찾아갈 수 있도록 인지해두자.
An Object that displays interactive web content, such as for an in-app browser.
상호작용이 가능한 웹 컨텐츠를 보여주기 위한 객체
공식문서에서, WebView를 사용하기 적합한 경우를 다음과 같이 설명하고 있다.
개인적인 생각은 다음과 같다.
WKWebView
는 Delegate Pattern을 사용하여, 웹 콘텐츠의 로딩, 사용자 인터페이스 이벤트, 네비게이션 액션 등을 관리하고 커스터마이징할 수 있게 해준다.
alert() / confirm()
이벤트 리스너 역할: iOS의 System Alert창을 노출하고 싶을 때window.open()
이벤트 리스너 역할: 새 창 열기 호출 시, 필요한 로직이 있는 경우(Javascript에서 호출한 경우 이벤트 핸들링)window.location.href
(새로운 URL 이동 시 = 네이비게이션), 이벤트 핸들링: 네비게이션을 하는데, 특정 URL은 차단하고 싶을 때(혹은 허용하고 싶을 때)@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)
...
}
WKWebViewConfiguration
에서 다양한 설정값들을 설정을 할 수 있다.allowsInlineMediaPlayback
navigationDelegate
& uiDelegate
는 프로토콜 델리게이트 패턴 적용을 위해 참조변수로 선언되어 있다.backForwardList
를 통해서 이전까지 라우팅된 기록 그리고 현재 화면을 조회할 수 있다.위 내용들은 공식문서의 내용을 가져와서 나의 언어로 바꾼 내용이다. 다만 내용은 방대하지만 위 내용으로 추린 이유는,
내가 한 번이라도 혹은 자주 작업했던 컴포넌트들을 위주로 정리를 했다.
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)
}
}
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>
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)
}