ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • iOS/Swift WKWebView 쿠키 공유하기
    Language/iOS,AOS 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()
            }
        }
     
        ...
    }

     

    끝!

    댓글

Designed by Tistory.