Swift WKWebview 구현하기
앱에 WebView를 띄워 postMessage를 전달하고 결과를 받아 봅시다.
WKWebview 생성하기
먼저 WebKit을 import 하고 WKWebView 타입 변수를 생성하고 View에 WKWebView를 추가합니다.
import UIKit
import WebKit
class WebViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
createWebView()
}
/// WKWebView 생성
func createWebView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.frame = view.bounds
view.addSubview(webView)
}
}
WKUIDelegate를 채택하여 WebView의 생성/삭제, JavaScript의 이벤트 수신할 수 있습니다.
https://developer.apple.com/documentation/webkit/wkuidelegate
WKWebview 불러오기
WKWebView의 load API를 호출하면 웹페이지를 불러옵니다.
/// WebView 불러오기
func loadWebView() {
guard let url = URL(string: "https://주소를 입력하세요") else { return }
let request = URLRequest(url: url)
webView.load(request)
}
PostMessage 보내기
window.postMessage()와 동일한 역할을 하는 API 이름을 알기 쉽지 않았는데
구글링도 아니고 삽질을 통해 알아냈습니다..ㅎㅎ
WKUserScript를 생성하여 Configuration에 추가해 줍니다.
/// WKWebView 생성
func createWebView() {
let webConfiguration = WKWebViewConfiguration()
////////////////////////////////////
// postMessage 설정
let requestData: String = "전송할 데이터"
let userScript = WKUserScript(source: "postMessage('\(requestData)')",
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
webConfiguration.userContentController.addUserScript(userScript)
webConfiguration.preferences.javaScriptEnabled = true
////////////////////////////////////
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view.addSubview(webView)
}
메시지 수신하기
메시지를 수신하기 위해 WKScriptMessageHandler를 채택하고, userContentController에 응답이름을 등록합니다.
WKScriptMessageHandler는 userContentController(_:didReceive:) 함수를 필수로 구현해야 합니다.
message.body로 수신한 메시지를 확인해 봅시다.
class WebViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler {
var webView: WKWebView!
let responseName: String = "응답이름"
override func viewDidLoad() {
super.viewDidLoad()
createWebView()
}
/// WKWebView 생성
func createWebView() {
let webConfiguration = WKWebViewConfiguration()
// postMessage 설정
let requestData: String = "전송할 데이터"
let userScript = WKUserScript(source: "postMessage('\(requestData)')",
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
webConfiguration.userContentController.addUserScript(userScript)
webConfiguration.preferences.javaScriptEnabled = true
////////////////////////////////////
// 메시지 수신할 핸들러 등록
webConfiguration.userContentController.add(self, name: responseName)
////////////////////////////////////
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view.addSubview(webView)
}
/// WebView 메시지 핸들러
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard message.name == responseName, let body = message.body as? String else { return }
// body를 파싱하거나 결과 메시지를 확인합니다.
NSLog("수신한 메시지: \(body)")
}
}
WebView에서 카메라 사용 시 카메라 권한 확인하기
Configuration에 allowsInlineMediaPlayback을 true로 설정합니다.
카메라 권한이 있을 경우 이전에 구현한 loadWebView를 호출하도록 했습니다.
그런데 카메라 권한을 앱에서 줘도 WebView에서 한 번 더 체크하더라구요? 제거하는 방법은 찾지 못했습니다.. 어쩔 수 없는 것인지..
import AVFoundation
/// WKWebView 생성
func createWebView() {
let webConfiguration = WKWebViewConfiguration()
////////////////////////////////////
// 카메라 권한 허용
webConfiguration.allowsInlineMediaPlayback = true
////////////////////////////////////
// postMessage 설정
let requestData: String = "전송할 데이터"
let userScript = WKUserScript(source: "postMessage('\(requestData)')",
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
webConfiguration.userContentController.addUserScript(userScript)
webConfiguration.preferences.javaScriptEnabled = true
// 메시지 수신할 핸들러 등록
webConfiguration.userContentController.add(self, name: responseName)
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view.addSubview(webView)
}
/// Camera 권한 체크
func checkCameraPermission() {
let permission = AVCaptureDevice.authorizationStatus(for: .video)
switch permission {
case .authorized:
DispatchQueue.main.async { self.loadWebView() }
case .denied:
let alert = UIAlertController(title: "카메라 권한 필요",
message: "설정 > 개인 정보 보호 > 카메라에서 권한을 변경하실 수 있습니다.",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: false, completion: nil)
return
case .notDetermined:
// 권한 요청
AVCaptureDevice.requestAccess(for: .video) { granted in
if granted {
DispatchQueue.main.async { self.loadWebView() }
} else {
NSLog("권한이 거부되었습니다.")
}
}
default:
NSLog("Permission = \(permission.rawValue)")
}
}
카메라 권한을 얻기 위해서는 Info.plist에 Privacy - Camera Usage Description을 설정해야 합니다.안할 경우 crash 발생합니다.
JSON Encoding/Decoding
/// JSON Encoding
func encodedString() -> String? {
var jsonData: [String: Any] = []
do {
// JSON
let jsonData = try JSONSerialization.data(withJSONObject: jsonData, options: .prettyPrinted)
return encodedString = String(data: jsonData, encoding: .utf8)
} catch {
NSLog(error.localizedDescription)
}
return nil
}
/// JSON Decoding
func parsingJson(_ jsonString: String) -> MyResponse? {
if let jsonData = jsonString.data(using: .utf8) {
let decoder = JSONDecoder()
let response = try? decoder.decode(MyResponse.self, from: jsonData)
return response
}
return nil
}
struct MyResponse: Codable {
let result: String
}