[iOS - swift] 2. WKWebView 사용 방법 (웹뷰, 쿠키...

[iOS - swift] 2. WKWebView 사용 방법 (웹뷰, 쿠키...

1. WKWebView 개념1 (UIWebView, AJAX, XHR, 캐시, 쿠키)

2. WKWebView 사용 방법 (웹뷰, 쿠키, WKScriptMessageHandler, WKNavigationDelegate, WKUIDelegate)

WKWebView를 사용하기 전 알아야할 기본 개념

WKWebView 기본 사용 방법

webView초기화: 가끔 viewDidLoad()에서 view를 초기화하여 사용하지만, webView같은 경우 viewDidLoad에서 초기화하지 않고 viewController 블록 내에서 바로 초기화하여 사용하는게 효율적

import WebKit let webView = WKWebView()

loadView()를 override하여 webView를 할당 loadView(): ViewController가 기본적으로 가지고 있는 view를 다른 view로 지정하고 싶은 경우 override하여 사용

override func loadView() { self.view = webView }

remote content 로드 방법

if let url = URL(string: "https://www.apple.com" { let request = URLRequest(url: url) webView.load(request) }

local content 로드 방법 url .deletingLastPathComponent(): url의 last path 컴포넌트가 제거된 url로 반환

if let url = Bundle.main.url(forResource: "help", withExtension: "html") { /// allowingReadAccessTo: url.deletingLastPathComponent(): "help.html"이라는 파일 로드하는 코드 webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) }

웹뷰에 HTML 직접 코드로 정의: loadHTMLString(:baseURL:) 사용 단, image나 CSS와 같은 번들의 assets을 참조해야하는 경우는 baseURL을 Bundle.main.resourceURL로 사용

let html = """ Hello, Swift! """ webView.loadHTMLString(html, baseURL: nil) /// image나 CSS와 같은 bundle의 assets에 접근하는 경우 webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)

WebView의 WKNavigationDelegate

ex) WKNavigationDelegate를 이용하여 특정 사이트에 대해서 방문할 수 없도록 제한하는 방법

WKNavigationDelegate 프로토콜 conform

class ViewController: UIViewController, WKNavigationDelegate { ... webView.navigationDelegate = self

webView(:decidePolicyFor:decisionHandler:) 메소드에서 decisionHandler에 허용하는 페이지면 .allow, 허용하지 않으면 .cancel로 전달

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if let host = navigationAction.request.url?.host { if host == "www.apple.com" { decisionHandler(.allow) return } } decisionHandler(.cancel) }

webVoew(:decidePolicyFor:decisionHandler:) 전화화면, 이메일 화면으로 이동되게끔 하는 코드

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if let url = navigationAction.request.url { if url.scheme == "mailto" || url.scheme == "tel" { if UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } decisionHandler(.cancel) return } } decisionHandler(.allow) return }

Page load 이벤트 구독

유저에게 웹이 HTML fetching중, CSS, image등을 다운받고 있어서 로딩중인걸 알리는 방법: estimatedProgress를 옵저빙

// 구독 webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) // 이벤트 수신은 observeValue 메소드를 오버라이딩 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "estimatedProgress" { print(Float(webView.estimatedProgress)) } }

웹 페이지의 title이 변경되었을 때 알 수 있는 방법: title를 옵저빙

// 구독 webView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: .new, context: nil) // 이벤트 수신은 observerValue 메소드를 오버라이딩 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "estimatedProgress" { print(Float(webView.estimatedProgress)) } }

유저가 방문한 페이지 조회

backList

for page in webView.backForwardList.backList { print("User visited \(page.url.absoluteString)") }

forwardList

for page in webView.backForwardList.forwardList { print("User visited \(page.url.absoluteString)") }

Page에 Javascript를 주입하는 방법

evaluateJavaScript() 사용

webView.evaluateJavaScript("document.getElementById('username').innerText") { (result, error) in if let result = result { print(result) } }

쿠키, Cookie 읽기 & 삭제

webView.configuration.websiteDataStore.httpCookieStore.getAllCookies로 쿠키 접근

// 인증 쿠키는 모두 삭제하고, 다른 쿠키는 출력하는 코드 webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in for cookie in cookies { if cookie.name == "authentication" { self.webView.configuration.websiteDataStore.httpCookieStore.delete(cookie) } else { print("\(cookie.name) is set to \(cookie.value)") } } }

웹 서버에 웹 브라우저에 접속하는 user 식별 값 전달 방법

customUserAgent 프로퍼티 사용

webView.customUserAgent = "My Awesome App"

WebView에서 자바 스크립트의 alert() 반응에 대한 처리 방법

WKUIDelegate를 conform

class ViewController: UIViewController, WKUIDelegate { ... webView.uiDelegate = self

webView(:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:) 메소드 구현

// 자바스크립트에서 alert() 기능을 사용하고 싶은 경우 func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let ac = UIAlertController(title: "Hey, listen!", message: message, preferredStyle: .alert) ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) present(ac, animated: true) completionHandler() }

WebView 화면 캡쳐

webView.takeSnapshot(with:) 사용

// 웹뷰의 왼쪽 상단 150*50 이미지 생성 let config = WKSnapshotConfiguration() config.rect = CGRect(x: 0, y: 0, width: 150, height: 50) webView.takeSnapshot(with: config) { image, error in if let image = image { print(image.size) } }

전화번호, 일정, 번호 등을 탭 가능한 링크로 표출 방법

WKWebView 생성 시 configuration정보 삽입

let config = WKWebViewConfiguration() config.dataDetectorTypes = [.all] let webView = WKWebView(frame: .zero, configuration: config)

* 참고

- The Ultimate Guide to WKWebView: https://www.hackingwithswift.com/articles/112/the-ultimate-guide-to-wkwebview

- WKWebView: https://developer.apple.com/documentation/webkit/wkwebview

- loadView(): https://developer.apple.com/documentation/uikit/uiviewcontroller/1621454-loadview

from http://ios-development.tistory.com/701 by ccl(A) rewrite - 2021-09-16 00:01:30