I have opened WKWebView with "https://www.google.com" for example. Then I'd like to open new url request in the same web view with new link "https://www.youtube.com" for example. I've put listener function to detect for new url and called "webView.load(newURLRequest)". However, the web view is never get loaded with new url request. Can someone help me to suggest solutions please? Thank you very much in advance.
Here is the full codes.
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.hackingwithswift.com")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
func reloadWebView(newURLRequest: URLRequest) {
webView.load(newURLRequest)
}
}
Then, func reloadWebView(newURLRequest: URLRequest) { ... } will be called whenever I received new url request from push notification.
You can use NotificationCenter.
A notification dispatch mechanism that enables the broadcast of information to registered observers.
Register the notification in your web view viewcontroller
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshData), name: NSNotification.Name("refreshweb"), object: nil)
}
#objc func refreshData() {
let url = URL (string: "https://www.youtube.com")
let requestObj = URLRequest(url: url!)
webview.load(requestObj)
}
Post the notification whenever you open the notification. (It may be willPresent notification: UNNotification or didReceive response: UNNotificationResponse in your app delegate)
NotificationCenter.default.post(name: NSNotification.Name("refreshweb"), object: nil)
you can pass the received URL from the push notification in the object.
Related
I am very new to coding so any help would be appreciated.
I am attempting to gather some basic survey data about video conferencing technology I am testing at work and the paid solution I am using routes to an advertisement page after the survey is completed. Since I won't be able to re-launch the web url every time the survey is taken, I would like for the page to automatically redirect back to the initial URL page every 2 minutes. Below is my existing code.
Thanks.
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://Mysurveypage/1234")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
}
var timer = Timer.scheduledTimer(timeInterval: 120.0, target: self, selector: #selector(ViewController.toDoTask), userInfo: nil, repeats: true)
func toDoTask()
{
let url = URL(string: "https://Mysurveypage/1234")!
webView.load(URLRequest(url: url))
}
First time can call toDoTask() in viewDidLoad()
You can try this code:
import UIKit
import WebKit
class HomeViewController: UIViewController, WKNavigationDelegate{
var webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
view = webView
let url = URL(string: "https://Mysurveypage/1234")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
override func viewDidAppear(_ animated: Bool) {
//Uncomment the following line of code to reload the webview currently on top of navigation stack, or in plain words, current browser tab showing in mobile window, Comment the other timer code if you intend to do this
//Timer.scheduledTimer(timeInterval: 2 * 60, target: self, selector: #selector(reloadWebView), userInfo: nil, repeats: true)
// Following line of code reloads the initial url i.e. "https://Mysurveypage/1234"
Timer.scheduledTimer(timeInterval: 2 * 60, target: self, selector: #selector(redirectToInitialUrl), userInfo: nil, repeats: true)
}
#objc private func reloadWebView() {
webView.reload()
}
#objc private func redirectToInitialUrl() {
let url = URL(string: "https://Mysurveypage/1234")!
webView.load(URLRequest(url: url))
}
}
PS: Apple documentation says, here:
You should never call this method directly.
It's usual to do all one time functions/operations, that one wants to do in UIViewController's life-cycle, in viewDidLoad() method.
Thanks so much for the responses. So unfortunately I am so new to coding, I did not know where to enter Jagdeep's code, but copying naeemjawaid's code worked great. I did have to delete the word "Home" from the class ViewController line. After that, all works great. Thanks again for the assistance.
I just started developing with swift, so I am sorry if the question is basic/stupid.
I have the following setup, just a test
import WebKit
import UIKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://hackingswift.com")!
webView.load(URLRequest(url:url))
webView.allowsBackForwardNavigationGestures = true
}
}
Unfortunately the browser doesn't load. The simulator only shows an empty navigation bar.
Suggestions? I am following a tutorial on hackingswift, so it's supposed to work.
You have to add webView as a subview or make an IBOutlet using Interface builder.
Try this:
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView?
func loadView() {
webView = WKWebView()
webView?.navigationDelegate = self
self.view.addSubview(webView!)
}
override func viewDidLoad() {
super.viewDidLoad()
self.loadView()
let url = URL(string: "https://hackingswift.com")!
webView?.load(URLRequest(url:url))
webView?.allowsBackForwardNavigationGestures = true
}
}
If you want it a bit more simple (without nullable variable), for example:
class ViewController: UIViewController, WKNavigationDelegate {
var webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
self.view.addSubview(webView)
webView?.allowsBackForwardNavigationGestures = true
self.loadUrl("https://hackingswift.com")
}
func loadUrl(_ url: String) {
if let url = URL(string: url) {
webView.load(URLRequest(url:url))
}
}
}
EDIT: it looks like some websites to load, while others do not, even if they are secure. If I put apple.com in the example, it loads, but a few others do not
Your url should be started with http or https for the webView to load.
Another possible reason is that your url containing an invalid certificate. Add the delegate function below into your code. You have to let WKWebView to bypass the certificate checking. However, this code is never recommended to go into production. You should be careful about what website your webView should and will load.
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let cred = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, cred)
}
The problem is this line:
let url = URL(string: "https://hackingswift.com")!
There is no such URL on the Internet, so you're not actually going to see anything. (You won't see anything if you paste that URL into any browser.)
So change that line to this:
let url = URL(string: "https://www.hackingwithswift.com")!
Now run the app, and presto, you'll see the web site:
I'm messing around with pdfs at the moment. I'm attempting to load a PDF into the system and write out the same PDF to gain an understandings of the the whole procedure.
The problem I've got it is that I'm having to load the pdf from the web and because the WebViewUI.loadRequest is asynchronous, it isn't completed in time.
override func viewDidLoad() {
super.viewDidLoad()
let filePath = getDocumentsDirectory().stringByAppendingPathComponent("output.pdf")
let url : NSURL! = NSURL(string: "http://www.nhs.uk/NHSEngland/Healthcosts/Documents/2014/HC5(T)%20June%202014.pdf")
loadTemplate(url, completion: {(webView: UIWebView) -> Void in
print("callback started")
let pdf = self.toPDF(webView)
do {
pdf!.writeToFile(filePath, atomically: true)
} catch {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
print("callback started")
})
print("Finished viewDidLoad")
}
func loadTemplate(url: NSURL, completion: (webView: UIWebView) -> Void) {
print("Start loadTemplate")
// do some crunching to create the SketchAnimation instance...
let webView = UIWebView(frame: CGRectMake(20, 100, 300, 40))
webView.loadRequest(NSURLRequest(URL: url))
self.view.addSubview(webView)
// invoke the completion callback
completion(webView: webView)
print("finished loadTemplate")
}
How do I add a callback to the loadRequest instead of loadTemplate?
You don't, exactly. You'd set up your view controller to be the web view's delegate and implement the webViewDidFinishLoad method. In that method you'd check to make sure the load that finished is the one you were after, and if so, then you'd invoked the code you want to run when the load is complete.
Here is a basic example of how to set that up:
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView: UIWebView!
var url = NSURL(string: "http://google.com")
override func viewDidLoad() {
super.viewDidLoad()
//load initial URL
let req = NSURLRequest(URL : url!)
webView.delegate = self
webView.loadRequest(req)
}
func webViewDidStartLoad(webView : UIWebView) {
print("AA")
}
func webViewDidFinishLoad(webView : UIWebView) {
print("BB")
}
}
I use WKWebView and I want to be notified when website is fully loaded. The webView:didFinishNavigation method of WKNavigationDelegate is fired when document.readyState is either interactive or complete and I want to be sure that site was completely loaded. I came up with the solution which uses JavaScript injection. Here is my MWE:
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate {
var webView: WKWebView!
#IBOutlet weak var loadLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let contentController = WKUserContentController()
let scriptPath = NSBundle.mainBundle().pathForResource("script", ofType: "js")!
let scriptString = try! String(contentsOfFile: scriptPath)
let script = WKUserScript(source: scriptString, injectionTime: .AtDocumentStart, forMainFrameOnly: true)
contentController.addUserScript(script)
contentController.addScriptMessageHandler(self, name: "readyHandler")
let configuration = WKWebViewConfiguration()
configuration.userContentController = contentController
webView = WKWebView(frame: CGRect.zero, configuration: configuration)
webView.navigationDelegate = self
loadLabel.text = nil
}
#IBAction func loadWebsite() {
webView.loadRequest(NSURLRequest(URL: NSURL(string: "http://stackoverflow.com")!))
loadLabel.text = "Loading..."
}
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
print("message received")
loadLabel.text = "Complete"
}
}
And this is the content of script.js file:
document.onreadystatechange = function () {
if(document.readyState === "complete"){
webkit.messageHandlers.readyHandler.postMessage("");
}
}
userContentController:didReceiveScriptMessage method is always called on iOS Simulator, but on the actual device (iPhone 6 in my case) it isn't called most of the times. Any idea what can be wrong about it or what's the other way of checking if website is completely loaded?
For some reason you need to add the webView to a visible view for this to work on the device. If you don't want the webView to be visible, add it and then set the hidden property to true.
For the code example above:
func viewDidLoad(){
...
webView.hidden = true
view.addSubview(webView)
}
I created a class that implements NSURLProtocol which will tells me about the UIWebView requests. I am looking to tell the UI that we hit a URL of interest and run code back on the ViewController to access the WebView.
I believe Protocols are the solution but cant seem to wrap my head around how to get this to work. Any suggestions and code example would be much appreciated. Here is what I've tried so far.
UI View Controller.swift
class WebViewController: UIViewController,WebAuthDelegate {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://example.com")
let request = NSURLRequest(URL: url!)
webView.loadRequest(request)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func onBackClick(sender: AnyObject) {
if(webView.canGoBack){
webView.goBack()
}
}
#IBAction func onFwdClick(sender: AnyObject) {
if(webView.canGoForward){
webView.goForward()
}
}
#IBAction func onRefresh(sender: AnyObject) {
webView.reload()
}
func getUserToken() {
print("RUN THIS AFTER I HIT URL IN URL PROTOCAL CLASS")
}
}
Here is my NSURLProtocol implemented class along with the attempted protocol(which please tell me if its the wrong approach)
class CUrlProtocol: NSURLProtocol {
//let delegate: WebAuthDelegate? = nil
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
print("URL = \(request.URL!.absoluteString)")
if request.URL!.absoluteString == "http://api-dev.site.com/token" {
//Tell the UI That we now have the info and we can access the UIWebView Object
}
return false
}
}
protocol WebAuthDelegate{
func getUserToken()
}
The best way to achieve this would probably be to post an NSNotification from your protocol when you match the URL.
In CUrlProtocol, when you find a match (notification name can be your choosing):
let notification:NSNotification = NSNotification(name: "MyURLMatchedNotification", object: nil)
NSNotificationCenter.defaultCenter().postNotification(notification)
In your WebViewController:
// During init (or viewDidAppear, if you only want to do it while its on screen)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getUserToken", name: "MyURLMatchedNotification", object: nil)
...
// During dealloc (or viewWillDisappear)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "MyURLMatchedNotification", object: nil)
You can also pass something with your notification, if you need information from that request. Just set the object parameter when you create your notification and change your getUserToken to accept a single parameter that has a type of NSNotification and access its object property.