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

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

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: How do unit test UIWebView loading?

My app has a basic webview controller to perform some operations. This view in the storyboard is not much besides a wrapper around a UIWebView. The controller itself has various public functions that can be called to load pages in the webview, like so:
class WebViewController: UIViewController, UIWebViewDelegate {
// MARK: Properties
#IBOutlet var webView: UIWebView!
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self
loadHomePage()
}
// MARK: Public
public func loadHomePage() {
navigateWebView(to: HOME_PAGE)
}
public func loadSettingsPage() {
navigateWebView(to: SETTINGS_PAGE)
}
public func loadSignOutPage() {
navigateWebView(to: SIGN_OUT_PAGE)
}
// MARK: Private
private func navigateWebView(to url: String) {
let request = URLRequest(url: URL(string: url)!)
webView.loadRequest(request)
}
I'm trying to write unit tests that verify that the proper URL is sent to the loadRequest function of the webview. Note that I don't actually care about loading the URL; this is just a unit test, so all I really want to test is that loadSettingsPage sends a URLRequest with the SETTINGS_PAGE URL to the webview to load, for example.
I tried something like this, with no success:
_ = webViewController.view // Calls viewDidLoad()
XCTAssertEqual(webViewController.webView.request?.url?.absoluteString, HOME_PAGE)
The value of the first part of the assertEqual was nil.
I assume I need to mock out the webView somehow but I'm not sure how to go about that. Any suggestions?
As a follow-up, I'd also like to be able to test when things like webView.reload() and webview.goBack() are called, so any pointers there would be appreciated as well. Thanks!

WKWebView: insert UIImage into web page

In iOS, given a web page loaded inside a WKWebView, how can I show my own UIImage inside the HTML?
Thanks
One way to do it is using Base64 encoding. The following should be a completely working example, assuming you wire up a UIWebView and have an image of the correct name:
import UIKit
import WebKit
class ViewController: UIViewController {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if let image = UIImage(named: "Castle"),
let data = UIImagePNGRepresentation(image) {
let base64 = data.base64EncodedString(options: [])
let url = "data:application/png;base64," + base64
let html = "<html><head></head><body><h1>Hello World!</h1><img src='\(url)'></body></html>"
webView.loadHTMLString(html, baseURL: URL(fileURLWithPath: ""))
}
}
}
I tried to do this in Playground, but couldn't get the webView to display, so it's a minimal app...
Output:

Is it possible to use a function similar to webViewFinishLoad without delegating?

I'm creating a framework to manipulate PDFs and at once point I load PDFs using the following code:
#IBOutlet var webView1: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
if let pdf = NSBundle.mainBundle().URLForResource("template", withExtension: "pdf", subdirectory: nil, localization: nil) {
let req = NSURLRequest(URL: pdf)
webView1.delegate = self
self.webView1.loadRequest(req)
}
}
And then making use of the UIWebViewDelegate properties of my ViewController class to benefit from webViewFinishLoad to know when loading is finished.
Is there anyway of achieving this same end result without delegating my webView1 to main view?
What are you looking for is to use a block callback, unfortunately
UIWebview doesn't support them.
There are still a lot of Cocoa libraries that don't support Closures. You could use for example ClosureKit to do this.
https://github.com/Reflejo/ClosureKit
Using this library you will be able to do this
webView.didFinishLoad = { webView in
println("didFinishLoad \(webView)")
}

DELAY issues: how to apply styles immediately or not show loaded webpage until styles are applied?

Technologies Used: XCode 6, iOS8, Swift
I'm loading a webpage in a uiwebview and I'm also appending a new stylesheet to the body of that webpage and overwriting some of its styles. But, there is a delay (maybe 1 second or 2) between when the webpage loads and the styles are applied so you can see the webpage before its restyled. I'm using javascript to append the new styles to the body of the webpage. How can I fix this so that the webpage will only show with the styles are already applied? Here is my code:
import UIKit
class SecondViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var website: UIWebView!
var url = "http://www.fake-website-url.net"
func loadUrl() {
let requestURL = NSURL(string: url)
let request = NSURLRequest(URL: requestURL!)
website.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
website.delegate = self
loadUrl()
}
func webViewDidFinishLoad(website: UIWebView) {
var loadStyles = "var script = document.createElement('link');script.type = 'text/css';script.rel = 'stylesheet';script.href = 'http://fake-url.styles.css';document.getElementsByTagName('body')[0].appendChild(script);"
website.stringByEvaluatingJavaScriptFromString(loadStyles)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Note, I'm using Swift.
What I would do is create a property to store the downloaded page. Then override the property setter to add your custom style sheet after the page is saved to that property. Then finally load it into your Web View.
Hope that makes sense.

Resources