web-dev-qa-db-fra.com

Comment ajouter des en-têtes HTTP dans la demande globale pour iOS dans swift

func webView(webView: WKWebView!, decidePolicyForNavigationAction navigationAction: WKNavigationAction!, decisionHandler: ((WKNavigationActionPolicy) -> Void)!) {
     var request = NSMutableURLRequest(URL: navigationAction.request.URL)
     request.setValue("value", forHTTPHeaderField: "key")
     decisionHandler(.Allow)
}

Dans le code ci-dessus, je souhaite ajouter un en-tête à la demande. J'ai essayé de faire navigationAction.request.setValue("IOS", forKey: "DEVICE_APP") mais ça ne marche pas.

aidez-moi de quelque manière que ce soit.

9
sandip

Malheureusement, vous ne pouvez pas faire cela avec WKWebView.

Cela ne fonctionne très certainement pas dans webView:decidePolicyForNavigationAction:decisionHandler: car le navigationAction.request est en lecture seule et une instance NSURLRequest non mutable que vous ne pouvez pas modifier.

Si je comprends bien, WKWebView s'exécute en sandbox dans un processus de contenu et de réseau distinct et, du moins sur iOS, il n'existe aucun moyen d'intercepter ou de modifier ses demandes réseau.

Vous pouvez le faire si vous revenez à UIWebView.

16
Stefan Arentz

Il existe de nombreuses façons de le faire. J'ai trouvé que la solution la plus simple consistait à sous-classer WKWebView et à remplacer la méthode loadRequest. Quelque chose comme ça:

class CustomWebView: WKWebView {
    override func loadRequest(request: NSURLRequest) -> WKNavigation? {
        guard let mutableRequest = request.mutableCopy() as? NSMutableURLRequest else {
            return super.loadRequest(request)
        }
        mutableRequest.setValue("custom value", forHTTPHeaderField: "custom field")
        return super.loadRequest(mutableRequest)
    }
}

Ensuite, utilisez simplement la classe CustomWebView comme s'il s'agissait d'un WKWebView.

EDIT NOTE : Ceci ne fonctionnera que sur la première requête, comme l'a souligné @Stefan Arentz.

NOTE: Certains champs ne peuvent pas être remplacés et ne seront pas modifiés. Je n'ai pas fait de test approfondi mais je sais que le champ User-Agent ne peut pas être remplacé à moins que vous ne fassiez un piratage spécifique ( vérifiez ici la réponse à cette question )

8
Gabriel Cartier

Avec certaines limitations, mais vous pouvez le faire. Intercepter la réponse dans la fonction déléguée webView:decidePolicyFornavigationResponse:decisionHandler:. Si les modifications apportées à l'URL, annulez-la en passant decisionHandler(.cancel) et rechargez la vue Web avec newURLRequest, qui définit les en-têtes personnalisés et l'URL interceptée. De cette manière, chaque fois qu'une URL change (par exemple, les utilisateurs tapent sur des liens), vous annulez cette demande et créez une nouvelle avec des en-têtes personnalisés.

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate  {
    var webView: WKWebView?
    var loadUrl = URL(string: "https://www.google.com/")!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: CGRect.zero)
        webView!.navigationDelegate = self
        view.addSubview(webView!)
        webView!.translatesAutoresizingMaskIntoConstraints = false
        webView!.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
        webView!.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        webView!.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        webView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true

        // Load first request with initial url
        loadWebPage(url: loadUrl)
    }

    func loadWebPage(url: URL)  {
        var customRequest = URLRequest(url: url)
        customRequest.setValue("some value", forHTTPHeaderField: "custom header key")
        webView!.load(customRequest)
    }

    // MARK: - WKNavigationDelegate

    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        guard let url = (navigationResponse.response as! HTTPURLResponse).url else {
            decisionHandler(.cancel)
            return
        }

        // If url changes, cancel current request which has no custom headers appended and load a new request with that url with custom headers
        if url != loadUrl {
            loadUrl = url
            decisionHandler(.cancel)
            loadWebPage(url: url)
        } else {
            decisionHandler(.allow)
        }
    }
}
2
Au Ris

J'ai modifié la réponse Au Ris pour utiliser NavigationAction au lieu de NavigationResponse, comme suggéré par jonny. En outre, cela corrige les situations où la même URL est appelée ultérieurement et vous n'avez plus à suivre l'URL actuelle. Cela ne fonctionne que pour les requêtes GET mais peut sûrement être adapté pour d'autres types de requête si nécessaire.

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate  {
    var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = WKWebView(frame: CGRect.zero)
        webView!.navigationDelegate = self
        view.addSubview(webView!)
        // [...] set constraints and stuff

        // Load first request with initial url
        loadWebPage(url: "https://my.url")
    }

    func loadWebPage(url: URL)  {
        var customRequest = URLRequest(url: url)
        customRequest.setValue("true", forHTTPHeaderField: "x-custom-header")
        webView!.load(customRequest)
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping
    (WKNavigationActionPolicy) -> Void) {
        if navigationAction.request.httpMethod != "GET" || navigationAction.request.value(forHTTPHeaderField: "x-custom-header") != nil {
            // not a GET or already a custom request - continue
            decisionHandler(.allow)
            return
        }
        decisionHandler(.cancel)
        loadWebPage(url: navigationAction.request.url!)
    }

}

0
Roben
private var urlrequestCurrent: URLRequest?

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    //print("WEB decidePolicyFor navigationAction: \(navigationAction)")
    if let currentrequest = self.urlrequestCurrent {
        //print("currentrequest: \(currentrequest), navigationAction.request: \(navigationAction.request)")
        if currentrequest == navigationAction.request {
            self.urlrequestCurrent = nil
            decisionHandler(.allow)
            return
        }
    }

    decisionHandler(.cancel)

    var customRequest = navigationAction.request
    customRequest.setValue("myvaluefffs", forHTTPHeaderField: "mykey")
    self.urlrequestCurrent = customRequest
    webView.load(customRequest)
}
0
Jonny