// // WebViewControllerSwift.swift // MCPlus // // Created by seo ha on 14/02/2019. // Copyright © 2019 KangSH. All rights reserved. // import Foundation import UIKit import WebKit class WebViewController: UIViewController { @IBOutlet weak var webView:WKWebView!{ didSet{ webView.uiDelegate = self webView.navigationDelegate = self webView.configuration.userContentController.add(self, name: "mCarePlus") webView.configuration.suppressesIncrementalRendering = false // 데이터를 모두 받아야만 화면이 보여지게 하는 옵션 var scriptContent = "var meta = document.createElement('meta');" scriptContent += "meta.name='viewport';" scriptContent += "meta.content='width=device-width';" scriptContent += "document.getElementsByTagName('head')[0].appendChild(meta);" webView.evaluateJavaScript(scriptContent, completionHandler: nil) webView.evaluateJavaScript("navigator.userAgent") { [weak webView](result, error) in if let userAgent = result as? String{ webView?.customUserAgent = userAgent.appending("/mCarePlus") } } guard let url = URL(string: urlString) else { return } let request = URLRequest(url: url) webView.load(request) webView.isUserInteractionEnabled = true webView.scrollView.bounces = false webView.scrollView.isScrollEnabled = true } } var rememberme:String? let urlString = "\(MCarePlusConstants.DOMAIN_NAME)\(MCarePlusConstants.APP_NAME)\(Constants.SERVICE_START_ADDR)" } extension WebViewController{ override func viewDidLoad() { super.viewDidLoad() self.navigationController?.navigationBar.isHidden = true // status bar 폰트 흰색으로, plist 파일에 View controller-based status bar appearance : NO를 추가해야함 self.setStatusBarBackgroundColor(color: .white) let targetName = Bundle.main.infoDictionary?["TargetName"] as? String ?? "" print("\n ####### target name:\(targetName) ####### \n") self.showStatusBarInfo() self.orderFileDelete() webView.frame = self.view.frame Notification.registerNotification(name: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: OperationQueue.main) { [weak self](notification) in self?.webView.evaluateJavaScript("window.activeObj.inputLoginLog('')", completionHandler: nil) let alert = UIAlertController(title: "", message: "개인정보보호를 준수해주세요. \n캡쳐행위는 모니터링 될 수 있습니다.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil)) self?.present(alert, animated: true, completion: nil) } } func showStatusBarInfo(){ let statusBar = UIApplication.shared.statusBarFrame print("Status Bar : \(statusBar)") } func orderFileDelete(){ let fileManager = FileManager.default let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask) let documentsURL = urls.first //원본파일 guard let origin = documentsURL?.appendingPathComponent("kunkuk") else{ return } //썸네일 guard let thumb = documentsURL?.appendingPathComponent("thumb") else{ return } //원본 하위 파일을 가져온다 do{ let files = try fileManager.contentsOfDirectory(at: origin, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) for file in files{ //이름 추출 let name = file.lastPathComponent //일시 추출 let date = String(name[7...14]) //현재날짜와 파일의 일시를 date형식으로 추출 let currentDate = Date() guard let fileDate = date.fromDate(format: "yyyyMMddhhmmss") else{ continue } //파일 날짜에 1month를 더한다 var dateComponents = DateComponents() dateComponents.month = 1 let calendar = Calendar.current guard let toMonth = calendar.date(byAdding: dateComponents, to: fileDate) else{ continue } //생성일이 한 달 된 파일일 경우 원본과 썸네일을 삭제한다 if toMonth < currentDate{ let originPath = origin.appendingPathComponent("/").appendingPathComponent(name) let thumbPath = thumb.appendingPathComponent("/").appendingPathComponent(name) do{ try fileManager.removeItem(at: originPath) try fileManager.removeItem(at: thumbPath) }catch{ print(error) continue } } } }catch{ print(error) return } } func degreesToRadians(_ x:Double) -> CGFloat { return CGFloat(M_PI * (x) / 180.0) } func setStatusBarBackgroundColor(color:UIColor){ guard let statusBarView = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView else { return } statusBarView.backgroundColor = color } func exitApp(){ exit(0) } func lockscreen(){ let lockOptionVC = LockOptionViewViewController() self.present(lockOptionVC, animated: true, completion: nil) } func makeUrlStringForPACS(queryDic:[String:Any]) -> String? { do{ let pacsObject = try JSONDecoder().decode(PACS.self, from: queryDic.json()) let urlString = "\(Constants.PACS_APP_SCHEME)//searchstudy?" var reduceArray = [String]() if let serverUrl = pacsObject.serverUrl{ reduceArray.append("serverurl=\(serverUrl)") } if let userId = pacsObject.userId{ reduceArray.append("&id=\(userId)") } if let userPw = pacsObject.userPw{ reduceArray.append("&pw=\(userPw)") } if let product = pacsObject.product{ reduceArray.append("&product=\(product)") } if let pId = pacsObject.pId{ reduceArray.append("&pid=\(pId)") } if let accno = pacsObject.accno{ reduceArray.append("&accno=\(accno)") } if let type = pacsObject.type{ reduceArray.append("&type=\(type)") } if let studyInstanceUid = pacsObject.studyInstanceUid{ reduceArray.append("&study_instance_uid=\(studyInstanceUid)") } return reduceArray.reduce(urlString, {"\($0)\($1)"}) }catch{ print(error) return nil } } } //MARK: - < toNative functions > extension WebViewController{ func callPacs(param:String){ print("tonative param=[\(param)]") var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } print("parameter dictionary is \(queryStringDictionary)") guard let pameteredURL = self.makeUrlStringForPACS(queryDic: queryStringDictionary)else{ return } print("url address to PACS =[\(pameteredURL)]") guard let url = URL(string: pameteredURL) else{ return } // PACS 앱 다운로드 사이트 유도 // iPhone 5 9.3.3(13G34) 테스트 완료 // iPhone 5s 10.2.0(14C92) 테스트 완료 if #available(iOS 10.0, *){ let options = [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false] // 유니버셜링크만 열도록 하는 옵션 UIApplication.shared.open(url, options: options) { [weak self](success) in if success{ print("true = \(success)") }else{ print("false = \(success)") guard let url = URL(string: Constants.PACS_APP_DOWNLOAD_ADDR) else { return } UIApplication.shared.open(url, options: options, completionHandler: { (success) in //앱 설치 유도 if success{ print("앱스토어로 제대로 보내줌.") }else{ self?.showAlert("", "인터넷연결을 확인하세요", "확인") } }) } } }else{ let PACSInstallYn = UIApplication.shared.canOpenURL(url) if PACSInstallYn{ UIApplication.shared.open(url) }else{ guard let url = URL(string: Constants.PACS_APP_DOWNLOAD_ADDR) else { return } UIApplication.shared.open(url) } } } func rotateScreen(param:String){ var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } print("parameter dictionary is \(queryStringDictionary)") let orientation = queryStringDictionary["orientation"] as? String ?? "" let screenRect = UIScreen.main.bounds let screenWidth = screenRect.size.width let screenHeight = screenRect.size.height // NSNumber * value; if orientation == "landscape"{ UIApplication.shared.statusBarOrientation = .landscapeRight UIApplication.shared.isStatusBarHidden = true let transform:CGAffineTransform = CGAffineTransform(rotationAngle: degreesToRadians(90)) self.view.transform = transform self.view.frame = CGRect(x: 0, y: 0, width: screenHeight, height: screenWidth) }else{ UIApplication.shared.statusBarOrientation = .portrait UIApplication.shared.isStatusBarHidden = false let transform:CGAffineTransform = CGAffineTransform(rotationAngle: degreesToRadians(0)) self.view.transform = transform self.view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight) } } // 팝업 브라우징 func popup(param:String){ var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "url=") queryStringDictionary["url"] = urlComponents[safe:1] ?? "" let storyboard = self.storyboard let VC = storyboard?.instantiateViewController(withIdentifier: "ExtraWebViewController") as! ExtraWebViewController if let url = queryStringDictionary["url"] as? String{ VC.url = url } self.present(VC, animated: true, completion: nil) } func getDeviceInfo(param:String){ var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } print("parameter dictionary is \(queryStringDictionary)") let dic = NSMutableDictionary() let uuid = UIDevice.current.identifierForVendor?.uuidString ?? "" let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" var sysinfo = utsname() uname(&sysinfo) // ignore return value let phoneKind = NSString(bytes: &sysinfo.machine, length: Int(_SYS_NAMELEN), encoding: String.Encoding.utf8.rawValue)! as String dic["deviceId"] = uuid dic["appVersion"] = version dic["appKind"] = "IOS" dic["phoneKind"] = phoneKind let callback = CallbackUtil() let callbackFunc = queryStringDictionary["callbackFn"] as? String ?? "" let callbackUrl = callback.callBackFunc(callbackFunc, withDic: dic) self.webView.evaluateJavaScript(callbackUrl, completionHandler: nil) } func readBarcode(param:String){ let storyboard = self.storyboard let VC = storyboard?.instantiateViewController(withIdentifier: "BarcodeViewController") as! BarcodeViewController //바코드 콜백 VC.callBack = { [weak self](barcode) in print("doCompletionHandler \(barcode)") var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } // print("parameter dictionary is\n\(queryStringDictionary)") // let dic = NSMutableDictionary() // if barcode == ""{ // dic["success"] = "fail" // dic["result"] = "barcode is null" // }else{ // dic["success"] = "true" // dic["result"] = barcode // } // let callback = CallbackUtil() let callbackFunc = queryStringDictionary["callbackFn"] as? String ?? "" // let callbackUrl = callback.callBackFunc(callbackFunc, withDic: NSMutableDictionary()) let callbackUrl = "\(callbackFunc)({\"success\":\"true\",\"result\":\"\(barcode)\"})" self?.webView?.evaluateJavaScript(callbackUrl, completionHandler: nil) } self.navigationController?.pushViewController(VC, animated: false) } func readQrcode(param:String){ let storyboard = self.storyboard let VC = storyboard?.instantiateViewController(withIdentifier: "BarcodeViewController") as! BarcodeViewController //qr코드 콜백 VC.callBack = { [weak self](qrcode) in print("doCompletionHandler \(qrcode)") var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } // print("parameter dictionary is\n\(queryStringDictionary)") // let dic = NSMutableDictionary() // if qrcode == ""{ // dic["success"] = "fail" // dic["result"] = "qrcode is null" // }else{ // dic["success"] = "true" // dic["result"] = qrcode // } // // let callback = CallbackUtil() let callbackFunc = queryStringDictionary["callbackFn"] as? String ?? "" // let callbackUrl = callback.callBackFunc(callbackFunc, withDic: dic) let callbackUrl = "\(callbackFunc)({\"success\":\"true\",\"result\":\"\(qrcode)\"})" self?.webView.evaluateJavaScript(callbackUrl, completionHandler: nil) } self.navigationController?.pushViewController(VC, animated: false) } func readPicture(param:String){ let storyboard = self.storyboard let VC = storyboard?.instantiateViewController(withIdentifier: "PictureViewController") as! PictureViewController let splited = param.split(separator: "&") var params = [String:String]() for p in splited{ let pair = p.split(separator: "=") let k = String(pair[safe:0] ?? "") let v = String(pair[safe:1] ?? "").removingPercentEncoding params[k] = v } let user = User.init() do{ user.hospitalCD = params["hospitalCD"] user.patientId = params["patientId"] user.userId = params["userId"] user.patientNm = params["patientNm"] user.age = params["age"] user.gender = params["gender"] user.deptCd = params["deptCd"] user.deptNm = params["deptNm"] user.doctorId = params["doctorId"] user.doctorNm = params["doctorNm"] user.treatCls = params["treatCls"] user.treatClsKr = params["treatClsKr"] user.serviceUrl = params["serviceUrl"] user.visitDt = params["visitDt"] } VC.user = user VC.callBack = { [weak self] (result) in var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } print("parameter dictionary is\n\(queryStringDictionary)") let dic = NSMutableDictionary() dic["success"] = "true" dic["result"] = result let callback = CallbackUtil() let callbackFunc = queryStringDictionary["callbackFn"] as? String ?? "" let callbackUrl = callback.callBackFunc(callbackFunc, withDic: dic) self?.webView.evaluateJavaScript(callbackUrl, completionHandler: nil) } self.navigationController?.pushViewController(VC, animated: false) } func showBrowsingUrl(param:String) { var queryStringDictionary = [String:Any]() let urlComponents = param.components(separatedBy: "&") for keyValuePair in urlComponents{ let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents[safe: 0]?.removingPercentEncoding ?? "" let value = pairComponents[safe: 1]?.removingPercentEncoding ?? "" queryStringDictionary[key] = value } guard let urlString = queryStringDictionary["url"] as? String, let url = URL(string: urlString) else { return } self.webView.load(URLRequest(url: url)) } } extension WebViewController:WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler{ func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void)) { let request = navigationAction.request print(request) guard let url = request.url else { return } let absoluteString = url.absoluteString switch absoluteString { case let variable where variable.hasPrefix("sms:"): fallthrough //메일 case let variable where variable.hasPrefix("mailto:"): fallthrough //전화 case let variable where variable.hasPrefix("tel:"): fallthrough //아이튠즈 case let variable where variable.hasPrefix("https://itunes.apple.com/"): fallthrough //스토리링크 case let variable where variable.hasPrefix("storylink://"): UIApplication.shared.open(url) decisionHandler(.cancel) //일반 웹호출 case let variable where variable.hasPrefix("http://"): fallthrough case let variable where variable.hasPrefix("https://"): decisionHandler(.allow) //url scheme은 중간에 대문자가 들어가도 소문자로 변환됨.. 근데 이게 안될때도 있고 그러하다. 따라서 웹에서는 계속 소문자로만 보내도록 약속. case let variable where variable.hasPrefix("tonative://"): let components = variable.components(separatedBy: "?") let functionName = components.first?[11...] ?? "" var parameters = components[safe: 1] ?? "" if components.count > 2{ var addParam = [String]() for i in 2.. Void) { if let urlResponse = navigationResponse.response as? HTTPURLResponse, let url = urlResponse.url, let allHeaderFields = urlResponse.allHeaderFields as? [String : String] { let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHeaderFields, for: url) HTTPCookieStorage.shared.setCookies(cookies , for: url, mainDocumentURL: nil) decisionHandler(.allow) } } func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { self.showAlert("", message, "확인", nil, { (action) in completionHandler() }) } func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { self.showAlert("", message, "확인", "취소", { (action) in completionHandler(true) },{ (action) in completionHandler(false) }) } func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { let alertController = UIAlertController(title: "", message: prompt, preferredStyle: .alert) alertController.addTextField { (textField) in textField.text = defaultText } alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in if let text = alertController.textFields?.first?.text { completionHandler(text) } else { completionHandler(defaultText) } })) alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in completionHandler(nil) })) self.present(alertController, animated: true, completion: nil) } func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { let userController = WKUserContentController() configuration.preferences.javaScriptCanOpenWindowsAutomatically = true configuration.userContentController = userController let newWebView:WKWebView = { let webView = WKWebView(frame: webView.frame, configuration: configuration) webView.uiDelegate = self webView.navigationDelegate = self webView.frame.origin.y = 0 webView.configuration.userContentController.add(self, name: "mCarePlus") webView.evaluateJavaScript("navigator.userAgent") { [weak webView](result, error) in if let userAgent = result as? String{ webView?.customUserAgent = userAgent.appending("/mCarePlus") } } return webView }() let button:UIButton = { let button = UIButton(type: .system) button.isHidden = true button.frame = CGRect(x:(webView.frame.size.width) - 30, y:0, width: 30, height: 30) button.backgroundColor = UIColor.black button.layer.cornerRadius = 15 button.setTitle("X", for: .normal) button.addTapGestureRecognizer(action: deleteSubWebView) return button }() webView.addSubview(newWebView) webView.addSubview(button) return newWebView } func deleteSubWebView(){ for view in webView.subviews{ view.removeFromSuperview() } } func webViewDidClose(_ webView: WKWebView) { for view in webView.subviews{ view.removeFromSuperview() } webView.removeFromSuperview() } public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { // 중복적으로 리로드가 일어나지 않도록 처리 필요. webView.reload() } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { } }