Migrating from UIWebView to WKWebView - ios

I'm migrating from UIWebView to WKWebView, how can I rewrite these function for WKWebView?
func webViewDidStartLoad(webView: UIWebView){}
func webViewDidFinishLoad(webView: UIWebView){}
and
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
print("webview asking for permission to start loading")
if navigationType == .LinkActivated && !(request.URL?.absoluteString.hasPrefix("http://www.myWebSite.com/exemlpe"))!{
UIApplication.sharedApplication().openURL(request.URL!)
print(request.URL?.absoluteString)
return false
}
print(request.URL?.absoluteString)
lastUrl = (request.URL?.absoluteString)!
return true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {
print("webview did fail load with error: \(error)")
let testHTML = NSBundle.mainBundle().pathForResource("back-error-bottom", ofType: "jpg")
let baseUrl = NSURL(fileURLWithPath: testHTML!)
let htmlString:String! = "myErrorinHTML"
self.webView.loadHTMLString(htmlString, baseURL: baseUrl)
}

UIWebView => WKWebView Equivalent
UIWebViewDelegate => WKNavigationDelegate
delegate => navigationDelegate
didFailLoadWithError => didFailNavigation
webViewDidFinishLoad => didFinishNavigation
webViewDidStartLoad => didStartProvisionalNavigation
shouldStartLoadWithRequest => decidePolicyForNavigationAction
About shouldStartLoadWithRequest you can write:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
print("webView:\(webView) decidePolicyForNavigationAction:\(navigationAction) decisionHandler:\(decisionHandler)")
switch navigationAction.navigationType {
case .linkActivated:
if navigationAction.targetFrame == nil {
self.webView?.loadRequest(navigationAction.request)
}
if let url = navigationAction.request.url, !url.absoluteString.hasPrefix("http://www.myWebSite.com/example") {
UIApplication.shared.open(url)
print(url.absoluteString)
decisionHandler(.cancel)
return
}
default:
break
}
if let url = navigationAction.request.url {
print(url.absoluteString)
}
decisionHandler(.allow)
}
And for the didFailLoadWithError:
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("webView:\(webView) didFailNavigation:\(navigation) withError:\(error)")
let testHTML = Bundle.main.path(forResource: "back-error-bottom", ofType: "jpg")
let baseUrl = URL(fileURLWithPath: testHTML!)
let htmlString = "myErrorInHTML"
self.webView.loadHTMLString(htmlString, baseURL: baseUrl)
}

Here is the Objective-C methods for the migration:
shouldStartLoadWithRequest -> decidePolicyForNavigationAction
Remember to call the decisionHandler:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
}
NSString *url = [navigationAction.request.URL query];
decisionHandler(WKNavigationActionPolicyAllow);
}
webViewDidStartLoad -> didStartProvisionalNavigation
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}
webViewDidFinishLoad -> didFinishNavigation
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
}
didFailLoadWithError -> didFailNavigation
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
}

Migrating UIWebView to WKWebView, Swift 4:
Equivalent of shouldStartLoadWithRequest:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
var action: WKNavigationActionPolicy?
defer {
decisionHandler(action ?? .allow)
}
guard let url = navigationAction.request.url else { return }
print(url)
if navigationAction.navigationType == .linkActivated, url.absoluteString.hasPrefix("http://www.example.com/open-in-safari") {
action = .cancel // Stop in WebView
UIApplication.shared.openURL(url) // Open in Safari
}
}
Equivalent of webViewDidStartLoad:
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print(String(describing: webView.url))
}
Equivalent of didFailLoadWithError:
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
let nserror = error as NSError
if nserror.code != NSURLErrorCancelled {
webView.loadHTMLString("404 - Page Not Found", baseURL: URL(string: "http://www.example.com/"))
}
}
Equivalent of webViewDidFinishLoad:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print(String(describing: webView.url))
}

Related

How to get headers from WKWbView finish loads

I am using WKWebView in app & i am looking for getting all headers from wkwebview in finish loads method webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { Just like in UIWebView
func webViewDidFinishLoad(_ webView: UIWebView) {
print("Finished loads---", webView.request?.allHTTPHeaderFields)
}
How can we achieve that in WKWebView ?
You need to set your view controller as the WKWebView Navigation Delegate WKNavigationDelegate and implement its decidePolicyFor method:
optional func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
Try like this:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let allHTTPHeaderFields = navigationAction.request.allHTTPHeaderFields ?? [:]
for (key, value) in allHTTPHeaderFields {
print("key:", key, "value:", value)
}
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)
}
}
Use WKWebView's webView(_:decidePolicyFor:decisionHandler:).
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
// MARK: - IBOutlet
#IBOutlet weak var webView: WKWebView!
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let urlStr = "https://www.google.com/"
if let url = URL(string: urlStr) {
let request = URLRequest(url: url)
webView.load(request)
//webView.allowsBackForwardNavigationGestures = false
//webView.navigationDelegate = self
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let request = navigationAction.request
if let host = navigationAction.request.url?.host {
if host == "www.google.com" {
if let headers = request.allHTTPHeaderFields {
print("Google Headers: \(headers)")
} else {
print("Nope, sir")
}
}
else if host == "www.apple.com" {
if let headers = request.allHTTPHeaderFields {
print("Apple Headers: \(headers)")
} else {
print("Nope, sir")
}
}
}
decisionHandler(.allow)
}
}
And I get the following.
["User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X)
AppleWebKit/605.1.15 (KHTML, like Gecko)", "Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8"]
Headers: ["Accept-Language": "en-us", "Upgrade-Insecure-Requests":
"1", "Accept-Encoding": "gzip, deflate, br", "User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X)
AppleWebKit/605.1.15 (KHTML, like Gecko)", "Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8"]

switch view if the Webview can't loading the URL?

I have 2 views on my screen first is the Webview and the second is a static view "errorView" with the error message "set to hidden". I am trying to load the errorView if we have an error loading website to Webview.
#objc private func loadURL() {
guard let url = URL(string: "https://www.hackingwi") else {
self.errroLoadingWebView.isHidden = false
return
}
webView?.load(URLRequest(url: url))
webView?.allowsBackForwardNavigationGestures = true
}
You can use WKNavigationDelegate.
set delegate
webView.uiDelegate = self
webView.navigationDelegate = self
class StaticWebPageVC: WKNavigationDelegate, WKUIDelegate {
func webView(_: WKWebView, didFinish _: WKNavigation!) {
// Web view loaded
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
// Show error view
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
// Show error view
}
}

WKWebView how to find the request in the WKNavigationDelegate methods

I'm trying to migrate from a UIWebView to WKWebView. shouldStartLoadWithRequest delegate method I could find the request as below:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(#"request: %#", request);
if ([request.URL.host isEqualToString:#"jsbridge"])
{
NSString* requestType = [request.URL.pathComponents objectAtIndex:2];
NSString* key = [request.URL.pathComponents objectAtIndex:3];
NSLog(#"requestType: %# - key: %#", requestType, key);
if([requestType isEqualToString:#"audio"])
{
[self playAudio:key];
}
return YES;
}
I need help finding the same request in the WKNavigationDelegate methods. Do I use the didCommit or didFinishNavigation methods and if so how do I find the request that it came from? Could someone give me an example? Wish I could do this is Swift but I have to stick to Objective-C. Thanks in advance.
As I know the equivalent of webView:shouldStartLoadWithRequest:navigationType: in UIWebView is webView:decidePolicyForNavigationAction:decisionHandler: in WKWebView.
Inside webView:decidePolicyForNavigationAction:decisionHandler:, you can get the request from navigationAction.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
// Do whatever you want with the request
decisionHandler(WKNavigationActionPolicyAllow);
}
Equivalent for UIWebview to WKWebview is as follows:
didFailLoadWithError => didFailNavigation
webViewDidFinishLoad => didFinishNavigation
webViewDidStartLoad => didStartProvisionalNavigation
shouldStartLoadWithRequest => decidePolicyForNavigationAction
The shouldStartWithRequest delegate method in WKWebview (Swift version) is as follows:
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) {
if (webView.url?.host ?? "") == "jsbridge" {
let requestType = webView.url?.pathComponents[2]
let key = webView.url?.pathComponents[3]
print("requestType: \(requestType ?? "") - key: \(key ?? "")")
if (requestType == "audio") {
playAudio(key)
}
}
}
I created the custom class
class PKWebKitView: WKWebView,WKUIDelegate,WKNavigationDelegate {
var webView :WKWebView!
func loadRequestUrl(myRequest : URLRequest) {
self.navigationDelegate = self
self.uiDelegate = self
self.load(myRequest)
} }
extension PKWebKitView: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let host = navigationAction.request.url?.absoluteString.removingPercentEncoding {
if host.contains(<endpoint check>) {
if let delegateWrapper = wkWebviewDelegate {
decisionHandler(.cancel)
}
}
if host.contains(<endpoint check>) {
let responseString = host
let query = "<Your query>"
wkWebviewDelegate?.launchScreen(query)
}
}
To Use:
let webConfiguration = WKWebViewConfiguration()
webView = PKWebKitView(frame: webViewContainer.frame, configuration: webConfiguration)
webView.loadRequestUrl(myRequest

URL loading issue in WKWebView

I'm getting a URL from API, I'm passing that URL to my webview and trying to load that, but it isn't loading. I don't know why but it isn't working. Even it's not showing any error or crashes. It's so weird but I don't know what I'm missing in that all the code is written fine. This is my code:
self.loadWeb(webURL: newsUrl!)
func loadWeb(webURL: String) {
let url = URL(string: webURL)
MBProgressHUD.hide(for: self.view, animated: true)
webView.navigationDelegate = self
webView.uiDelegate = self
webView.load(URLRequest(url: url!))
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.frame.size.height = 1
webView.scrollView.isScrollEnabled = false
webView.frame.size = webView.scrollView.contentSize
self.bgViewHeight.constant = webView.frame.size.height
}
private func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
print(error.localizedDescription)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Start to load")
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
print("finish to load")
}
How i can load this?

Create a WKWebView in a UIView

I'm trying to add a WKWebView inside of a UIView ,
The code seems to work fine ( the page is loaded the bounds is good the delegate print the message with no error)
but the View (called ViewForStuffInWeb ) stay blank, nothing in it
can someone explain why ?
import UIKit
import WebKit
class ViewController: UIViewController ,WKNavigationDelegate {
#IBOutlet var ViewForStuffInWeb: UIView!
var webView = WKWebView()
let request = "https://www.google.fr"
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.automaticallyAdjustsScrollViewInsets = false
let config = WKWebViewConfiguration()
webView = WKWebView(frame: ViewForStuffInWeb.bounds ,configuration : config)
webView.navigationDelegate = self
ViewForStuffInWeb = webView
println("webview : frame :\(webView.frame) , bounds : \(webView.bounds)")
requesting(request)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func requesting (request :String) {
if let url = NSURL(string: request) {
webView.loadRequest(NSURLRequest(URL: url))
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
println("decide policy action")
decisionHandler(WKNavigationActionPolicy.Allow)
}
func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) {
println("decide policy response")
decisionHandler(WKNavigationResponsePolicy.Allow)
}
func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation!) {
println("commit navigation")
}
func webView(webView: WKWebView, didFailNavigation navigation: WKNavigation!, withError error: NSError) {
println("fail in didFailNavigation \(error)")
}
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
println("fail in didFailProvisionalNavigation \(error)")
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
println("finish navigation")
}
thanks for reading
You never add the WKWebView to the view hierarchy. In your viewDidAppear, which code should really move to viewDidLoad, you probably want to replace:
ViewForStuffInWeb = webView
with:
ViewForStuffInWeb.addSubview(webView)
Although it is unclear what ViewForStuffInWeb actually is. The above will only work if that view exists in your nib and if it is connected.

Resources