투케이2K

31. (TWOK/UTIL) [Ios/Swift] A_Main - 웹뷰 로드 화면 관련 클래스 정리 본문

투케이2K 유틸파일

31. (TWOK/UTIL) [Ios/Swift] A_Main - 웹뷰 로드 화면 관련 클래스 정리

투케이2K 2022. 3. 30. 10:45

[설 명]

프로그램 : Ios / Swift

설 명 : 웹뷰 로드 화면 관련 클래스 정리

 

[소스 코드]

 

import UIKit
import SafariServices
import WebKit
import AVFoundation

class A_Main: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate {
    

    // MARK: - [클래스 설명]
    /*
    // -----------------------------------------
    1. 메인 웹뷰 화면 호출 액티비티 화면
    2. 사용하는 스토리보드 : Main
    3. 웹뷰 호출 실시 및 자바스크립트 통신 처리
    // -----------------------------------------
    */
    
    
    
    
    
    // MARK: - [빠른 로직 찾기 : 주석 로직 찾기]
    // -----------------------------------------
    // [SEARCH FAST] : [인트로 화면 처리]
    // [SEARCH FAST] : [메인 웹뷰 포그라운드 푸시 알림 JS 전달]
    // [SEARCH FAST] : [저장된 프리퍼런스 데이터 확인]
    // [SEARCH FAST] : [네트워크 활성 상태 체크]
    // [SEARCH FAST] : [웹뷰 로드 수행 실시]
    // [SEARCH FAST] : [포그라운드 및 백그라운드 상태 확인]
    // [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
    // [SEARCH FAST] : [웹뷰 리로드 상태 확인]
    // [SEARCH FAST] : [자바스크립트 통신 수행]
    // [SEARCH FAST] : [웹뷰 에러 코드 감지]
    // -----------------------------------------
    
    
    
    
    
    // MARK: - [웹뷰 전역 변수 선언 부분]
    private var main_webview: WKWebView? = nil // [동적으로 웹뷰 생성]
    var javascriptController = WKUserContentController() // [자바스크립트 통신 사용]
    let javascriptConfig = WKWebViewConfiguration() // [자바스크립트 통신 사용]
    let kwebviewPreference = WKPreferences() // [웹뷰에 대한 기본 속성 설정을 캡슐화]

    
    
    
    
    // MARK: - [뷰 컨트롤러 종료 시 호출되는 함수]
    deinit {
        // [WKWebView Progress 퍼센트 가져오기 이벤트 제거]
        if self.main_webview != nil {
            self.main_webview?.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
        }
        
        // [브로드 캐스트 알림 해제]
    }
    
    
    
    
    
    // MARK: - [뷰 화면 관련 전역 변수]
    @IBOutlet weak var introBg: UIImageView!
    
    
    

    
    // MARK: - [일반 전역 변수]
    let ACTIVITY_NAME = "A_Main"
    
    
    
    
    
    // MARK: - [뷰 로드 실시]
    override func viewDidLoad() {
        super.viewDidLoad()
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidLoad() :: 뷰 로드 실시]")
        print("====================================")
        print("")

        // -----------------------------------------
        // [뷰 컨트롤러 배경 색상 지정]
        self.view.backgroundColor = UIColor.init(rgb: 0xffffff).withAlphaComponent(1.0)
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [메인 웹뷰 포그라운드 푸시 알림 JS 전달]
        S_Preference().setString(_sKey: S_FinalData.PRE_ROOT_ACTIVITY, _sValue: "RUN")
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [저장된 프리퍼런스 데이터 확인]
        S_Preference().setString(_sKey: S_FinalData.PRE_MOBILE_MOCO, _sValue: S_DeviceID().getDeviceID()) // [디바이스 고유값 저장]
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidLoad() :: 사전 저장된 프리퍼런스 데이터 확인]")
        print("-------------------------------")
        print("univ :: [학교 구분] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_USER_UNIV))
        print("-------------------------------")
        print("uid :: [사용자 학번] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_USER_UID))
        print("-------------------------------")
        print("upw :: [사용자 비번] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_USER_UPW))
        print("-------------------------------")
        print("iddi :: [사용자 신분] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_USER_IDDI))
        print("-------------------------------")
        print("autoLogin :: [자동 로그인] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_AUTO_LOGIN))
        print("-------------------------------")
        print("picture :: [사용자 사진 표시] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_USER_PICTURE))
        print("-------------------------------")
        print("shake :: [흔들기 이벤트] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_SHAKE))
        print("-------------------------------")
        print("plat :: [플랫폼] :: ", S_FinalData.PRE_MOBILE_PLAT)
        print("-------------------------------")
        print("moco :: [디바이스 고유값] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_MOCO))
        print("-------------------------------")
        print("version :: [앱 버전] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_VERSION))
        print("-------------------------------")
        print("code :: [앱 코드] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_CODE))
        print("-------------------------------")
        print("token :: [푸시 토큰] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_PUSH_TOKEN))
        print("-------------------------------")
        print("loginScheme :: [로그인 스키마 데이터] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_LOGIN))
        print("-------------------------------")
        print("callScheme :: [일반 스키마 데이터] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_CALL))
        print("-------------------------------")
        print("PRE_APP_UPDT_TIME :: [앱 재구동 시간 [분 단위]] :: ", S_Preference().getString(_sKey: S_FinalData.PRE_APP_UPDT_TIME))
        print("====================================")
        print("")

        
        /*
        // MARK: [스키마 데이터 확인]
        self.showAlert(type: 0,
                       tittle: "[스키마 및 숏컷 접속 확인]",
                       content: "로그인 스키마 데이터 : " + S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_LOGIN) + "\n"
                       + "일반 스키마 데이터 : " + S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_CALL) + "\n",
                       okBtb: "확인",
                       noBtn: "")
        // */
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [뷰 컨트롤러 상태 업데이트 수행 실시 >> 퍼미션 권한 체크]
        self.permissionState()
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [네트워크 활성 상태 체크]
        if C_StateCheck().getWhatOfNetwork() == true { // SceneDelegate 저장된 데이터 확인
            
            // [SEARCH FAST] : [웹뷰 로드 수행 실시]
            self.init_WebView(_loadUrl: S_FinalData.WV_LOAD_MAIN_ENZ_URL)
        }
        else {
            // [알림 팝업창 호출]
            self.showAlert(
                type:0,
                tittle: S_FinalData.AL_TITLE,
                content: S_FinalData.AL_NET + " (\(self.ACTIVITY_NAME))",
                okBtb: S_FinalData.AL_OK,
                noBtn: ""
            )
        }
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [뷰 컨트롤러 파일에서 설정 : 상태바 콘텐츠 색상 변경]
    override var preferredStatusBarStyle: UIStatusBarStyle {
        if #available(iOS 13, *) {
            //return .lightContent // [흰 색상 콘텐츠 표시]
            return .darkContent // [검은 색상 콘텐츠 표시]
            //return .default // [검은 색상 콘텐츠 표시]
        } else {
            return .default
        }
    }
    
    
    
    
    
    // MARK: - [뷰 로드 완료]
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewWillAppear() :: 뷰 로드 완료]")
        print("====================================")
        print("")
    }
        
    
    
    
    
    // MARK: - [뷰 화면 표시]
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidAppear() :: 뷰 화면 표시]")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [포그라운드 및 백그라운드 상태 확인]
        NotificationCenter.default.addObserver( // [포그라운드]
            self,
            selector: #selector(self.checkForeground),
            name: UIApplication.willEnterForegroundNotification,
            object: nil
        )
        NotificationCenter.default.addObserver( // [백그라운드]
            self,
            selector: #selector(self.checkBackground),
            name: UIApplication.didEnterBackgroundNotification,
            object: nil
        )
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [포그라운드 처리 실시]
        self.checkForeground()
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [뷰 정지 상태]
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewWillDisappear() :: 뷰 정지 상태]")
        print("====================================")
        print("")
    }
        
    
    
    
    
    // MARK: - [뷰 종료 상태]
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidDisappear() :: 뷰 종료 상태]")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [포그라운드 및 백그라운드 상태 확인]
        NotificationCenter.default.removeObserver( // [포그라운드]
            self,
            name: UIApplication.willEnterForegroundNotification,
            object: nil
        )
        NotificationCenter.default.removeObserver( // [백그라운드]
            self,
            name: UIApplication.didEnterBackgroundNotification,
            object: nil
        )
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
        S_Preference().mainFinishClear()
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [포그라운드 상태 처리 메소드 작성]
    @objc func checkForeground() {
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> checkForeground() :: 뷰 컨트롤러 포그라운드]")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [웹뷰 리로드 상태 확인]
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [뷰 컨트롤러 상태 업데이트 수행 실시]
        self.permissionState()
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [백그라운드 상태 처리 메소드 작성]
    @objc func checkBackground() {
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> checkBackground() :: 뷰 컨트롤러 백그라운드]")
        print("====================================")
        print("")
    }
    
    
    
    
    
    // MARK: - [퍼미션 상태 값 갱신 메소드 : 포그라운드 상태로 올라올때 마다 체크 수행 : 사용자가 강제로 변경한 상태 체크]
    func permissionState(){
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> permissionState() :: 뷰 컨트롤러 퍼미션 상태 업데이트 수행 실시]")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [위치 권한 활성 상태 체크 메소드 호출]
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [블루투스 권한 설정 퍼미션 확인 실시]
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [웹뷰 초기 설정 값 정의 실시 및 웹뷰 로드 수행]
    func init_WebView(_loadUrl:String){
        // [사용자 모바일 상태바 높이 확인]
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> permissionState() :: 웹뷰 초기 설정 및 웹뷰 로드 수행]")
        print("-------------------------------")
        print("url :: \(_loadUrl)")
        print("-------------------------------")
        print("width :: ", self.view.frame.size.width)
        print("-------------------------------")
        print("height :: ", self.view.frame.size.height)
        print("-------------------------------")
        print("statusBarHeight :: ", statusBarHeight)
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [웹뷰 로드 수행 실시]
        // [SEARCH FAST] : [웹뷰 세션 및 캐시 삭제 수행]
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [전체 방문 데이터 지우기]
        /*
        WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), completionHandler: {
            (records) -> Void in
            for record in records{
                WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> init_WebView() :: 사전 전체 방문 데이터 삭제 수행]")
                print("-------------------------------")
                print("type :: removeData")
                print("====================================")
                print("")
            }
        })
        // */
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [원하는 캐시 데이터만 골라서 삭제]
        ///*
        let websiteDataTypes = NSSet(array:
                                            [WKWebsiteDataTypeDiskCache, // 디스크 캐시
                                             WKWebsiteDataTypeMemoryCache, // 메모리 캐시
                                             WKWebsiteDataTypeCookies, // 웹 쿠키,
                                             
                                             WKWebsiteDataTypeOfflineWebApplicationCache, // 앱 캐시
                                             WKWebsiteDataTypeWebSQLDatabases, // 웹 SQL 데이터 베이스
                                             WKWebsiteDataTypeIndexedDBDatabases // 데이터 베이스 정보
                                             
                                             //WKWebsiteDataTypeLocalStorage // 로컬 스토리지
                                             //WKWebsiteDataTypeSessionStorage // 세션 스토리지
                                            ])
        let date = NSDate(timeIntervalSince1970: 0)
        WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set, modifiedSince: date as Date, completionHandler:{
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> init_WebView() :: 사전 캐시 및 세션 데이터 삭제 수행]")
            print("-------------------------------")
            print("type :: removeData")
            print("====================================")
            print("")
        })
        // */
        // -----------------------------------------
        
        
        // -----------------------------------------        
        // [URL 요청 후 잔여 캐시 데이터 삭제]
        URLCache.shared.removeAllCachedResponses()        
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [설치된 날짜 가져오는 코드]
        let urlToDocumentsFolder: URL? = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
        let installDate = try? FileManager.default.attributesOfItem(atPath: (urlToDocumentsFolder?.path)!)[.creationDate] as! Date
        
        // [설치된 날짜부터 지금까지의 cookie all clear]
        URLSession.shared.configuration.httpCookieStorage?.removeCookies(since: installDate!)
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> init_WebView() :: 사전 캐시 및 세션 데이터 삭제 수행]")
        print("-------------------------------")
        print("type :: URLSession removeCookies")
        print("====================================")
        print("")
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [웹 보기에 대한 쿠키, 디스크 및 메모리 캐시, 기타 유형의 데이터를 관리하는 개체]
        self.javascriptConfig.websiteDataStore = WKWebsiteDataStore.default() // [디폴트]
        //self.javascriptConfig.websiteDataStore = WKWebsiteDataStore.nonPersistent() // [쿠키 셋팅]
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [자바스크립트 통신 수행]
        /*
        [브릿지 경로 지정]
        1. JS >> IOS 호출 시 사전 브릿지 경로 등록 필요
        */
        
        self.addJavaScriptBridge()
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [웹뷰 전체 화면 설정 실시]
        self.main_webview = WKWebView.init(
            frame: CGRect.init(
                x: 0,
                y: statusBarHeight,
                width: self.view.frame.width, // [전체 가로 지정]
                height: self.view.frame.height - statusBarHeight // [전체 높이 - 상태바 세로 지정]
            ),
            configuration: self.javascriptConfig
        )
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [웹뷰 캐시 삭제 실시]
        WKWebsiteDataStore.default().removeData(ofTypes:
        [
            WKWebsiteDataTypeDiskCache,
            WKWebsiteDataTypeMemoryCache
        ],
        modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [웹뷰 옵션값 지정]
        self.main_webview?.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true  // 자바스크립트 활성화
        self.main_webview?.navigationDelegate = self // 웹뷰 변경 상태 감지 위함
        //self.main_webview?.allowsBackForwardNavigationGestures = true // 웹뷰 뒤로가기, 앞으로 가기 제스처 사용
        self.main_webview?.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) // 웹뷰 로드 상태 퍼센트 확인
        self.main_webview?.uiDelegate = self // alert 팝업창 이벤트 받기 위함
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [웹뷰 스크롤 바운스 방지]
        self.main_webview?.scrollView.alwaysBounceVertical = false
        self.main_webview?.scrollView.bounces = false
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [메인 뷰에 웹뷰 추가 실시]
        self.view.addSubview(self.main_webview!)
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [실제 웹뷰 주소 로드]
        let url = URL (string: _loadUrl) // 웹뷰 로드 주소
        let request = URLRequest(url: url! as URL)
        self.main_webview!.load(request)
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [테스트 html 파일 로드]
        /*
        guard let localFilePath = Bundle.main.path(forResource: "javaScriptTest", ofType: "html")
        else {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> init_WebView() :: 웹뷰 로드 수행]")
            print("-------------------------------")
            print("error :: file path is nil")
            print("====================================")
            print("")
            return
        }
        let urlFile = URL(fileURLWithPath: localFilePath)
        let request = URLRequest(url: urlFile)
        self.main_webview!.load(request as URLRequest)
        // */
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [SEARCH FAST] : [인트로 화면 처리]
        self.main_webview?.isHidden = true // [사전 웹뷰 숨김 처리]
        // -----------------------------------------
    }

    
    
    
    
    // MARK: - [자바스크립트 통신을 위한 초기화 부분]
    // [SEARCH FAST] : [자바스크립트 통신]
    func addJavaScriptBridge(){
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> addJavaScriptBridge() :: 자바스크립트 통신 브릿지 추가]")
        print("-------------------------------")
        print("Bridge :: system")
        print("-------------------------------")
        print("Bridge :: setMarket")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [자바스크립트 통신 수행]
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [브릿지 경로 추가 : 데이터 받을 경로 : 자바스크립트 >> IOS]
        // [userContentController 부분에서 message.name 정의]
        self.javascriptController.add(self, name: "system")
        self.javascriptController.add(self, name: "setMarket")
        // -----------------------------------------
        
        
        // -----------------------------------------
        self.javascriptConfig.userContentController = self.javascriptController
        //self.main_webview = WKWebView(frame: self.view.bounds, configuration: javascriptConfig)
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [자바스크립트 >> IOS 통신 부분]
    @available(iOS 8.0, *)
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // -----------------------------------------
        // [SEARCH FAST] : [자바스크립트 통신 수행]
        // -----------------------------------------

        
        
        // -----------------------------------------
        // [웹 코드] window.webkit.messageHandlers.system.postMessage("");
        // -----------------------------------------
        if message.name == "system" {
            guard let checkType = message.body as? String // [전달 받은 메시지 확인]
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: system() :: JS >> IOS]")
                print("-------------------------------")
                print("error :: [type] :: ", type(of: message.body))
                print("====================================")
                print("")
                
                // [에러 팝업창 알림 표시]
                self.showAlert(
                    type: 0,
                    tittle: S_FinalData.AL_TITLE,
                    content: S_FinalData.ERROR_DATA_NULL + " [system]",
                    okBtb: S_FinalData.AL_OK,
                    noBtn: ""
                )
                
                // [리턴 종료]
                return
            }
            
            // -----------------------------------------
            
            // [자바스크립트에서 전달 받은 데이터 저장]
            let receiveData = message.body as! String
            
            // -----------------------------------------
            
            // [로그 출력 실시]
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> userContentController :: system() :: JS >> IOS]")
            print("-------------------------------")
            print("전달받은 데이터 :: ", receiveData)
            print("-------------------------------")
            print("설 명 :: ", "사용자 전체 계정 정보 요청")
            print("-------------------------------")
            print("로 직 :: ", "setSystem() 메소드 호출 수행 실시")
            print("====================================")
            print("")

            // -----------------------------------------
            
            // [로그인 스키마 데이터 딕셔너리 변환 실시]
            var loginDic : Dictionary<String, Any> = [String : Any]()
            var loginFlag = false
            let loginData = S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_LOGIN)
            
            if C_Util().stringNotNull(str: loginData) == true { // [널 값이 아닌 경우]
                
                // [jsonObject to Dictionary 변환 실시]
                loginDic = C_Util().jsonObject_To_Dic(jsonString: loginData)
                
                if loginDic != nil && loginDic.count>0 && loginDic.isEmpty == false { // [널 값이 아닌 경우]
                    
                    // [플래그값 변경]
                    loginFlag = true
                }
            }
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> userContentController :: system() :: JS >> IOS]")
            print("-------------------------------")
            print("설 명 :: ", "[사전] 로그인 스키마 데이터 값 체크 실시]")
            print("-------------------------------")
            print("스키마 데이터 :: ", loginDic.description)
            print("====================================")
            print("")
            
            // -----------------------------------------
            
            // [일반 스키마 데이터 딕셔너리 변환 실시]
            var callDic : Dictionary<String, Any> = [String : Any]()
            var callFlag = false
            let callData = S_Preference().getString(_sKey: S_FinalData.PRE_SCHEME_DATA_CALL)
            
            if C_Util().stringNotNull(str: callData) == true { // [널 값이 아닌 경우]
                
                // [jsonObject to Dictionary 변환 실시]
                callDic = C_Util().jsonObject_To_Dic(jsonString: callData)
                
                if callDic != nil && callDic.count>0 && callDic.isEmpty == false { // [널 값이 아닌 경우]
                    
                    // [플래그값 변경]
                    callFlag = true
                }
            }
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> userContentController :: system() :: JS >> IOS]")
            print("-------------------------------")
            print("설 명 :: ", "[사전] 일반 스키마 데이터 값 체크 실시]")
            print("-------------------------------")
            print("스키마 데이터 :: ", callDic.description)
            print("====================================")
            print("")
            
            // -----------------------------------------
            
            // [전체 자바스크립트로 전송할 데이터 생성 실시]
            var jsonDic : [String: Any] = [
                "moco" : S_DeviceID().getDeviceID(), // [디바이스 고유값]
                "version" : S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_VERSION), // [앱 버전 (ex : 1.0.0)]
                "code" : S_Preference().getString(_sKey: S_FinalData.PRE_MOBILE_CODE), // [앱 버전 코드 (ex : 1)]
                "plat" : S_FinalData.PRE_MOBILE_PLAT, // [모바일 플랫폼]
                "token" : S_Preference().getString(_sKey: S_FinalData.PRE_PUSH_TOKEN) // [파이어베이스 푸시 토큰]
            ] as Dictionary
            
            
            // [로그인 스키마 데이터]
            if loginFlag == true {
                jsonDic["loginScheme"] = loginDic // [딕셔너리 삽입]
            }
            else {
                jsonDic["loginScheme"] = "" // [널 데이터 삽입]
            }
            
            
            // [일반 스키마 데이터]
            if callFlag == true {
                jsonDic["callScheme"] = callDic // [딕셔너리 삽입]
            }
            else {
                jsonDic["callScheme"] = "" // [널 데이터 삽입]
            }
            
            // -----------------------------------------
            
            // [전체 Dictionary 데이터를 json으로 변환 실시]
            let jsonObj = C_Util().dic_To_JsonObject_String(_dicData: jsonDic)
            
            // -----------------------------------------
            
            // [IOS >> JS 호출 수행 실시]
            self.iosToJs_setSystem(_jsonData: jsonObj)
        }
        // -----------------------------------------
        
        
        
        // -----------------------------------------
        // [웹 코드] window.webkit.messageHandlers.setMarket.postMessage(jsonString);
        // -----------------------------------------
        if message.name == "setMarket" {
            guard let checkType = message.body as? String // [전달 받은 메시지 확인]
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                print("-------------------------------")
                print("error :: [type] :: ", type(of: message.body))
                print("====================================")
                print("")
                
                // [에러 팝업창 알림 표시]
                self.showAlert(
                    type: 0,
                    tittle: S_FinalData.AL_TITLE,
                    content: S_FinalData.ERROR_DATA_NULL + " [setMarket]",
                    okBtb: S_FinalData.AL_OK,
                    noBtn: ""
                )
                
                // [리턴 종료]
                return
            }
            
            
            // -----------------------------------------
            
            // [자바스크립트에서 전달 받은 데이터 저장]
            let receiveData = message.body as! String
            
            // -----------------------------------------
            
            // [자바스크립트 데이터 방어 로직 추가 실시 : 데이터 널 체크]
            if C_Util().stringNotNull(str: receiveData) == true { // [널 값이 아닌 경우]
            }
            else { // [널 값인 경우]
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                print("-------------------------------")
                print("전달받은 데이터 :: ", receiveData)
                print("-------------------------------")
                print("error :: [msg] :: ", S_FinalData.ERROR_DATA_NULL)
                print("====================================")
                print("")
                
                // [에러 팝업창 알림 표시]
                self.showAlert(
                    type: 0,
                    tittle: S_FinalData.AL_TITLE,
                    content: S_FinalData.ERROR_DATA_NULL + " [setMarket]",
                    okBtb: S_FinalData.AL_OK,
                    noBtn: ""
                )
                
                // [리턴 종료]
                return
            }
            
            // -----------------------------------------
            
            // [자바스크립트 데이터 방어 로직 추가 실시 : key 값 체크]
            if C_Util().stringMultiContains(str: receiveData.lowercased(), array: ["ios", "id"]) == true {
            }
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                print("-------------------------------")
                print("전달받은 데이터 :: ", receiveData)
                print("-------------------------------")
                print("error :: [msg] :: ", S_FinalData.ERROR_PARSING_KEY)
                print("====================================")
                print("")
                
                // [에러 팝업창 알림 표시]
                self.showAlert(
                    type: 0,
                    tittle: S_FinalData.AL_TITLE,
                    content: S_FinalData.ERROR_PARSING_KEY + " [setMarket]",
                    okBtb: S_FinalData.AL_OK,
                    noBtn: ""
                )
                
                // [리턴 종료]
                return
            }
            
            // -----------------------------------------
            
            // [자바스크립트 데이터 방어 로직 추가 실시 : json 데이터 형식 체크 실시]
            if C_Util().stringJsonObjectEnable(str: receiveData) == true {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                print("-------------------------------")
                print("전달받은 데이터 :: ", receiveData)
                print("-------------------------------")
                print("설 명 :: ", "마켓 이동 정보 전달 받음")
                print("-------------------------------")
                print("로 직 :: ", "마켓 수행 실시")
                print("====================================")
                print("")
                
                // [json 형식 문자열을 딕셔너리로 변환 실시]
                let jsonDic = C_Util().jsonObject_To_Dic(jsonString: receiveData)
                
                // [세부 json 데이터 받기 실시]
                if jsonDic.keys.contains("ios") == true { // [키값이 존재할 경우]
                    do {
                        // -----------------------------------------
                        // [딕셔너리에 세부 데이터 저장 실시]
                        var dicData : Dictionary<String, Any> = jsonDic["ios"] as! Dictionary<String, Any>
                        // -----------------------------------------
                        // [패키지명 및 앱 아이디 확인 실시]
                        let appId = dicData["id"] as! String // [앱 스토어 이동 아이디]
                        // -----------------------------------------
                        // [자바스크립트 전달 받은 데이터 확인 방어 로직 추가 : 에러 체크]
                        if C_Util().stringNotNull(str: appId) == true
                            && appId.hasPrefix("id") == true { // [널 데이터 아님]
                            
                            // [마켓 이동 수행 실시]
                            self.goMarketRun(_id: appId)
                        }
                        // -----------------------------------------
                        else { // [널 데이터]
                            print("")
                            print("====================================")
                            print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                            print("-------------------------------")
                            print("전달받은 데이터 :: ", receiveData)
                            print("-------------------------------")
                            print("error :: [msg] :: ", S_FinalData.ERROR_PARSING_DATA)
                            print("====================================")
                            print("")
                            
                            // [에러 팝업창 알림 표시]
                            self.showAlert(
                                type: 0,
                                tittle: S_FinalData.AL_TITLE,
                                content: S_FinalData.ERROR_PARSING_DATA + " [setMarket]",
                                okBtb: S_FinalData.AL_OK,
                                noBtn: ""
                            )
                            
                            // [리턴 종료]
                            return
                        }
                        // -----------------------------------------
                    }
                    catch {
                        print("")
                        print("====================================")
                        print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                        print("-------------------------------")
                        print("전달받은 데이터 :: ", receiveData)
                        print("-------------------------------")
                        print("catch :: ", error.localizedDescription)
                        print("====================================")
                        print("")
                    }
                }
            }
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> userContentController :: setMarket() :: JS >> IOS]")
                print("-------------------------------")
                print("전달받은 데이터 :: ", receiveData)
                print("-------------------------------")
                print("error :: [msg] :: ", S_FinalData.ERROR_JSON_PARSING)
                print("====================================")
                print("")
                
                // [에러 팝업창 알림 표시]
                self.showAlert(
                    type: 0,
                    tittle: S_FinalData.AL_TITLE,
                    content: S_FinalData.ERROR_JSON_PARSING + " [setMarket]",
                    okBtb: S_FinalData.AL_OK,
                    noBtn: ""
                )
                
                // [리턴 종료]
                return
            }
        }
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [IOS >> 자바스크립트 통신 부분]
    // -----------------------------------------
    // [SEARCH FAST] : [자바스크립트 통신]
    // -----------------------------------------
    func iosToJs_setSystem(_jsonData:String){
        
        // [인풋 데이터 널 체크 수행 실시]
        if C_Util().stringNotNull(str: _jsonData) == true {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> iosToJs_setSystem() :: IOS >> JS]")
            print("-------------------------------")
            print("JS 함수 :: setSystem")
            print("-------------------------------")
            print("전달할 데이터 :: ", _jsonData)
            print("-------------------------------")
            print("설 명 :: ", "사용자 전체 계정 정보 전송")
            print("====================================")
            print("")
            
            // MARK: [json 전송 : 자바스크립트 에서는 object 형식으로 받는다]
            self.main_webview!.evaluateJavaScript("setSystem(\(_jsonData))") { (success, error) in
                if error != nil {
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> iosToJs_setSystem() :: IOS >> JS]")
                    print("-------------------------------")
                    print("JS 함수 :: setSystem")
                    print("-------------------------------")
                    print("설 명 :: ", "사용자 전체 계정 정보 전송")
                    print("-------------------------------")
                    print("전송 결과 [error] :: ", error)
                    print("====================================")
                    print("")
                }
                else {
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> iosToJs_setSystem() :: IOS >> JS]")
                    print("-------------------------------")
                    print("JS 함수 :: setSystem")
                    print("-------------------------------")
                    print("설 명 :: ", "사용자 전체 계정 정보 전송")
                    print("-------------------------------")
                    print("전송 결과 [success] :: ", "OK")
                    print("====================================")
                    print("")
                }
            }
        }
        else {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> iosToJs_setSystem() :: IOS >> JS]")
            print("-------------------------------")
            print("JS 함수 :: setSystem")
            print("-------------------------------")
            print("설 명 :: ", "사용자 전체 계정 정보 전송")
            print("-------------------------------")
            print("error :: [msg] :: ", S_FinalData.ERROR_DATA_NULL)
            print("====================================")
            print("")
            
            // [에러 팝업창 알림 표시]
            self.showAlert(
                type: 0,
                tittle: S_FinalData.AL_TITLE,
                content: S_FinalData.ERROR_DATA_NULL + " [setSystem]",
                okBtb: S_FinalData.AL_OK,
                noBtn: ""
            )
            
            // [리턴 종료]
            return
        }
    }
    // -----------------------------------------
    // [SEARCH FAST] : [자바스크립트 통신]
    // -----------------------------------------
    func iosToJs_checkResult(_string:String){
        
        // [인풋 데이터 널 체크 수행 실시]
        if C_Util().stringNotNull(str: _string) == true {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> iosToJs_checkResult() :: IOS >> JS]")
            print("-------------------------------")
            print("JS 함수 :: checkResult")
            print("-------------------------------")
            print("전달할 데이터 :: ", _string)
            print("-------------------------------")
            print("설 명 :: ", "인증 번호 전송")
            print("====================================")
            print("")
            
            // MARK: [string 전송 : 36^1]
            self.main_webview!.evaluateJavaScript("checkResult('\(_string)')") { (success, error) in
                if error != nil {
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> iosToJs_checkResult() :: IOS >> JS]")
                    print("-------------------------------")
                    print("JS 함수 :: checkResult")
                    print("-------------------------------")
                    print("설 명 :: ", "인증 번호 전송")
                    print("-------------------------------")
                    print("전송 결과 [error] :: ", error)
                    print("====================================")
                    print("")
                }
                else {
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> iosToJs_checkResult() :: IOS >> JS]")
                    print("-------------------------------")
                    print("JS 함수 :: checkResult")
                    print("-------------------------------")
                    print("설 명 :: ", "인증 번호 전송")
                    print("-------------------------------")
                    print("전송 결과 [success] :: ", "OK")
                    print("====================================")
                    print("")
                }
            }
        }
        else {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> iosToJs_checkResult() :: IOS >> JS]")
            print("-------------------------------")
            print("JS 함수 :: checkResult")
            print("-------------------------------")
            print("설 명 :: ", "인증 번호 전송")
            print("-------------------------------")
            print("error :: [msg] :: ", S_FinalData.ERROR_DATA_NULL)
            print("====================================")
            print("")
            
            // [에러 팝업창 알림 표시]
            self.showAlert(
                type: 0,
                tittle: S_FinalData.AL_TITLE,
                content: S_FinalData.ERROR_DATA_NULL + " [checkResult]",
                okBtb: S_FinalData.AL_OK,
                noBtn: ""
            )
            
            // [리턴 종료]
            return
        }
    }
    // -----------------------------------------
    // [SEARCH FAST] : [자바스크립트 통신]
    // -----------------------------------------
    func iosToJs_shakeResult(){
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> iosToJs_shakeResult() :: IOS >> JS]")
        print("-------------------------------")
        print("JS 함수 :: shakeResult")
        print("-------------------------------")
        print("설 명 :: ", "디바이스 흔들기 이벤트 발생 전달")
        print("====================================")
        print("")
        
        // MARK: [함수 호출]
        self.main_webview!.evaluateJavaScript("shakeResult('\("")')") { (success, error) in
            if error != nil {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> iosToJs_shakeResult() :: IOS >> JS]")
                print("-------------------------------")
                print("JS 함수 :: shakeResult")
                print("-------------------------------")
                print("설 명 :: ", "디바이스 흔들기 이벤트 발생 전달")
                print("-------------------------------")
                print("전송 결과 [error] :: ", error)
                print("====================================")
                print("")
            }
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> iosToJs_shakeResult() :: IOS >> JS]")
                print("-------------------------------")
                print("JS 함수 :: shakeResult")
                print("-------------------------------")
                print("설 명 :: ", "디바이스 흔들기 이벤트 발생 전달")
                print("-------------------------------")
                print("전송 결과 [success] :: ", "OK")
                print("====================================")
                print("")
            }
        }
    }
    // -----------------------------------------
    
    
    
    
    
    // MARK: - [웹뷰 로드 수행 시작 부분]
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        let _startUrl = String(describing: webView.url?.description ?? "")
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> didStartProvisionalNavigation() :: 웹뷰 로드 수행 시작]")
        print("-------------------------------")
        print("주 소 :: \(_startUrl)")
        print("====================================")
        print("")
    }
    
    
    
    
    
    // MARK: - [실시간 웹뷰 로드 상태 퍼센트 확인 부분 : 0.1 ~ 1.0]
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        // [0 ~ 1 사이의 실수형으로 결과값이 출력된다 [0 : 로딩 시작, 1 : 로딩 완료]]
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> observeValue() :: 실시간 웹뷰 로드 상태 확인]")
        print("-------------------------------")
        print("원 본 :: \(Float((self.main_webview?.estimatedProgress)!))")
        print("-------------------------------")
        print("퍼센트 :: \(Float((self.main_webview?.estimatedProgress)!)*100)")
        print("====================================")
        print("")
        
        if Float((self.main_webview?.estimatedProgress)!) >= 1.0 { // 0.5 / 0.9 / 1.0
            
            //DispatchQueue.main.asyncAfter(deadline: .now() + 1.3) { // [특정 시간 이후 수행]
            DispatchQueue.main.async { // [즉시 수행]
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> observeValue() :: 인트로 화면 닫기 수행 실시]")
                print("-------------------------------")
                print("퍼센트 :: \(Float((self.main_webview?.estimatedProgress)!)*100)")
                print("====================================")
                print("")
                
                // -----------------------------------------
                // [SEARCH FAST] : [인트로 화면 처리]
                self.main_webview?.isHidden = false // [웹뷰 활성]
                self.introBg.isHidden = true // [로딩 이미지 비활성]
                // -----------------------------------------
                
                
                // -----------------------------------------
                // [쿠키매니저에 저장된 쿠키 확인]
                if self.main_webview != nil {
                    if #available(iOS 11.0, *) {
                        self.main_webview!.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
                            // for cookie in cookies { }
                            print("")
                            print("====================================")
                            print("[\(self.ACTIVITY_NAME) >> observeValue() :: 자바스크립트에 저장된 [개별] 쿠키값 확인 실시]")
                            print("-------------------------------")
                            //print("key :: \(cookie.name)")
                            //print("value :: \(cookie.value)")
                            print("쿠키 개수 :: ", cookies.count)
                            print("-------------------------------")
                            print("쿠키 정보 :: ", cookies)
                            print("====================================")
                            print("")
                        }
                    }
                    else {
                        print("")
                        print("====================================")
                        print("[\(self.ACTIVITY_NAME) >> observeValue() :: 자바스크립트에 저장된 [개별] 쿠키값 확인 실시]")
                        print("-------------------------------")
                        print("error [에러] :: iOS 11.0 미만 디바이스")
                        print("====================================")
                        print("")
                    }
                }
                // -----------------------------------------
            }
        }
    }
    
    
    
    
    
    // MARK: - [웹뷰 로드 수행 완료 부분]
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let _endUrl = String(describing: webView.url?.description ?? "")
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> didFinish() :: 웹뷰 로드 수행 완료]")
        print("-------------------------------")
        print("주 소 :: \(_endUrl)")
        print("====================================")
        print("")
        
        // -----------------------------------------
        // [퍼미션 상태 업데이트 체크 수행 실시]
        self.permissionState()
        // -----------------------------------------
    }

    
    
    
    
    // MARK: - [웹뷰 로드 수행 에러 확인]
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        // -----------------------------------------
        // [SEARCH FAST] : [웹뷰 에러 코드 감지]
        let _nsError = (error as NSError).code
        let _errorUrl = String(describing: webView.url?.description ?? "")
        // -----------------------------------------
        
        
        // -----------------------------------------
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> didFail() :: 웹뷰 로드 수행 에러]")
        print("-------------------------------")
        print("에러 주소 :: \(_errorUrl)")
        print("-------------------------------")
        print("에러 코드 :: \(_nsError)")
        print("-------------------------------")
        print("에러 메시지 :: \(S_WebViewErrorCode().checkError(_errorCode: _nsError))")
        print("====================================")
        print("")
        // -----------------------------------------
    }

    
    
    
    
    // MARK: - [웹뷰 실시간 url 변경 감지 실시]
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        // -----------------------------------------
        // [실시간 웹뷰 주소 변경 감지]
        let _shouldUrl = String(describing: webView.url?.description ?? "")
        var action: WKNavigationActionPolicy?
        defer {
            decisionHandler(action ?? .allow)
        }
        guard let url = navigationAction.request.url else { return }
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
        print("-------------------------------")
        print("주 소 :: \(url)")
        print("====================================")
        print("")
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [전화 이동 실시]
        if "\(url)".hasPrefix("tel:") {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
            print("-------------------------------")
            print("주 소 :: \(url)")
            print("-------------------------------")
            print("로 직 :: 전화 걸기 이동 실시")
            print("====================================")
            print("")
            
            self.goTelIntent(_url: "\(url)")
        }
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [이메일 이동 실시]
        if "\(url)".hasPrefix("mailto:") {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
            print("-------------------------------")
            print("주 소 :: \(url)")
            print("-------------------------------")
            print("로 직 :: 메일 보내기 이동 실시")
            print("====================================")
            print("")
            
            self.goMailIntent(_url: "\(url)")
        }
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [문자 이동 실시]
        if "\(url)".hasPrefix("sms:") {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
            print("-------------------------------")
            print("주 소 :: \(url)")
            print("-------------------------------")
            print("로 직 :: 문자 보내기 실시")
            print("====================================")
            print("")
            
            self.goSmsIntent(_url: "\(url)")
        }
        // -----------------------------------------
        
        
        // -----------------------------------------
        // [하이퍼링크 이동 실시]
        if "\(url)".hasPrefix("l:") {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
            print("-------------------------------")
            print("주 소 :: \(url)")
            print("-------------------------------")
            print("로 직 :: 하이퍼링크 이동 실시")
            print("====================================")
            print("")
            
            self.goLinkIntent(_url: "\(url)")
        }
        // -----------------------------------------
    }
    
    
    
    
    
    // MARK: - [웹뷰 실시간 url status 상태 코드 감지 실시]
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
                 decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        
        // -----------------------------------------
        // [SEARCH FAST] : [웹뷰 에러 코드 감지]
        // -----------------------------------------
        // [핸들러 처리 실시]
        defer {
            decisionHandler(.allow)
        }
        var _url = ""
        // -----------------------------------------
        if let url = navigationResponse.response.url {
            _url = url.description
        }
        else {
            _url = ""
        }
        // -----------------------------------------
        // [응답 상태 값 확인 실시]
        if let response = navigationResponse.response as? HTTPURLResponse {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> WKNavigationResponse() :: 웹뷰 실시간 url status 상태 코드 감지]")
            print("-------------------------------")
            print("주 소 :: \(_url)")
            print("-------------------------------")
            print("상태 코드 :: \(response.statusCode)")
            print("====================================")
            print("")
            
            
            // MARK: [에러 응답 코드 인 경우]
            ///*
            // -----------------------------------------
            if response.statusCode >= 400 {
                
                // [무한 루프 방지 위해 기존에 저장된 에러 값 체크 실시]
                let errorCheck = String(describing:S_Preference().getString(_sKey: S_FinalData.PRE_WEBVIEW_RELOAD))
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> WKNavigationResponse() :: 웹뷰 실시간 url status 상태 코드 감지]")
                print("-------------------------------")
                print("로 직 :: 에러 발생 로직 처리 실시")
                print("-------------------------------")
                print("[기존] 저장된 에러 발생 여부 :: \(errorCheck)")
                print("====================================")
                print("")
                
                // -----------------------------------------
                // MARK: [에러가 중복 실행된 경우 >> 에러 팝업창 표시]
                if errorCheck != nil
                    && errorCheck.count>0
                    && errorCheck.trim().equals(_string: "") == false
                    && errorCheck.trim().equals(_string: "1") == true { // MARK: [에러 팝업창]
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> WKNavigationResponse() :: 웹뷰 실시간 url status 상태 코드 감지]")
                    print("-------------------------------")
                    print("로 직 :: 재시도 최종 실패 >> [에러 팝업창] 웹뷰 로드 에러 표시 실시")
                    print("====================================")
                    print("")
                    
                    
                    // MARK: [실시간으로 웹뷰 에러가 발생한 경우 >> 에러 팝업창 표시]
                    // MARK: [사용자가 다시 접속 시 에러 발생한 경우 >> SceneDelegate >> sceneWillEnterForeground >> 앱 재기동]
                    
                    
                    // [에러 팝업창 표시]
                    ///*
                    self.showAlertWebview(
                        tittle:S_FinalData.AL_TITLE,
                        
                        content:"URL : " + "\(_url)" + "\n" + "\n" +
                                "Error : " + S_FinalData.ERROR_WEBVIEW_LOAD + "\n" + "\n" +
                                "HTTPURLResponse : " + "\(response.statusCode)" + "\n" + "\n" +
                                "TIME : " + String(describing: C_Util().getNowDateTime24()) + "",
                        
                        //_url:_url, // [에러 주소]
                        _url: S_FinalData.WV_LOAD_MAIN_ENZ_URL, // [메인 주소]
                        
                        okBtb:S_FinalData.AL_OK,
                        noBtn:""
                    )
                    // */
                }
                // -----------------------------------------
                // MARK: [처음으로 에러가 발생한 경우 >> 프리퍼런스 데이터 널 인 경우 :: 재시도 기회 제공]
                else {
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> WKNavigationResponse() :: 웹뷰 실시간 url status 상태 코드 감지]")
                    print("-------------------------------")
                    print("로 직 :: 에러 최초 발생 >> [재시도] 웹 페이지 다시 로드 수행 실시")
                    print("====================================")
                    print("")
                    
                    
                    // -----------------------------------------
                    // MARK: [웹뷰 재호출 프리퍼런스 값 지정 실시]
                    S_Preference().setString(_sKey: S_FinalData.PRE_WEBVIEW_RELOAD, _sValue: "1")
                    // -----------------------------------------
                    
                    
                    // -----------------------------------------
                    // [SEARCH FAST] : [웹뷰 세션 및 캐시 삭제 수행]
                    self.clearWebViewChahe()
                    // -----------------------------------------
                    
                    
                    // -----------------------------------------
                    // [웹뷰 객체 지우기 실시]
                    if self.main_webview != nil {
                        // [웹뷰 제거 실시]
                        self.main_webview?.removeFromSuperview()
                        self.main_webview = nil
                        
                        // [자바스크립트 통신 사용 초기화]
                        self.javascriptController = WKUserContentController()
                    }
                    // -----------------------------------------
                    
                    
                    // -----------------------------------------
                    // [SEARCH FAST] : [인트로 화면 처리]
                    self.introBg.isHidden = false // [로딩 이미지 활성]
                    // -----------------------------------------
                    
                    
                    // -----------------------------------------
                    // [SEARCH FAST] : [웹뷰 로드 수행 실시]
                    self.init_WebView(_loadUrl: S_FinalData.WV_LOAD_MAIN_ENZ_URL)
                    // -----------------------------------------
                }
            }
            // -----------------------------------------
            else { // MARK: [정상 응답 코드 인 경우]
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> WKNavigationResponse() :: 웹뷰 실시간 url status 상태 코드 감지]")
                print("-------------------------------")
                print("로 직 :: [정상] 웹뷰 이동 로직 처리 실시")
                print("====================================")
                print("")
                
                // MARK: [웹뷰 재호출 프리퍼런스 값 지정 실시]
                S_Preference().setString(_sKey: S_FinalData.PRE_WEBVIEW_RELOAD, _sValue: "")
            }
            // -----------------------------------------
        }
    }
    
    
    
    
    
    // MARK: - [웹뷰 모달창 닫힐때 앱 종료현상 방지]
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    
    
    
    
    // MARK: - [웹뷰 alert 팝업창 처리]
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
                 initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void){
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> runJavaScriptAlertPanelWithMessage() :: 웹뷰 alert 팝업창 처리]")
        print("-------------------------------")
        print("message :: \(message)")
        print("====================================")
        print("")
        
        // [팝업창 정의 실시]
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler() }))
        self.present(alertController, animated: true, completion: nil)
    }


    
    
    
    // MARK: - [웹뷰 confirm 팝업창 처리]
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> runJavaScriptConfirmPanelWithMessage() :: 웹뷰 confirm 팝업창 처리]")
        print("-------------------------------")
        print("message :: \(message)")
        print("====================================")
        print("")
        
        // [팝업창 정의 실시]
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in completionHandler(false) }))
        alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler(true) }))
        self.present(alertController, animated: true, completion: nil)
    }
    
    
    
    
    
    // MARK: [웹뷰 에러 발생 시 표시 팝업창]
    var webviewAlert : UIAlertController? = nil
    func showAlertWebview(tittle:String, content:String, _url:String, okBtb:String, noBtn:String) {
        // [메인 큐에서 비동기 방식 실행 : UI 동작 실시]
        DispatchQueue.main.async {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> showAlertWebview() :: 웹뷰 에러 발생 팝업창 표시 실시]")
            print("-------------------------------")
            print("제 목 :: \(tittle)")
            print("-------------------------------")
            print("내 용 :: \(content)")
            print("-------------------------------")
            print("주 소 :: \(_url)")
            print("====================================")
            print("")
            
            
            // [UIAlertController 객체 정의 실시]
            self.webviewAlert = UIAlertController(
                title: tittle + "\n",
                message: content + "\n",
                preferredStyle: UIAlertController.Style.alert
            )
            
            
            // [인풋으로 들어온 확인 버튼이 nil 아닌 경우]
            if(okBtb != "" && okBtb.count>0){
                let okAction = UIAlertAction(title: okBtb, style: .default) { (action) in
                    //----------------------------------
                    // MARK: [확인 버튼 클릭 이벤트 내용 정의 실시]
                    if self.main_webview != nil {
                        // ----------------------------------
                        // [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
                        S_Preference().webViewReloadClear()
                        // ----------------------------------
                        // [SEARCH FAST] : [웹뷰 세션 및 캐시 삭제 수행]
                        self.clearWebViewChahe()
                        // ----------------------------------
                        // [SEARCH FAST] : [인트로 화면 처리]
                        self.main_webview?.isHidden = true // [웹뷰 비활성]
                        self.introBg.isHidden = false // [로딩 이미지 활성]
                        // ----------------------------------
                        let url = URL (string: _url) // [웹뷰 로드 주소]
                        let request = URLRequest(url: url! as URL)
                        self.main_webview!.load(request)
                        // ----------------------------------
                    }
                    // ----------------------------------
                    // [팝업창 초기화 실시]
                    self.webviewAlert = nil
                    //----------------------------------
                    return
                    //----------------------------------
                }
                self.webviewAlert!.addAction(okAction) // 버튼 클릭 이벤트 객체 연결
            }
            
            
            // [인풋으로 들어온 취소 버튼이 nil 아닌 경우]
            if(noBtn != "" && noBtn.count>0){
                let noAction = UIAlertAction(title: noBtn, style: .default) { (action) in
                    // -----------------------------------------
                    // [취소 버튼 클릭 이벤트 내용 정의 실시]
                    // -----------------------------------------
                    // [팝업창 초기화 실시]
                    self.webviewAlert = nil
                    // -----------------------------------------
                    return
                    // -----------------------------------------
                }
                self.webviewAlert!.addAction(noAction) // 버튼 클릭 이벤트 객체 연결
            }
            
            
            // [alert 팝업창 활성 실시]
            self.present(self.webviewAlert!, animated: false, completion: nil)
        }
    }
    
    
    
    
    
    // MARK: - [웹뷰 쿠키 및 캐시 데이터 초기화 메소드]
    func clearWebViewChahe(){
        // -----------------------------------------
        // [SEARCH FAST] : [웹뷰 세션 및 캐시 삭제 수행]
        // -----------------------------------------
        
        
        // ---------------------------------------------
        if self.main_webview != nil { // [웹뷰가 널이 아닌 경우]
            // -----------------------------------------
            // [전체 방문 데이터 지우기]
            /*
            WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), completionHandler: {
                (records) -> Void in
                for record in records{
                    WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
                    print("")
                    print("====================================")
                    print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 전체 방문 데이터 삭제 수행]")
                    print("-------------------------------")
                    print("type :: removeData")
                    print("====================================")
                    print("")
                }
            })
            // */
            // -----------------------------------------
            
            
            // -----------------------------------------
            // [원하는 캐시 데이터만 골라서 삭제]
            ///*
            let websiteDataTypes = NSSet(array:
                                                [WKWebsiteDataTypeDiskCache, // 디스크 캐시
                                                 WKWebsiteDataTypeMemoryCache, // 메모리 캐시
                                                 WKWebsiteDataTypeCookies, // 웹 쿠키,
                                                 
                                                 WKWebsiteDataTypeOfflineWebApplicationCache, // 앱 캐시
                                                 WKWebsiteDataTypeWebSQLDatabases, // 웹 SQL 데이터 베이스
                                                 WKWebsiteDataTypeIndexedDBDatabases // 데이터 베이스 정보
                                                 
                                                 //WKWebsiteDataTypeLocalStorage // 로컬 스토리지
                                                 //WKWebsiteDataTypeSessionStorage // 세션 스토리지
                                                ])
            let date = NSDate(timeIntervalSince1970: 0)
            WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set, modifiedSince: date as Date, completionHandler:{
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 수행]")
                print("-------------------------------")
                print("type :: removeData")
                print("====================================")
                print("")
            })
            // */
            // -----------------------------------------
            
            
            // -----------------------------------------
            // [설치된 날짜 가져오는 코드]
            let urlToDocumentsFolder: URL? = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
            let installDate = try? FileManager.default.attributesOfItem(atPath: (urlToDocumentsFolder?.path)!)[.creationDate] as! Date
            
            // [설치된 날짜부터 지금까지의 cookie all clear]
            URLSession.shared.configuration.httpCookieStorage?.removeCookies(since: installDate!)
            
            // [로그 출력 실시]
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 수행]")
            print("-------------------------------")
            print("type :: URLSession removeCookies")
            print("====================================")
            print("")
            // -----------------------------------------
            
            
            // -----------------------------------------
            // [웹뷰에 저장된 쿠키 데이터 확인 실시]
            if #available(iOS 11.0, *) {
                self.main_webview!.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
                    if cookies.count>0 { // [저장된 쿠키가 있는 경우]
                        for cookie in cookies {
                            self.main_webview!.configuration.websiteDataStore.httpCookieStore.delete(cookie, completionHandler: {
                                print("")
                                print("====================================")
                                print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 수행]")
                                print("-------------------------------")
                                print("설 명 :: ", "자바스크립트에 저장된 [개별] 쿠키 값 제거 실시")
                                print("-------------------------------")
                                print("key :: \(cookie.name)")
                                print("-------------------------------")
                                print("value :: \(cookie.value)")
                                print("====================================")
                                print("")
                            })
                        }
                    }
                    else { // [저장된 쿠키가 없는 경우]
                        print("")
                        print("====================================")
                        print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 수행]")
                        print("-------------------------------")
                        print("결 과 :: 저장된 쿠키 없음")
                        print("====================================")
                        print("")
                    }
                }
            }
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 실패]")
                print("-------------------------------")
                print("error [에러] :: iOS 11.0 미만 디바이스")
                print("====================================")
                print("")
            }
            // -----------------------------------------
        }
        else {
            print("")
            print("====================================")
            print("[\(self.ACTIVITY_NAME) >> clearWebViewChahe() :: 웹뷰 쿠키 및 세션 데이터 삭제 실패]")
            print("-------------------------------")
            print("error [에러] :: main_webview 웹뷰 객체 널 (NULL) 임")
            print("====================================")
            print("")
        }
        // -----------------------------------------
    }
    
  
} // [클래스 종료]

 

반응형
Comments