web-dev-qa-db-fra.com

iOS Comment ajouter un cookie à chaque demande UIWebView?

J'ai besoin d'ouvrir l'URL avec Angular dans UIWebView et j'ai besoin d'envoyer un cookie avec chaque demande UIWebView

Ce que j'ai essayé de faire:

J'ai essayé de vérifier si la requête contient un cookie. Si c'est le cas, UIWebView effectue la demande, sinon je crée la même demande mais avec un cookie et je l'exécute. Pour substituer des requêtes, j'ai utilisé la méthode UIWebViewDelegate 'func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool. Mais cela ne fonctionne pas comme prévu, certaines requêtes s’effectuent sans cookies.

Mon code:

final class FieldServiceViewController: UIViewController {

    private var webView = UIWebView()
    private var sessionID = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        _ = JSONAPI.getSessionID().subscribe(onNext: { [weak self] sessionID in
            self?.sessionID = sessionID
            self?.configureUI()
            let string = "https://someURL"
            let url = URL(string: string)
            let request = URLRequest(url: url!)
            self?.webView.loadRequest(request)
        })
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        webView.frame = view.bounds
    }

    private func configureUI() {
        webView.delegate = self
        view.addSubview(webView)
    }

    private func cookedRequest(from: URLRequest) -> URLRequest? {

        let cookiesKey = "Cookie"
        let headers = from.allHTTPHeaderFields ?? [:]
        if (headers.contains { $0.0 == cookiesKey }) {
            return nil
        }

        var request = from
        request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
        let cookiesToAdd = "SESSIONID=\(sessionID)"
        request.addValue(cookiesToAdd, forHTTPHeaderField: cookiesKey)
        return request
        }
    }

    extension FieldServiceViewController: UIWebViewDelegate {

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if let cooked = cookedRequest(from: request) {
            webView.loadRequest(cooked)
            return false
        }

        return true
    }
}

Comment ajouter un cookie à chaque demande UIWebView?

P.S. J'ai également enregistré le cookie dans HTTPCookieStorage, mais il semble qu'il n'y ait aucune connexion entre les demandes de UIWebView et le stockage partagé.

9
BadCodeDeveloper

Merci de votre aide. Le problème a été résolu en créant un cookie avec un domaine spécifique:

final class FieldServiceViewController: UIViewController, DLHasHomeTitleView {

    private let fieldServiceEndPoint = Bundle.main.object(forInfoDictionaryKey: "FIELD_SERVICE_ENDPOINT") as! String

    private var webView = UIWebView()
    private var sessionID = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        configureUI()

        _ = JSONAPI.getSessionID().subscribe(onNext: { [weak self] sessionID in
            guard let `self` = self else { return }

            self.sessionID = sessionID

            let urlString = "https://\(self.fieldServiceEndPoint)"
            let url = URL(string: urlString)
            let request = URLRequest(url: url!)

            let cookie = HTTPCookie(properties: [
                .name: "JSESSIONID",
                .value: sessionID,
                .path: "/",
                .domain: self.fieldServiceEndPoint])
            HTTPCookieStorage.shared.setCookie(cookie!)

            self.webView.loadRequest(request)
        })
    }
1
BadCodeDeveloper

Je préférerais (WKWebView } _ au lieu de UIWebView car UIWebView est obsolète

Nous allons maintenant ajouter l’identifiant de session à chaque requête de votre Angular projet.

Au lieu d’ajouter l’identifiant de session en créant une nouvelle requête à partir de la méthode déléguée, je vous recommande d’ajouter un niveau request interceptor at Angular pour vous permettre de mieux contrôler chaque requête de votre Angular projet. 

Enregistrer l'intercepteur via une fabrique anonymous

$httpProvider.interceptors.Push(function($q, dependency1, dependency2) {
  return {
   'request': function(config) {
       config.headers['SESSIONID'] = 'Your Session id here';
    },

    'response': function(response) {

    }
  };
});

Maintenant, comment vous pouvez utiliser cela.

Vous pouvez convertir le code ci-dessus en Swift String. Lorsque vous avez votre identifiant de session et le Angular Project est chargé, vous pouvez l'exécuter à l'aide de la méthode evalujavaScript de wkwebview.

par exemple.

var sessionId = "you id"
        var s="\n" +
        " $httpProvider.interceptors.Push(function($q, dependency1, dependency2) {\n" +
        " return {\n" +
        " \'request\': function(config) {\n" +
        " config.headers[\'SESSIONID\'] = \'\(sessionId)\';\n" +
        " },\n" +
        " \n" +
        " \'response\': function(response) {\n" +
        " \n" +
        " }\n" +
        " };\n" +
        " });"

        webView.evaluateJavaScript(s, completionHandler: {(message,error) in
            print(error ?? "No Error")
        })
4
Sahil Manchanda

Vous pouvez changer votre code en ceci:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    if request.allHTTPHeaderFields?["SESSIONID"] == nil {
       var request: URLRequest = request
       request.allHTTPHeaderFields?["SESSIONID"] = "your_session_id"
       webView.loadRequest(request)
       return false
    }
    return true
}

METTRE À JOUR

Comme je le vois, le meilleur moyen de résoudre votre problème consiste à intercepter vos demandes avec URLProtocol. Créez la classe suivante:

class MyURLProtocol: URLProtocol, NSURLConnectionDelegate, NSURLConnectionDataDelegate {

    static let protocolKey = "MyURLProtocolKey"

    private var connection: NSURLConnection?

    override class func canInit(with request: URLRequest) -> Bool {
        if let isCustom = URLProtocol.property(forKey: MyURLProtocol.protocolKey, in: request) as? Bool{
            return false
        }
        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        //You can add headers here
        var request = request
        print("request: \(request.url?.absoluteString ?? " ")")
        request.allHTTPHeaderFields?["SESSION_ID"] = "your_session_id"
        return request
    }

    override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
        return super.requestIsCacheEquivalent(a, to: b)
    }

    override func startLoading() {
        let newRequest: NSMutableURLRequest = self.request as! NSMutableURLRequest
        URLProtocol.setProperty(true, forKey: MyURLProtocol.protocolKey, in: newRequest)
        self.connection = NSURLConnection(request: newRequest as URLRequest, delegate: self, startImmediately: true)
    }

    override func stopLoading() {
        self.connection?.cancel()
        self.connection = nil
    }

    //MARK: NSURLConnectionDataDelegate methods
    func connection(_ connection: NSURLConnection, didReceive response: URLResponse) {
        self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
    }

    func connection(_ connection: NSURLConnection, didReceive data: Data) {
         self.client?.urlProtocol(self, didLoad: data as Data)
    }

    func connectionDidFinishLoading(_ connection: NSURLConnection) {
        self.client?.urlProtocolDidFinishLoading(self)
    }

    func connection(_ connection: NSURLConnection, didFailWithError error: Error) {
        self.client?.urlProtocol(self, didFailWithError: error)
    }
}

Maintenant dans votre AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    URLProtocol.registerClass(MyURLProtocol.self)
    return true
}
3
Taras Chernyshenko