투케이2K

161. (ios/swift) 파일 매니저 (FileManager) , http 통신 사용해 웹뷰에서 파일 다운로드 수행 실시 본문

IOS

161. (ios/swift) 파일 매니저 (FileManager) , http 통신 사용해 웹뷰에서 파일 다운로드 수행 실시

투케이2K 2022. 7. 21. 15:29

[개발 환경 설정]

개발 툴 : XCODE

개발 언어 : SWIFT

 

[사전 설정]

 

[파일 다운로드 주소 감지 부분 : a 태그 href 감지]

    // 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("[A_Main >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
        print("_shouldUrl :: \(_shouldUrl)")
        print("requestUrl :: \(url)")
        print("===============================")
        print("")
        
        // -----------------------------------------
        // [SEARCH FAST] : [파일 다운로드 수행]
        if "\(url)".hasPrefix("f:") {
            
            // [주소에서 파일 확장자 확인]
            let fileUrl = "\(url)".subString(_start: 2, _end: "\(url)".count-1) // 주소
            let fileExtension = C_Util().urlFileExtensionName(string: fileUrl) // 확장자
            print("")
            print("===============================")
            print("[A_Main >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
            print("로 직 :: 파일 다운로드 로직 처리 실시")
            print("fileUrl :: \(fileUrl)")
            print("fileExtension :: \(fileExtension)")
            print("===============================")
            print("")
            
            
            // [파일 확장자 널 체크 수행]
            if C_Util().stringNotNull(str: fileExtension) == true { // [파일 확장자 널 아님]
                
                // [로딩 프로그레스 호출]
                self.progressStart(onView: self.view)
                
                // [파일 다운로드 및 저장 실시]
                C_Util().appDownloadFile(onView: self.view, fileUrl: fileUrl){(result, msg) in
                    print("")
                    print("===============================")
                    print("[A_Main >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
                    print("콜 백 :: 파일 다운로드 결과 확인")
                    print("result :: ", result)
                    print("msg :: ", msg)
                    print("===============================")
                    print("")
                    
                    // [로딩 프로그레스 종료]
                    self.progressStop()
                    
                    // [에러 메시지 분기 처리]
                    if result == true { // [정상]
                        self.showAlert(
                            type:0,
                            tittle: S_FinalData.AL_FILE,
                            content: S_FinalData.AL_DOWN_SUCCESS,
                            okBtb: S_FinalData.AL_OK,
                            noBtn: "")
                    }
                    else { // [실패]
                        self.showAlert(
                            type:0,
                            tittle: S_FinalData.AL_FILE,
                            content: S_FinalData.AL_DOWN_FAIL + " " + msg,
                            okBtb: S_FinalData.AL_OK,
                            noBtn: "")
                    }
                }
            }
            else { // [파일 확장자 널 데이터]
                print("")
                print("===============================")
                print("[A_Main >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
                print("로 직 :: 파일 다운로드 로직 처리 에러")
                print("error :: FILE EXTENSION IS NULL")
                print("===============================")
                print("")
                
                // [팝업창 알림]
            }
        }
        
        // -----------------------------------------

    }
 

[파일 다운로드 수행 부분]

    // MARK: - [비동기 http 파일 다운로드 수행 실시]
    func appDownloadFile(onView : UIView, fileUrl : String, completion: @escaping (Bool, String)->()) {
        
        /*
        // -----------------------------------------
        [appDownloadFile 메소드 설명]
        // -----------------------------------------
        1. 파일 다운로드 수행 실시 메소드 (아이폰 >> 파일 폴더 >> 나의 iPhone >> 애플리케이션 >> 저장)
        // -----------------------------------------
        2. 호출 방법 :
         C_Util().appDownloadFile(onView: self.view, fileUrl: "http://img.championat.com/news/big/l/c/ujejn-runi_1439911080563855663.jpg"){(result, msg) in
             print("")
             print("====================================")
             print("[A_Main >> decidePolicyFor() :: 웹뷰 실시간 url 변경 감지]")
             print("콜 백 :: 파일 다운로드 결과 확인")
             print("result :: ", result)
             print("msg :: ", msg)
             print("====================================")
             print("")
             
             // [에러 메시지 분기 처리]
             if result == true { // [정상]
             }
             else { // [실패]
             }
         }
        // -----------------------------------------
        3. 사전 설정 사항 :
         - 필요 info plist 설정
           [1] http 허용 : App Transport Security Settings >> Allow Arbitrary Loads >> YES
           [2] 아이폰 파일 접근 설정 : Supports opening documents in place : YES
           [3] 아이튠즈 공유 설정 : Application supports iTunes file sharing : YES
        // -----------------------------------------
        4. 로직 :
         - 인풋으로 들어온 파일 주소 널 체크 수행 실시
         - 현재 날짜 및 시간 확인 실시
         - 파일 확장자 확인 실시
         - 파일이 저장될 경로 설정 수행 실시
         - URLSession 사용해 비동기 http 요청 및 파일 다운로드 수행 및 저장 실시
         - 파일 저장 명칭은 현재 날짜 및 시간.확장자
        // -----------------------------------------
        5. 참고 : html a 태그 소스 코드
         <a href='f:http://img.championat.com/news/big/l/c/ujejn-runi_1439911080563855663.jpg' download="file"> 파일다운로드 </a>
        // -----------------------------------------
        */
        
        
        // [인풋 데이터 널 체크 수행 실시]
        if fileUrl != nil
            && fileUrl.count>0
            && fileUrl != ""
            && fileUrl != "null"
            && fileUrl.isEmpty == false
            && fileUrl.hasPrefix("http"){
            
            // [URL 타입 선언 확인 실시]
            guard let urlCheck = URL(string: fileUrl)
            else {
                print("")
                print("====================================")
                print("[C_Util >> appDownloadFile() :: URL 주소 파일 확장자 포함 확인 에러]")
                print("-------------------------------")
                print("error :: ", "URL 파싱 에러")
                print("====================================")
                print("")
                
                // [콜백 반환]
                completion(false, "[appDownloadFile] : url parsing error")
                return
            }
            
            
            // [현재 날짜 및 시간 확인 실시]
            let nowDate = Date() // 현재의 Date 날짜 및 시간
            let dateFormatter = DateFormatter() // Date 포맷 객체 선언
            dateFormatter.locale = Locale(identifier: "ko") // 한국 지정
            
            dateFormatter.dateFormat = "yyyyMMddkkmmss" // Date 포맷 타입 지정
            //dateFormatter.dateFormat = "kkmmss" // Date 포맷 타입 지정
            let date_string = dateFormatter.string(from: nowDate) // 포맷된 형식 문자열로 반환
            
            
            // [파일 확장자 및 이름 확인 실시]
            var fileExtension = String(describing: urlCheck.pathExtension) // [jpg]
            let fileOriginName = String(describing: urlCheck.lastPathComponent) // [file.jpg]
            
            
            // [파일 확장자명 종료 확인]
            if fileExtension != nil && fileExtension.count>0 && fileExtension != "" {
            }
            else {
                guard let lastEIndex = fileUrl.lastIndex(of: "/") else { fatalError() } // 마지막 / 문자 인덱스 위치
                let endIndex = fileUrl.index(fileUrl.startIndex, offsetBy: fileUrl.count-1)
                var files = String(fileUrl[lastEIndex...endIndex]) // 문자열 분리 실시
                files = files.replacingOccurrences(of: "/", with: "") // 불필요 문자 제거
                
                let arrays = files.components(separatedBy: ".")
                if arrays != nil && arrays.isEmpty == false && arrays.count>0 && arrays.count == 2 { // [. 기준으로 정상적으로 분리가 된 경우]
                    
                    // [변수에 삽입 실시]
                    fileExtension = arrays[1]
                }
            }
            
            
            // [최종 파일 명칭 확인 실시]
            if fileExtension != nil && fileExtension.count>0 && fileExtension != "" {
                
                // [현재 날짜 및 시간 + 파일 확장자 데이터 결합 실시]
                let fileName = date_string + "." + fileExtension
                
                
                // [파일이 저장될 경로 설정 실시]
                let fileManager = FileManager.default // 파일 매니저 선언
                let documentsUrl =  fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! // 기본 경로 확인
                let fileSavePath = documentsUrl.appendingPathComponent(fileName) // 실제 저장되는 경로
                
                
                // [http 비동기 방식을 사용해서 파일 다운로드 및 저장 수행 실시]
                var urlComponents = URLComponents(string: fileUrl)
                var requestURL = URLRequest(url: (urlComponents?.url)!)
                requestURL.httpMethod = "GET" // GET
                requestURL.addValue("application/x-www-form-urlencoded; charset=utf-8;", forHTTPHeaderField: "Content-Type") // GET
                print("")
                print("====================================")
                print("[C_Util >> appDownloadFile() :: http 통신 파일 다운로드 요청 실시]")
                print("-------------------------------")
                print("주 소 :: ", requestURL)
                print("-------------------------------")
                print("파일 저장 경로 :: ", fileSavePath)
                print("====================================")
                print("")
                
                
                // [http 요쳥을 위한 URLSessionDataTask 생성]
                let dataTask = URLSession.shared.dataTask(with: requestURL, completionHandler: { (data, response, error) in

                    // [error가 존재하면 종료]
                    guard error == nil else {
                        print("")
                        print("====================================")
                        print("[C_Util >> appDownloadFile() :: http 통신 파일 다운로드 요청 실패]")
                        print("-------------------------------")
                        print("주 소 :: ", requestURL)
                        print("-------------------------------")
                        print("fail :: ", error?.localizedDescription ?? "")
                        print("====================================")
                        print("")
                        
                        // [콜백 반환]
                        completion(false, error?.localizedDescription ?? "")
                        return
                    }

                    // [status 코드 체크 실시]
                    let successsRange = 200..<300
                    guard let statusCode = (response as? HTTPURLResponse)?.statusCode, successsRange.contains(statusCode)
                    else {
                        print("")
                        print("====================================")
                        print("[C_Util >> appDownloadFile() :: http 통신 파일 다운로드 요청 에러]")
                        print("-------------------------------")
                        print("주 소 :: ", requestURL)
                        print("-------------------------------")
                        print("error :: ", (response as? HTTPURLResponse)?.statusCode ?? 0)
                        print("-------------------------------")
                        print("msg :: ", (response as? HTTPURLResponse)?.description ?? "")
                        print("====================================")
                        print("")
                        
                        // [콜백 반환]
                        completion(false, (response as? HTTPURLResponse)?.description ?? "")
                        return
                    }

                    // [response 데이터 획득]
                    let resultCode = (response as? HTTPURLResponse)?.statusCode ?? 0
                    let resultLen = data! // 데이터 길이
                    print("")
                    print("====================================")
                    print("[C_Util >> appDownloadFile() :: http 통신 파일 다운로드 성공]")
                    print("-------------------------------")
                    print("주 소 :: ", requestURL)
                    print("-------------------------------")
                    print("resultCode :: ", resultCode)
                    print("-------------------------------")
                    print("resultLen :: ", resultLen)
                    print("====================================")
                    print("")
                    
                    // [파일 저장 수행 실시]
                    if let data = data {
                        
                        // [설정한 경로에 파일 저장]
                        if let _ = try? data.write(to: fileSavePath, options: Data.WritingOptions.atomic) {
                            print("")
                            print("====================================")
                            print("[C_Util >> appDownloadFile() :: http 통신 파일 저장 [성공]]")
                            print("-------------------------------")
                            print("파일 저장 경로 :: ", fileSavePath)
                            print("====================================")
                            print("")
                            
                            // [콜백 반환]
                            completion(true, "[appDownloadFile] : File Download Success")
                        }
                        else {
                            print("")
                            print("====================================")
                            print("[C_Util >> appDownloadFile() :: http 통신 파일 저장 [실패] [1]]")
                            print("-------------------------------")
                            print("파일 저장 경로 :: ", fileSavePath)
                            print("-------------------------------")
                            print("error :: ", "data write error")
                            print("====================================")
                            print("")
                            
                            // [콜백 반환]
                            completion(false, "[appDownloadFile] : data write error")
                        }
                    }
                    else {
                        print("")
                        print("====================================")
                        print("[C_Util >> appDownloadFile() :: http 통신 파일 저장 [실패] [2]]")
                        print("-------------------------------")
                        print("파일 저장 경로 :: ", fileSavePath)
                        print("-------------------------------")
                        print("error :: ", "data parsing error")
                        print("====================================")
                        print("")
                        
                        // [콜백 반환]
                        completion(false, "[appDownloadFile] : data parsing error")
                    }
                })

                // [network 통신 실행]
                dataTask.resume()
            }
            else {
                print("")
                print("====================================")
                print("[C_Util >> appDownloadFile() :: http 통신 파일 다운로드 요청 에러]")
                print("-------------------------------")
                print("error :: ", "file extension is null")
                print("====================================")
                print("")
                
                // [콜백 반환]
                completion(false, "[appDownloadFile] : file extension is null")
                return
            }
        }
        else {
            
            // [콜백 반환]
            completion(false, "[appDownloadFile] : Input data is null")
        }
    }
 

[결과 출력]

 

 

반응형
Comments