From 439d2cf2aca80eaa6b1722b917903a724df26208 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Tue, 17 May 2022 11:38:45 +0900 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E4=BB=98=E3=83=95=E3=82=A1=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E8=A1=A8=E7=A4=BA=E4=BF=AE=E6=AD=A3=EF=BC=88PDF?= =?UTF-8?q?=E3=83=BB=E7=94=BB=E5=83=8F=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebView/View/SubView/SubViewStack.swift | 6 + .../WebView/View/WebViewController.storyboard | 4 +- .../WebView/View/WebViewController.swift | 138 +++++++++++++++++- 3 files changed, 141 insertions(+), 7 deletions(-) diff --git a/AgileWorks/AgileWorks/WebView/View/SubView/SubViewStack.swift b/AgileWorks/AgileWorks/WebView/View/SubView/SubViewStack.swift index 2329a0d..ab641f1 100644 --- a/AgileWorks/AgileWorks/WebView/View/SubView/SubViewStack.swift +++ b/AgileWorks/AgileWorks/WebView/View/SubView/SubViewStack.swift @@ -23,6 +23,8 @@ class SubViewStack: NSObject { } func push(_ webView: WKWebView, superView: UIView) { + // 回転時リサイズ設定 + webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] webViews.append(webView) webView.uiDelegate = self webView.allowsBackForwardNavigationGestures = true @@ -30,6 +32,7 @@ class SubViewStack: NSObject { let swipeRightGesture: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(self.handleRight(sender:))) swipeRightGesture.numberOfTouchesRequired = 1 swipeRightGesture.direction = .right + swipeRightGesture.delegate = self webView.addGestureRecognizer(swipeRightGesture) superView.addSubview(webView) } @@ -77,4 +80,7 @@ extension SubViewStack: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return true } + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } } diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.storyboard b/AgileWorks/AgileWorks/WebView/View/WebViewController.storyboard index ea412d4..bca840b 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.storyboard +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.storyboard @@ -20,7 +20,7 @@ - + diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift index bae50ca..3299374 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift @@ -18,6 +18,7 @@ class WebViewController: UIViewController { @IBOutlet private var closeButton: UIBarButtonItem! @IBOutlet private var menuButton: UIBarButtonItem! var mainWebView: WKWebView! + var subWebView: WKWebView! // 別ウインドウで開いたときの子ウインドウスタック var subViewStack = SubViewStack() var loadURL: String! @@ -95,7 +96,7 @@ class WebViewController: UIViewController { let configuration = WKWebViewConfiguration() configuration.userContentController = userContentController configuration.applicationNameForUserAgent = kCustomUserAgent - mainWebView = WKWebView(frame: self.formView.frame, configuration: configuration) + mainWebView = WKWebView(frame: self.formView.bounds, configuration: configuration) // スクロール設定 mainWebView.scrollView.bounces = true @@ -418,10 +419,11 @@ extension WebViewController: WKUIDelegate { func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { if navigationAction.targetFrame?.isMainFrame != true { - let webView = WKWebView(frame: self.formView.frame, configuration: configuration) - webView.load(navigationAction.request) - subViewStack.push(webView, superView: view) - return webView + subWebView = WKWebView(frame: self.formView.bounds, configuration: configuration) + subWebView.navigationDelegate = self + subViewStack.push(subWebView, superView: mainWebView) + subWebView.load(navigationAction.request) + return subWebView } return nil } @@ -438,6 +440,132 @@ extension WebViewController: WKUIDelegate { } extension WebViewController: WKNavigationDelegate { + func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { + if let attachmentFileName = attachmentFileName(ofResponce: navigationResponse), + let url = navigationResponse.response.url { + download(url: url, saveAs: attachmentFileName) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } + + private func attachmentFileName(ofResponce navigationResponse: WKNavigationResponse) -> String? { + guard let response = navigationResponse.response as? HTTPURLResponse, + let contentDisposition = response.allHeaderFields["Content-Disposition"] as? String + else { return nil } + print(response.allHeaderFields) + if let (fileNameStar: fileNameStar, fileName: fileName) = getAttachmentFileName(contentDisposition: contentDisposition) { + if let name = fileNameStar, let decoded = parseFilenameStar(name) { + return decoded + } else if let name = fileName { + return parseFilename(name) + } + } + return nil + } + + private func getAttachmentFileName(contentDisposition: String) -> (fileNameStar: String?, fileName: String?)? { + var isAttachment = false + var fileNameStar: String? + var fileName: String? + for keyValue in contentDisposition.split(separator: ";") { + let keyValuePair = keyValue.split(separator: "=", maxSplits: 2) + let key = keyValuePair[0].trimmingCharacters(in: .whitespaces) + switch key { + case "attachment": + isAttachment = true + + case "filename*": + if keyValuePair.count >= 2 { + fileNameStar = keyValuePair[1].trimmingCharacters(in: .whitespaces) + } + + case "filename": + if keyValuePair.count >= 2 { + fileName = keyValuePair[1].trimmingCharacters(in: .whitespaces) + } + + default: + break + } + } + if isAttachment { + return (fileNameStar: fileNameStar, fileName: fileName) + } else { + return nil + } + } + + private func parseFilenameStar(_ encoded: String) -> String? { + // RFC 5987 のパターン (ややルーズ) + guard let pattern = try? NSRegularExpression(pattern: "^([^']+)'([^']*)'(.*)$", options: []) else { return nil } + let results = pattern.matches(in: encoded, options: [], range: NSRange(0.. Substring { + let first = str.index(str.startIndex, offsetBy: nsRange.location) + let last = str.index(first, offsetBy: nsRange.length) + return str[first.. String { + // 非標準だが "" で囲まれているパターンもある + if (str.count >= 2) && str.hasPrefix("\"") && str.hasSuffix("\"") { + let first = str.index(after: str.startIndex) + let last = str.index(before: str.endIndex) + return String(str[first.. URLRequest { + var request = URLRequest(url: url) + let formHost = KeychainDataStore().readServerURL()! + // WebView と同じセッションでダウンロードできるように Cookie 設定。 + // 他サイトへのアクセス時に Cookie を漏らさないよう、ホスト名とパスを確認しておく。 + if (url.host == formHost) && url.path.starts(with: "/AgileWorks/Broker/") { + request.setValue("JSESSIONID=\(KeychainDataStore().readSessionID()!)", forHTTPHeaderField: "Cookie") + } + return request + } } extension WebViewController: SubViewStackEventDelegate { -- GitLab