WKWebview loaded page does not interact properly - swift

I am trying to view the website https://www.methodenguide.de/basic inside a WKWebView. The website itself loads, but it doesn't behave as it should or as it does in Safari:
The boxes on the homepage don't show images
Links don't load targetet urls (didFinish navigation method says page is loaded instantly, but in fact nothing seems to happen)
Navigation menu is not shown properly (compared to Safari view).
The website works perfectly in Safari on the iPhone, so there seems to be a problem with the WKWebView, but I have no clue where to look ...
Any help is appreciated, as I'm fairly new to iOS / Swift development!
Thanks in advance, everybody :)
#IBOutlet weak var website: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
website.navigationDelegate = self
let request = URLRequest(url: URL(string: "https://www.methodenguide.de/basic")!)
website.load(request)
website.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
website.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: .new, context: nil)
}
func webView(_ website: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
{
print("Began loading page")
}
func webView(_ website: WKWebView,
didFinish navigation: WKNavigation!)
{
print("Finished loading page")
}

The answer lies in the info.plist. You need to enable http (not secure) connections as the images are loaded via ajax or the certificate is not secure.
App Transport Security Settings:
Allow Arbitrary Loads in Web Content
Allow Arbitrary Loads
Set both to YES.

Related

WKWebView Navigation Delegate Not Called

I am having difficulty getting a WKWebview to call its delegate methods, namely the did finish one.
I am attempting something similar to this post generating a pdf report using html loaded into a WKWebView;
WKWebView not calling navigation delegate methods
However trying the suggestion there, that doesn't work for me. I have a WKWebView made in a separate class to the View controller that will be calling its methods.
If I strip things right down and just try to simply load a website in the WebView to see if the delegate functions get called I get nothing.
Here is my test class;
import UIKit
import WebKit
class TestWebview: NSObject {
let webView = WKWebView ()
func loadWebsite () {
print ("LOAD TEST CALLED")
webView.navigationDelegate = self
let link = URL(string: "https://www.apple.com")!
let request = URLRequest(url: link)
webView.load(request)
}
}
extension TestWebview: WKNavigationDelegate {
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
print ("DID COMMIT")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print ("FINISHED LOADING")
}
}
And here is how I am calling it in a separate view controller;
override func viewDidLoad() {
super.viewDidLoad()
let test = TestWebview ()
test.loadWebsite()
}
Although if I put a WKWebView as an outlet into a view controller using Storyboards then the delegate methods do get called. I am trying to avoid this however as I don't want to see a web view in the view controller and want to keep all the code for that separate in another class.
Am I missing something? Checking various other posts on Stack Overflow about this hasn't given me any solutions other than making sure the navigation delegate is being set, which I am. Any help would be greatly appreciated.
You need to move let test = TestWebview () to class level, otherwise this object is going to be evicted when viewDidLoad completes: the navigationDelegate is defined as weak, so it's not going to prevent it either.

Assistance with Swift 5 WebKit and opening TEL and EMAIL links from HTML in ViewController

Thank you for your assistance in advance. I am hopeless stuck.
Issue: I am running 11.3.1 XCode and Swift 5. I have created general WKWebViews for four ViewControllers on a tabbed app. They are purely serving HTML. I cannot program a swift button from HTML obviously.
On Controller WebKit pages:
import UIKit
import WebKit
class SecondViewController: UIViewController {
#IBOutlet var webViewTwo: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://berksstorage.com/beekeeper/login.html")
webViewTwo.load(URLRequest(url: url!))
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
webView: all Data detectors are selected:
WebView Data Selectors
`
Summary: No matter what I do, not all links open. Why? All of my button links are HTTPS.
iOS13 just completely disregards the HTML a. button links as nothing. I know the button a. links are structured properly. I am not sure why swift will not open TEL and EMAIL button links?
Can someone explain to me why iOS13 will NOT open any TEL and EMAIL links inside the Webview? I can only assume there is a restriction somewhere. Please help!
This is definitely solvable. First though, let's dispel the notion that you cannot program a button from HTML. If you're serving the HTML within a WKWebView, then you can capture for the click links when they occur. Here's how:
1) Create a class object that conforms to WKNavigationDelegate
2) Within that class, implement func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) which is a delegate prescribed function.
3) Implement as follows:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == WKNavigationType.linkActivated {
// Here you can examine properties of the link through the navigationAction object
let request = navigationAction.request
let urlString = request.url.absoluteURL.lowercased()
if urlString.hasPrefix("tel") {
//You can construct a url to then open
let phoneUrl = // construct here
UIApplication.shared.open(phoneUrl)
decisionHandler(WKNavigationActionPolicy.cancel)
return
} else if urlString.contains("mailto:") {
let mailUrl = // construct here
UIApplication.shared.open(mailUrl)
decisionHandler(WKNavigationActionPolicy.cancel)
return
}
}
print("not captured, continuing execution")
decisionHandler(WKNavigationActionPolicy.allow)
}
4) You need to set the delegate for your WKWebView:
yourWkWebView.navigationDelegate = theObjectThatConformsToTheDelegateInStep3
Final Thoughts:
If you need to start the email construction process, here are some guidelines:
Open = message://
Start draft with recipient = mailto://TheirEmailAddress
Start draft with recipient, cc = mailto:TheirEmailAddress?cc=TheirEmailAddress
Start draft with recipient, bcc = mailto:TheirEmailAddress?bcc=TheirEmailAddress
Start draft with recipient, subject = mailto:TheirEmailAddress&subject=Your%20Subject%20Text
Start draft with recipient, body = mailto:TheirEmailAddress&body=Your%20Body%20Text
Start draft with recipient, CC, BCC, subject, body = mailto:TheirEmailAddress?cc=TheirEmailAddress?bcc=TheirEmailAddress&subject=Your%20Subject%20Text&body=Your%20Body%20Text
If you need to open the phone app, you should be able to pass the link itself. iOS is looking for something that starts with tel:// or telprompt://
This site does a good job keeping up-to-date with the URL schemes that Apple uses:
https://ios.gadgethacks.com/news/always-updated-list-ios-app-url-scheme-names-0184033/

Check if UIWebView is done loading in Swift

I am making an application that loads a UIWeb View and runs a line of code the moment the webpage is completely loaded.
I am using code like this to load the webpage:
let links = URL (string: "https://example.com")
let loadpage = URLRequest(url: links!)
webPage.loadRequest(load)
How can I run a piece of code the moment the webpage is done? I have tried some examples online but the webpage stops loading while checking if it has loaded?
Thanks!
As stated in the documentation of UIWebView, for apps targeting iOS8 or later you should be using WKWebView instead.
When using a WKWebView, you can make your class conform to WKNavigationDelegate and the delegate method func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) will be called once the webview finishes loading a network request.
If for some reason you are still targeting iOS7 or any previous iOS versions and hence the use of a UIWebView, you can use UIWebViewDelegate's func webViewDidFinishLoad(_ webView: UIWebView) method instead.
Skeleton code for the UIWebView solution:
class WebVC: UIViewController {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
webView.delegate = self
let url = URL(string: "https://example.com")
let request = URLRequest(url: url)
webView.loadRequest(request)
}
}
extension WebVC: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
print("Finished loading")
}
}

Swift 3 - Check if WKWebView has loaded page

My question:
How do I check if a page in WKWebView has fully loaded in Xcode using Swift 3?
This is my problem:
Webpage 1:
From this page I load Webpage 2
Webpage 2:
I need to get html data from Webpage 2, but when I print the HTML data I get HTML data of webpage 1, which I don't want. But when I print HTML data 2 seconds later it gives me the right HTML data.
I need to know whether or not a page in WKWebView did finish loading. I can see in the WebView it is loaded and also the progressbar is fully loaded, but when I print html data of the page I get html data of previous page, which is not what I want. Only if I wait a second it gives the right data, probably cause Webpage 2 is loaded.
So how do I let Xcode to print html when the next page is totally loaded?
I have tried several methods:
detect WKWebView finish loading
Call JavaScript function from native code in WKWebView
Maybe I can use:
if webView.isloading { get }
but I don't know how to implement this method and if it should work.
I have tried several methods from Stack but these are not working for me or outdated.
Do you guys know a solution for this problem in Swift 3?
Thanks!
Answer (Big thanks to #paulvs )
To check if your WKWebView has loaded easily implement the following method:
import WebKit
import UIKit
class ViewController: UIViewController, WKNavigationDelegate {
let webView = WKWebView()
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
print("loaded")
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.yourwebsite.com/") !
let request = URLRequest(url: url)
webView.navigationDelegate = self
webView.load(request)
// Do any additional setup after loading the view, typically from a nib.
}
}
Add WKNavigationDelegate to class
Add:
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) { print("loaded") }
Result: It will print "loaded" in the console everytime the WKWebView has finished loading the page. This was excactly what I was looking for, so again a big thanks to Paulvs!
Set delegate > WKNavigationDelegate
Objective-C
// Start loading WKWebView
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
NSLog(#"Start loading");
}
//Finished loading WKWebView
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
NSLog(#"End loading");
}
Swift 4.2
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
print("Start loading")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("End loading")
}

How can I check If the valid page was loaded in the WKWebView?

That's what I'm doing:
Loading the page in WKWebView
Pressing the button on the page
As a result I can get either valid URL, either invalid URL. How do I check if I've got the valid one? I need something like URLThatWasLoadedInWKWebView == "myValidURL"?
var webView: WKWebView!
var webUrl="google.com"
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: webUrl)!
let urlRequest = URLRequest(url: url)
webView.load(urlRequest)
view.insertSubview(webView, at: 0)
}
After I clicked on the button, I need to check that the page has loaded the valid "mail.google.com"
If you have your view controller conform to the WKNavigationDelegate then you can use those delegate functions to get the information you're looking for.
Inside this delegate function:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
You could check the webView.url which shows you the url that the web view just loaded. You could use that to check against whatever url you are trying to check against.