Language/iOS,AOS
iOS/Swift WKWebView 쿠키 공유하기
건담아빠
2024. 9. 23. 16:54
iOS/Swift로 하이브리드 앱으로 개발된 서비스에서 새창일경우 View하나 만들어서 WKWebView로 페이지를 띄우는데 새창의 웹뷰에서 로그인이 되었을 경우에 부모창에는 쿠키가 공유되지 않는 문제가 발생하였다.
현재 버전에서 문제점을 파악하고 후딱 처리해보자.
웹에서 Bridge를 통해서 Native 함수를 호출하고 Native상 메소드에서 부모 WebView에 쿠키를 공유하는 방법으로 진행하였다.
React
Common library
// 자식창에서 로그인 후 부모창의 세션정보를 업데이트 하기 위해 사용
static updateSessionOfOpener() {
if (Util.Browser.isAndroidApp()) {
AndroidBridge.callOpener('Common.Native.updateSession');
} else if (Util.Browser.isIosApp()) {
// IOS 자식창에서 로그인 후 부모창의 세션정보를 업데이트
window.updateSessionOfOpenerCallback = (jsonData) => {
if (jsonData['result'] === false) {
// updateSessionOfOpener이 Native에 없을떄 후처리
// alert('FAIL');
} else {
// alert('SUCCESS');
}
};
const message = {
action: 'updateSessionOfOpener',
callback: 'window.updateSessionOfOpenerCallback',
};
window.webkit.messageHandlers.IosBridge1.postMessage(message);
} else {
if (window.opener && window.opener.sessionHandler) {
window.opener.sessionHandler.update();
}
}
}
Swift
MainViewController
// MARK: - iOS Bridge
// 웹 액션 정의 : WebAction을 구분하는데 사용되는 타입
enum WebAction: String {
case setAppData
case getAppData
case getAppVersion
case getVersionCode
case loginWithKakao
case loginWithNaver
case loginWithFacebook
case loginWithApple
case windowFullPDF
case windowFull
case windowFrame
case openExternalLink
case windowClose
case windowCloseAndOpenerReload
case getNotificationId
case getDeepLink
case share
case isNotificationAuthorization
case updateSessionOfOpener
}
extension MainViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard message.name == IOS_BRIDGE_NAME,
let messageBody = message.body as? [String: Any],
let action = messageBody["action"] as? String else { return }
let webAction = WebAction(rawValue: action)
Utils.Log("@@@@@@@@@@@@@@@@@@@@@@@ \(action)")
switch webAction {
...
case .updateSessionOfOpener:
// 로그인 후 팝업 웹뷰의 쿠키를 메인 웹뷰로 동기화
if let popupWKWebView = self.getActiveWkWebView(), let mainWKWebView = wKMainWeb {
// 쿠키 동기화 후 메인 웹뷰만 새로고침
Utils.syncCookies(from: popupWKWebView, to: mainWKWebView) {
// 쿠키 동기화 완료 후에 메인 웹뷰를 새로고침
mainWKWebView.reload()
// 혹시 모르니 콜백
guard let callback = messageBody["callback"] as? String else { return }
let jsonData: [String: Any] = [
"result": true
]
if let jsonString = Utils.convertDictionaryToJSONString(dictionary: jsonData) {
self.executeJavasScript(wKWeb: self.getActiveWkWebView(), callback: "\(callback)(\(jsonString));")
} else {
Utils.Log("Failed to convert dictionary to JSON string.")
}
}
}
default:
Utils.Log("undefined action")
// 콜백 함수 실행
guard let callback = messageBody["callback"] as? String else { return }
let jsonData: [String: Any] = [
"result": false,
"message": "undefined action"
]
if let jsonString = Utils.convertDictionaryToJSONString(dictionary: jsonData) {
self.executeJavasScript(wKWeb: self.getActiveWkWebView(), callback: "\(callback)(\(jsonString));")
} else {
Utils.Log("Failed to convert dictionary to JSON string.")
}
}
}
}
Utils
class Utils: NSObject {
...
static func syncCookies(from sourceWebView: WKWebView, to targetWebView: WKWebView, completion: @escaping () -> Void) {
sourceWebView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
for cookie in cookies {
targetWebView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
}
// 쿠키 동기화가 끝난 후 completion 호출
completion()
}
}
...
}
끝!