Intercept Request with Wkwebview

Intercept request with WKWebView

I see that after 5 years this question still generates curiosity, so I describe how I solved it and about some main problems I faced up.
As many who answered here, I have implemented WKURLSchemeHandler and used new schemes.

First of all the URL that wkwebview launches must not be HTTP (or HTTPS) but one of yours new schemes.

Example

mynewscheme://your-server-application.com

In you WKWebViewConfiguration conf, I set the handler:

[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewscheme"];
[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewschemesecure"];

In CustomSchemeHandler I have implemented webView:startURLSchemeTask: and webView:stopURLSchemeTask:.

In my case I check if the request is for a file that I just saved locally, otherwise I change actual protocol ("mynewscheme or "mynewschemesecure") with http (or https) and I make request by myself.

At this point I solved the "interception problem".

In this new way we have the webview "location" (location.href via javascript) with my new scheme and with it new problems started.

  • First problem is that my applications work mainly with javascript,
    and document.cookie has stopped working. I'm using Cordova
    framework, so I've develeped a plugin to set and get cookie to
    replace document.cookie (I had to do this, because, obviously, I
    have also http header set-cookie).

  • Second problem is that I've got a lot of "cross-origin" problems, then
    I changed all my urls in relative url (or with new schemes)

  • Third problem is that browser automatically handle server port 80
    and 443, omitting them, but has now stopped (maybe because of "not
    http location"). In my server code I had to handle this.

Writing down these few rows I admit that it seems to was an easy problem to solve, but I ensure that find out a workaround, how to solve it and integrate with the infinite amount of code has been hard. Every step towards the solution corresponded to a new problem.

How to intercept all http(s) requests on ios WKWebView?

Take a look at this github repository called as WKWebViewWithURLProtocol Casolorz. This library enables you to use NSURLProtocol to intercept your network requests using method swizzling.

Ios WKWebView intercepting http/https requests

Eventually I've ended up using. GCDWebServer

I've setup local webserver like so:

let webServer: GCDWebServer = GCDWebServer()

webServer.addGETHandler(forBasePath: "/", directoryPath: baseResourcePath, indexFilename: "index.html", cacheAge: 0, allowRangeRequests: true)

Then to provide files that are located outside of index.html contained directory
one has to attach custom get handler:

webServer.addHandler(forMethod: "GET", pathRegex: "images", request: GCDWebServerRequest.self) { request in
let fileName = request.path.components(separatedBy: "/images/")[1]
var documentsURL = FileManager.default.urls(for: .docmentDirectory, in: .userDomainMask)[0]
documentsURL.appendPathComponent("images/\(fileName)")
let response = GCDWebServerFileResponse(file: documentsURL.path)
return response
}

Intercept links in wkwebview

You can implement a Coordinator object and set it as your WKNavigationDelegate. Then you can implement decidePolicyFor navigationAction method and decide what to do on each request:



import SwiftUI
import WebKit

struct ContentView: View {
var body: some View {
WebView(request: .init(url: URL(string: "https://google.com")!))
}
}


struct WebView: UIViewRepresentable {
let request: URLRequest
func makeCoordinator() -> Coordinator { .init(self) }
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
webView.load(request)
}
class Coordinator: NSObject, WKNavigationDelegate {
var webView: WebView
init(_ webView: WebView) { self.webView = webView }
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
if let url = navigationAction.request.url,
let host = url.host, !host.hasPrefix("www.google.com"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
print(url)
print("Redirected to browser. No need to open it locally")
decisionHandler(.cancel)
} else {
print("Open it locally")
decisionHandler(.allow)
}
} else {
print("not a user click")
decisionHandler(.allow)
}
}
}
}


struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}



Related Topics



Leave a reply



Submit