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,
anddocument.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
How Do Set a Width and Height of an Image in Swift
Collectionview with the Horizontal Scroll with Mulitple Section
How to Write Application Logs to File and Get Them
iOS Input Focused Inside Fixed Parent Stops Position Update of Fixed Elements
"Can't Find Model for Source Store" Occurring During iPhone "Automatic Lightweight Migration"
Object-C/iOS :How to Use Asynchronous to Get a Data from Url
Latitude and Longitude Points from Mkpolyline
Where to Highlight Uicollectionviewcell: Delegate or Cell
Swift - Must Call a Designated Initializer of the Superclass Skspritenode Error
How to Determine If the Sim/Phone Number Has Changed
Is There Any Limitation to Distribution of Apps in iOS Enterprise Program
Uirefreshcontrol Stuck After Switching Tabs in Uitabbarcontroller
Generating Custom Thumbnail from Alassetrepresentation
Storyboard Instantiateviewcontrollerwithidentifier Not Setting Iboutlets