How to make a webview NOT clickable in Swift iOS - ios

I want to implement a webview in Swift for an iOS application where I just want to display the content of a given website. The implementation below works but I have 2 requirements that I don't know how to implement:
I want the user not to be able to interact with the page displayed in any way. So if for example there is a link, the user cannot click on that. Same goes for any other element of the page, like images, etc. Is there a way to do so? In practice, the website content would need to be served as if it was a picture of the content, without the possibility to interact with individual elements of the page.
I want that the address of the website is never visible to the user. In my implementation below, that seems to be the case, but I am not sure if that would work in any condition and if there is a safer way to ensure that the web address is never displayed to the user (even when for example iOS informs the user that there was an issue loading the page, etc).
What I have in ViewController.swift is below:
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: "my-website-here")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
}

After the closing bracket of the func override func viewDidLoad() try implementing this
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(.cancel)
}
also just under webView.load(URLRequest(url: url))
add
navigationController?.isToolbarHidden = true
navigationController?.isNavigationBarHidden = true

Related

Instance member 'webView' cannot be used on type 'MyWebView(UIview)'

I am creating one SDK to get the url from user and load. So ai m creating my own class with WKWebview. But i am getting few issues about Instance member 'webView' cannot be used on type 'MyWebView(UIview)'
Code :
import Foundation
import WebKit
public class MyWebView: UIView, WKNavigationDelegate {
// initialize the view
var webView: WKWebView!
// load the view
private func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
}
// get the url and load the page
public static func loadUrl(Url: String) {
MyWebView.webView.load(URLRequest(url: URL(string: Url)!))
}
}
In my loadUrl, what ever user sending i need to use that url and load the url. Same in my view controller will look like :
import UIKit
class ViewController: UIViewController {
var webView: MyWebView!
override func loadView() {
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Any help would be great.
Your loadUrl function should not be static, since it needs access to an instance property, webView. Making the function non-static solves the issue.
Also a couple of minor improvements: don't force unwrap the URL init, since with an incorrect input that will crash. Use optional binding to safely unwrap it instead. I'd also suggest renaming the input argument label on loadUrl, since there's no point in having to right out loadUrl(Url:) every time you call the func, loadUrl( reads more naturally.
public func loadUrl(_ urlString: String) {
guard let url = URL(string: urlString) else { return }
webView.load(URLRequest(url: url))
}

Swift webview PROXY

With the code below I create a webview navigating to a URL. It works perfectly. But I need this navigation to be through an HTTP proxy.
How do I put proxy in a webview?
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView()
webView.navigationDelegate = self
view = webView
let url = URL(string: "https://www.iphub.info")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
}
Unfortunately, there's no simple way to achieve that.
You may intercept deprecated UIWebView with custom NSURLProtocol subclass, which utilizes NSURLSession inside. You'd easily set HTTP proxy configuration to the connectionProxyDictionary property of the NSURLSessionConfigurtion. Here's the example. That would work, but you may see slightly worse performance than with WKWebView.
Alternatively, you may consider using NetworkExtension.framework, if the proxy server supports tunneling. Here's a sample project which utilizes Network Extension.

WKNavigationDelegate Crashing App on Assignment

I'm working on a simple web wrapper application for iOS, and I'm having some issues with WKWebView and WKNavigationDelegate. I want to use the didFinishNavigation function from WKNavigationDelegate, so I can grab information from the URL query on navigation (namely a session GUID). My program launches correctly and loads my webpage when I comment out the "webView.navigationDelegate = self" line, but when I include that, my app crashes immediately with the following errors:
" -[UIWebView setNavigationDelegate:]: unrecognized selector sent to instance
0x7f8251e058f0"
"*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UIWebView setNavigationDelegate:]: unrecognized selector sent to
instance 0x7f8251e058f0'"
I noticed that both of these error messages include "UIWebView," when I'm trying to use WKWebView, so I tried to use the "custom class" field on the webview from the identity inspector part of the storyboard, but when I try to run after that, I get "(lldb)." Any help/insight would be appreciated, I'm including my code below:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
webView.navigationDelegate = self
loadURL("http://mydomain/login.html")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func loadURL(targetURL: String){
if let url = NSURL(string: targetURL) {
let request = NSURLRequest(URL: url)
webView.loadRequest(request)
}
}
private func checkDomainGetSessionGUID(){
print ("we are here")
if let query = webView.URL?.query {
let queryArr = query.componentsSeparatedByString("&")
var parsedQuery : [String: String] = [:]
for field in queryArr {
let parts = field.componentsSeparatedByString("=")
parsedQuery.updateValue(parts[1], forKey: parts[0])
print ("key = \(parts[0]) and value = \(parts[1])")
}
}
else {
print ("didn't enter the if let")
}
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
print ("delegate")
checkDomainGetSessionGUID()
}
}
PROCEDURE 1:
Step-1: Check UIElements that you are using in Storyboard design. if you had used Web view instead of using **WebKit View this error might come.Check your IBOutlet connection.
Step-2: Check your IOS deployment target, It must be IOS 11 and above because of UIWebKit View was released in IOS 8 but it contains a bug that was fixed in IOS 11 only. So set your deployment target 11 and above.
Step-3: Check your info.plist property. The following property should add in the listApp Transport Security Settings -> Allow Arbitrary Loads -> YES
PROCEDURE 2:
If in case you want deployment target as IOS 10 or below IOS 11 means you can implement like this
Step-1: Create a new UIViewcontroller with its swift ViewController file. And add below-given code to run your URL:
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}}
I hope this might be helpful to you...
I was getting this error inside (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
I removed the line [super webView:webView didFinishNavigation:navigation]; and everything worked as I expected, I'm not sure if it's hacky though.

How to only display part of web page content (swift)

I am brand new to coding (no background in any programming language at all). I am trying to learn swift. I am wanting to create a simple weather app that displays weather information in text once the user enters a city. I am grabbing the content from weather-forecast.com. I have figured out how to load the web content, but I want to only display a snippet (one paragraph) of the content from the page, not the whole page. Can someone please show me how to do that?
{
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet weak var cityText: UITextField!
#IBOutlet weak var webContent: UIWebView!
#IBAction func GoButtonPressed(sender: AnyObject) {
let url = NSURL (string: "http://www.weather-forecast.com");
let requestObj = NSURLRequest(URL: url!);
webContent.loadRequest(requestObj);
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
}
Here is an example of simple view controller which loads only part of the website dribble.com. The controller has method to select the DOM element and only show that element. It is quite simple, yet powerful enough to show how you could work further on this.
import UIKit
import JavaScriptCore
import WebKit
class TestViewController: UIViewController {
private weak var webView: WKWebView!
private var userContentController: WKUserContentController!
override func viewDidLoad() {
super.viewDidLoad()
createViews()
loadPage("https://dribbble.com/", partialContentQuerySelector: ".dribbbles.group")
}
private func createViews() {
userContentController = WKUserContentController()
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(webView)
let views: [String: AnyObject] = ["webView": webView, "topLayoutGuide": topLayoutGuide]
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[topLayoutGuide][webView]|", options: .allZeros, metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[topLayoutGuide][webView]|", options: .allZeros, metrics: nil, views: views))
self.webView = webView
}
private func loadPage(urlString: String, partialContentQuerySelector selector: String) {
userContentController.removeAllUserScripts()
let userScript = WKUserScript(source: scriptWithDOMSelector(selector),
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
forMainFrameOnly: true)
userContentController.addUserScript(userScript)
let url = NSURL(string: urlString)!
webView.loadRequest(NSURLRequest(URL: url))
}
private func scriptWithDOMSelector(selector: String) -> String {
let script =
"var selectedElement = document.querySelector('\(selector)');" +
"document.body.innerHTML = selectedElement.innerHTML;"
return script
}
}
The view controller shown in the example above only loads photos, design section inside the dribble website.
You won't be able to do that easily - UIWebView doesn't have any API to expose the structure of the web page it is loading nor to control/permit partial loading of a page.
Perhaps you might be able to scrape the content of the page and then display it, but you would do this before loading it in the UIWebView, and after you've scraped it then a web view is probably not the best way to display it anyway.
Do some searching for html and web scraping to see what the term means.
Alternatively if you know the web page content structure, you can inject javascript into the page as UIWebView is loading it and that javascript would stop the other parts of the page from being displayed (but if weather-forecast.com change the structure of their html in the future your javascript would probably no longer work)
Either way, both seems a bit too complex for a beginner though unless perhaps you can pick things up quick and are competent but its a lot to learn.
Instead of getting data off a website you could install a weather API into your app. This would be quicker and probably easier as with most weather API's you could choose what information to display.
Some more information on how to install a weather API is to go to this website.
Hope I solved your problem, Toby

Determinate finish loading website in webView with Swift in Xcode

i'm trying to create a webapp with swift in xcode, this is my current code:
IBOutlet var webView: UIWebView!
var theBool: Bool = false
var myTimer = NSTimer()
#IBOutlet var progressBar: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://stackoverflow.com")
let request = NSURLRequest(URL: url)
webView.loadRequest(request)
}
I've a question, How i can determinate the finish loading of the page in webView?
Do you know a documentation that contains all the definitions of the WebView? I mean .. (start / end load, the current url, title page, etc ..)?
(Sorry for my English).
Through the UIWebView delegate call.
You need to set your webViews delegate to the current controller, and conform to the UIWebViewDelegate protocol. When the webView finished loading the page func webViewDidFinishLoad(_ webView: UIWebView) will get called.
For WKWebview there is also wknavigationdelegate didfinish, but not do the trick as the SO question WKWebView didn't finish loading, when didFinishNavigation is called - Bug in WKWebView? and this answer show.
I also found when the page to load is very complicate and dinamic, UIWebview's webViewDidFinishLoad(- webView: UIWebView) also not works.
And I think use native swift or objective-c to detect when the page is loaded is a bad choice. The more flexable and effective way is to use javascript to call the native swift code when page finishing loading. What's more this also work for a specific dom finishing loading event and very dynamic content.
For how to call swift from javascript refer to this post.
Here is a sample code for dynamic content with anjularjs.
js,
var homeApp = angular.module('home', ['ui.bootstrap', 'ngAnimate']);
homeApp
.directive("printerinfo",
function() {
return {
restrict: "E",
link: function() { //call navite swift when page finishing loading
try {
window.webkit.messageHandlers.testHandler.postMessage("Hello from JavaScript");
} catch(err) {
console.log('The native context does not exist yet');
}
},
templateUrl: "/static/tpls/cloud/app/printerinfo.php",
}
})
swift3,
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.name)
if(message.name == "testHandler") {
//webpage content loaded
print(Date())
print("javascript test call swift")
}
Here I use angularjs to check element ready, you can also refter how-to-call-a-function-after-a-div-is-ready or check-if-a-given-dom-element-is-ready or jquery-ready-equivalent-event-listener-on-elements for more.

Resources