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é.
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)
})
}
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")
})
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
}