ダウンロードしたいファイル(CSV)があります。 Webサイトのログイン画面の背後にあります。ユーザーがログインできるようにWKWebView
を表示し、ログイン後にアプリにファイルをダウンロードさせたいと思いました。
ユーザーがWebサイトにログインした後にWKWebView
の外部にファイルをダウンロードしようとしましたが、目的のファイルの代わりにログインフォームでhtmlドキュメントをダウンロードするため、セッションデータはサンドボックス化されているようです。
WKUserScript
をWKUserContentController
オブジェクトに追加しようとしましたが、HTML以外のファイルがロードされたときにスクリプトが実行されません。
ユーザーがWKWebView
経由でログインできるようにして、このファイルにアクセスする方法はありますか?
現在、WKWebViewインスタンスは、デフォルトのネットワークストレージ(NSURLCache、NSHTTPCookieStorage、NSCredentialStorage)、およびネットワーク要求のカスタマイズに使用できる標準のネットワーククラス(NSURLProtocolなど)を無視します。
したがって、WKWebViewインスタンスのCookieはアプリの標準のCookieストレージに保存されないため、標準のCookieストレージのみを使用するNSURLSession/NSURLConnectionはWKWebViewのCookieにアクセスできません(これはおそらくあなたが抱えている問題です: 「ログインステータス」はほとんどの場合Cookieに保存されますが、NSURLSession/NSURLConnectionはCookieを認識しません。
キャッシュ、クレデンシャルなどの場合も同様です。WKWebViewには独自のプライベートストレージがあり、したがって標準のCocoaネットワーククラスではうまく機能しません。
NSURLProtocolもWKWebViewでサポートされていないため、リクエストをカスタマイズ(独自のカスタムHTTPヘッダーの追加、既存のヘッダーの変更など)、独自のカスタムURLスキームの使用などもできません。
したがって、WKWebViewはCocoaの標準のネットワークAPIに参加していないため、多くのアプリにとってはほとんど役に立たないのです。
私はまだAppleがiOS 8がリリースされるまでこれを変更することを望んでいます。
バグレポートをAppleに送信します。したがって、Appleはこれらの問題が深刻であり、修正が必要であることを認識します。
リクエストから返されるレスポンスCookieを確認しましたか。このようなデリゲートメソッドを使用できます。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
decisionHandler(WKNavigationResponsePolicyAllow);
}
Cookieを取得できます Javascript経由 :
次に、取得したCookieを使用して、ファイルを手動でダウンロードできます。
webView.evaluateJavaScript("(function() { return document.cookie })()", completionHandler: { (response, error) -> Void in
let cookie = response as! String
let request = NSMutableURLRequest(URL: docURL)
request.setValue(cookie, forHTTPHeaderField: "Cookie")
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
// Your CSV file will be in the response object
}).resume()
})
あなたがやろうとしていることに似た何かを達成しました:
navigationDelegate
を設定します-webView:decidePolicyForNavigationResponse:decisionHandler
を実装しますnavigationResponse.response
(NSHTTPURLResponse*
にキャスト)を調べて、セッション情報を含むSet-Cookie
ヘッダーを検索できます。認証済みセッションが必要です。Cookie
ヘッダーをレスポンスで指定されたCookieで手動で指定することにより、CSVをダウンロードできます。デリゲートメソッドは、「メインフレーム」リクエストに対してのみ呼び出されることに注意してください。つまり、AJAXリクエストまたは内部フレームはそれをトリガーしません。これが機能するには、ページ全体を更新する必要があります。
AJAXリクエスト、iframeなどの動作をトリガーする必要がある場合は、JavaScriptを挿入する必要があります。
UserContentController didReceiveScriptMessageからリクエストをしようとすると、セッションCookieがないようです。
ただし、decidePolicyForNavigationActionから呼び出されると、次のコードはログインしていることを検出します。
let urlPath: String = "<api endpoint at url at which you are logged in>"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
let string1 = NSString(data: data, encoding: NSUTF8StringEncoding)
println(string1)
println(data)
if(error != nil) {
println("Error sending token to server")
// Print any error to the console
println(error.localizedDescription)
}
var err: NSError?
})
task.resume()