web-dev-qa-db-fra.com

Comment récupérer un fichier à l'aide de WKWebView?

Il y a un fichier (CSV) que je souhaite télécharger. C'est derrière un écran de connexion sur un site Web. Je voulais afficher un WKWebView pour permettre à l'utilisateur de se connecter, puis de demander à l'application de télécharger le fichier après s'être connecté.

J'ai essayé de télécharger le fichier en dehors de WKWebView après que l'utilisateur s'est connecté au site Web, mais les données de session semblent être mises en sandbox car elles téléchargent un document html avec le formulaire de connexion au lieu du fichier souhaité.

J'ai également essayé d'ajouter un WKUserScript à l'objet WKUserContentController, mais le script ne s'exécute pas lorsqu'un fichier non HTML est chargé.

Existe-t-il un moyen pour moi d'accéder à ce fichier tout en permettant aux utilisateurs de se connecter via WKWebView?

35
Devin McKaskle

À l'heure actuelle, les instances WKWebView ignoreront les stockages réseau par défaut (NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) ainsi que les classes de réseau standard que vous pouvez utiliser pour personnaliser les demandes réseau (NSURLProtocol, etc.).

Ainsi, les cookies de l'instance WKWebView ne sont pas stockés dans le stockage de cookies standard de votre application, et donc NSURLSession/NSURLConnection qui utilise uniquement le stockage de cookies standard n'a pas accès aux cookies de WKWebView (et c'est exactement le problème que vous avez probablement: le "statut de connexion" est probablement stocké dans un cookie, mais NSURLSession/NSURLConnection ne verra pas le cookie).

Il en va de même pour le cache, pour les informations d'identification, etc. WKWebView a ses propres stockages privés et ne fonctionne donc pas bien avec les classes de mise en réseau Cocoa standard.

Vous ne pouvez pas non plus personnaliser les demandes (ajouter vos propres en-têtes HTTP personnalisés, modifier les en-têtes existants, etc.), utiliser vos propres schémas d'URL personnalisés, etc., car NSURLProtocol n'est pas non plus pris en charge par WKWebView.

Donc, pour le moment, WKWebView est assez inutile pour de nombreuses applications, car il ne participe pas aux API de mise en réseau standard de Cocoa.

J'espère toujours que Apple changera cela jusqu'à la sortie d'iOS 8, car sinon WKWebView sera inutile pour de nombreuses applications, et nous resterons probablement avec UIWebView un peu plus longtemps.

Envoyez donc des rapports de bogues à Apple, donc Apple apprend que ces problèmes sont sérieux et doivent être corrigés.

95
Alex

Avez-vous vérifié les cookies de réponse revenant de la demande. Vous pouvez utiliser une méthode déléguée comme celle-ci.

- (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);
}
15
Nick Anger

Vous pouvez obtenir le cookie via Javascript :

Vous pouvez ensuite utiliser le cookie obtenu pour télécharger le fichier manuellement:

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()
})
1
Pieter Meiresone

J'ai accompli quelque chose de similaire à ce que vous essayez de faire:

  • utilisez la vue Web pour vous connecter comme vous le faites déjà
  • définissez un navigationDelegate sur votre vue Web
  • mettre en place -webView:decidePolicyForNavigationResponse:decisionHandler dans votre délégué
  • lorsque cette méthode déléguée est appelée (après la connexion de l'utilisateur), vous pouvez inspecter navigationResponse.response (le convertir en NSHTTPURLResponse*) et recherchez un Set-Cookie en-tête contenant les informations de session dont vous aurez besoin pour les sessions authentifiées.
  • vous pouvez ensuite télécharger le CSV en spécifiant manuellement l'en-tête Cookie dans votre demande avec les cookies spécifiés dans la réponse.

Notez que les méthodes déléguées sont uniquement appelées pour les requêtes "trame principale". Ce qui signifie que AJAX les requêtes ou les cadres internes ne le déclencheront pas. La page entière doit être actualisée pour que cela fonctionne.

Si vous devez déclencher un comportement pour les requêtes AJAX, iframes, etc., vous devrez injecter du javascript.

1
Sebastien Martin

Je ne semble pas avoir le cookie de session lorsque j'essaie une demande de userContentController didReceiveScriptMessage.

Cependant, lorsqu'il est appelé à partir de decidePolicyForNavigationAction, le code suivant détecte que je suis connecté.

     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()
0
moonhead