Swift WKWebView and Javascript Interaction - ios

I've been having trouble getting a WKWebView in Swift to trigger some javascript in the loaded web page. Im just trying to use javascript to change a background color on the website if the user swipes left, swipes right, or clicks a button. Any help is greatly appreciated.
import UIKit
import WebKit
class myViewController: UIViewController, WKNavigationDelegate {
#IBOutlet var container: UIView!
var webView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
self.webView = WKWebView()
container.addSubview(webView!)
webView?.allowsBackForwardNavigationGestures = true
webView?.navigationDelegate = self
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(myViewController.handleSwipes(_:)))
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(myViewController.handleSwipes(_:)))
leftSwipe.direction = .Left
rightSwipe.direction = .Right
view.addGestureRecognizer(leftSwipe)
view.addGestureRecognizer(rightSwipe)
}
override func viewDidAppear(animated: Bool) {
let frame = CGRectMake(0, 0, container.bounds.width, container.bounds.height)
webView!.frame = frame
let url = NSURL(string: "https://www.google.com")
let request = NSURLRequest(URL: url!)
self.webView!.loadRequest(request)
}
#IBAction func buttonClick(sender: AnyObject) {
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='red';", completionHandler: nil)
}
func handleSwipes(sender:UISwipeGestureRecognizer){
if (sender.direction == .Left){
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='black';", completionHandler: nil)
}
if (sender.direction == .Right){
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='green';", completionHandler: nil)
}
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='red';", completionHandler: nil)
}
}

You misspelled the Javascript's function name. It should be getElementById instead of getElementByID:
document.getElementById('hplogo').style.backgroundColor = '...'

Related

WKWebView.scrollView.bounces = false is Not working

I click the button to go to another Webview. However, I removed the bounce from the moved Webview, but it does not work.
First WKWebView
var openSecondScreen : SecondWebViewController!
var preloadCheck = false
...
func openSecondScreen(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
openSecondScreen = storyboard.instantiateViewController(withIdentifier: "SecondWebViewController") as! SecondWebViewController
openSecondScreen.delegate = self
openSecondScreen.loadViewIfNeeded()
openSecondScreen.secondWKWebView.navigationDelegate = self
preloadCheck = true
}
....
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if preloadCheck {
self.navigationController?.pushViewController(openSecondScreen, animated: true)
preloadCheck = false
}
}
Second WKWebView
#IBOutlet var secondWKWebView: WKWebView!
...
override func loadView() {
super.loadView()
secondWKWebView.uiDelegate = self
secondWKWebView.navigationDelegate = self
secondWKWebView.scrollView.delegate = self
...
}
extension SecondWebViewController: UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("scrollViewDidScroll")
scrollView.bounces = false
}
}
Scroll does not display the log. Therefore, the function does not work either.
Editing: I don't think I wrote this down in advance. I'm even setting it up in advance.But it didn't work
override func viewDidLoad() {
super.viewDidLoad()
secondWKWebView.scrollView.bounces = false
}
Thanks in advance

How to Detect Back Swipe in WkWebView

Is it possible to detect a back swipe in a web view when there has not been any forward navigation? The following code works fine if the user has moved off the first page but I want to know if they back swiped while on that page.
Update - This is the code I'm using after modifying it per comments. I added the navigation back function and the swipe gesture.
class WebViewClient: UIViewController, WKUIDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate
{
var webView: WKWebView!
public func load(pageLink page: String)
{
print("Opening: " + page)
if webView != nil
{
if let myURL = URL(string:page)
{
webUrlRequest = page
let myRequest = URLRequest(url: myURL)
webView.load(myRequest)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
print("Opened: " + webUrlRequest)
}
override func loadView()
{
let pref = WKPreferences()
pref.javaScriptEnabled = true
let config = WKWebViewConfiguration()
config.preferences = pref
webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
view = webView
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
{
if navigationAction.navigationType == .backForward && webView.backForwardList.backList.count == 0
{
print("Can't go back any more")
}
decisionHandler(.allow)
}
#objc func backNavigationFunction(_ sender: UIScreenEdgePanGestureRecognizer)
{
let dX = sender.translation(in: view).x
if sender.state == .ended
{
let fraction = abs(dX / view.bounds.width)
if fraction >= 0.35
{
print("Back swipe")
//back navigation code here
}
}
}
override func viewDidLoad()
{
super.viewDidLoad()
let swipeGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(backNavigationFunction(_:)))
swipeGesture.edges = .left
swipeGesture.delegate = self
webView.addGestureRecognizer(swipeGesture)
}
}
I would implement a UIScreenEdgePanGestureRecognizer to handle this. Add the following to your viewDidLoad
let swipeGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(backNavigationFunction(_:)))
swipeGesture.edges = .left
swipeGesture.delegate = self
view.addGestureRecognizer(swipeGesture)
Then, implement a function to handle the backNavigationFunction like below:
#objc func backNavigationFunction(_ sender: UIScreenEdgePanGestureRecognizer) {
let dX = sender.translation(in: view).x
if sender.state == .ended {
let fraction = abs(dX / view.bounds.width)
if fraction >= 0.35 {
//back navigation code here
}
}
}
Don't forget to make the ViewController inherit from the UIGestureRecognizerDelegate class (i.e. class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate). The delegate in question here is UIGestureRecognizerDelegate but I anticipate you'll need the others as well.

Unable to start Activity Indicator in Swift 3?

I am new to IOS. I am trying to implement activity indicator while loading web view, but I am unable to do that.While debugging I encounter that animator is starting but it is not getting visible. I am using swift 3. Here my code is as below.Please let me know what I am doing wrong. If anyone have good resource to learn about activity indicator please mention that also.
class ViewController: UIViewController,UIWebViewDelegate {
var WebView: UIWebView!
override func viewDidLoad()
{
super.viewDidLoad()
WebView = UIWebView(frame: UIScreen.main.bounds)
WebView.delegate = self
view.addSubview(WebView)
if let url = URL(string: "https://apple.com")
{
let request = URLRequest(url: url)
WebView.loadRequest(request)
}
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
}
// weak var activityindicator: UIActivityIndicatorView!
let activityindicator = UIActivityIndicatorView()
func webViewDidStartLoad(_ webView: UIWebView)
{
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = false
activityindicator.stopAnimating()
activityindicator.alpha = 0
activityindicator.isHidden = true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError)
{
activityindicator.isHidden = true
}
}
Looks like the activity indicator is not added to view. Similar to how we are adding webview, center and add the indicator in viewDidLoad (code below).
activityindicator.center = self.view.center
view.addSubview(activityindicator)
Also I would suggest moving the global declarations to one place. i.e move the indicator declaration let activityindicator = UIActivityIndicatorView(), to be below webview's on top, instead of middle of class. This helps in quick readability.
Here is your full code. Now it's working -
import UIKit
class ViewController: UIViewController,UIWebViewDelegate {
var WebView: UIWebView!
override func viewDidLoad()
{
super.viewDidLoad()
WebView = UIWebView(frame: UIScreen.main.bounds)
WebView.delegate = self
view.addSubview(WebView)
if let url = URL(string: "https://apple.com")
{
let request = URLRequest(url: url)
WebView.loadRequest(request)
}
activityindicator.startAnimating()
activityindicator.center = self.view.center
view.addSubview(activityindicator)
activityindicator.color = UIColor.black
activityindicator.alpha = 1
}
// weak var activityindicator: UIActivityIndicatorView!
let activityindicator = UIActivityIndicatorView()
func webViewDidStartLoad(_ webView: UIWebView)
{
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = false
activityindicator.stopAnimating()
activityindicator.alpha = 0
activityindicator.isHidden = true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError)
{
activityindicator.isHidden = true
}
}

Added UIBarButtonItem cannot be triggered

language: swift 3.0
os: macOS 10.12.3
xcode: 8.2.1
Here is a blank Storyboard with a ViewController.
And below is the code:
import UIKit
import WebKit
class CommonWebViewViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
let backButton = UIBarButtonItem(title: "BACK", style: .plain, target: self, action: #selector(goBack))
let closeButton = UIBarButtonItem(title: "CLOSE", style: .plain, target: nil, action: #selector(close))
let webview = WKWebView()
var url = ""
override func viewDidLoad() {
super.viewDidLoad()
view = webview
navigationItem.setLeftBarButtonItems([backButton], animated: true)
webview.uiDelegate = self
webview.navigationDelegate = self
webview.allowsBackForwardNavigationGestures = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
title = webView.title
}
func load(withUrl url: String) {
self.url = url
webview.load(URLRequest(url: URL(string: self.url)!))
}
func goBack() {
if webview.canGoBack {
webview.goBack()
navigationItem.leftBarButtonItems?.append(closeButton)
}
else {
close()
}
}
func close() {
_ = self.navigationController?.popViewController(animated: true)
}
}
I want to make a browser, and when I tap the BACK button, there's no response unless I click a link in webview.
P.S if I create the UIBarButtonItem object in viewDidload method, the problem will be solved.

Swift javascript/ios bridge breaks swipe gesture recognizer

I have a swipe gesture recognizer to bring a toolbar off and on the screen. It was working beautifully until I added a JavaScript to iOS bridge using WKUserContentController(). The bridge works, successfully printing the JavaScript message, but swiping no longer works. But if I comment out Webview = WKWebView(frame: self.view.frame, configuration: configuration) and view.addSubview(Webview) the bridge is obviously broken, but the gesture recognizer works. I just can't get them both working at the same time. Where have I gone wrong?
Edit: Maybe this is relevant: with the code as below, the activity indicator does not appear when the WebView is loading. Also, if I comment out the lines that start the toolbar hidden (starting point swiped off the page), the toolbar should appear, but it doesn't:
import UIKit
import WebKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate,
WKNavigationDelegate, WKScriptMessageHandler {
let locationManager = CLLocationManager()
#IBOutlet var Webview: WKWebView!
#IBOutlet var ActInd: UIActivityIndicatorView!
#IBOutlet var Toolbar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
let controller = WKUserContentController()
controller.add(self, name: "SwiftNative")
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
// commenting out these two lines disables the bridge but activates swiping again
Webview = WKWebView(frame: self.view.frame, configuration: configuration)
view.addSubview(Webview)
let url = URL(string: "https://www.bazleysawesomesite.com")
let request = URLRequest(url: url!)
Webview.load(request)
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(_:)))
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(_:)))
rightSwipe.direction = .right
leftSwipe.direction = .left
view.addGestureRecognizer(rightSwipe)
view.addGestureRecognizer(leftSwipe)
self.view.backgroundColor = UIColor.black
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Message from beyond: \(message.body)")
}
// Make the status bar text light
override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
// Start the toolbar "hidden"
// commenting out these lines should make the toolbar appear, but it doesn't
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
Toolbar.center.x = Toolbar.center.x - self.view.frame.width
}
// Activity Indicator stuff
func webViewDidStartLoad(_ : WKWebView) {
ActInd.startAnimating()
}
func webViewDidFinishLoad(_ : WKWebView) {
ActInd.stopAnimating()
if self.Toolbar.center.x > 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x - self.view.frame.width
})
}
}
// handle swipes
func handleSwipes(_ sender:UISwipeGestureRecognizer) {
if (sender.direction == .right) {
if self.Toolbar.center.x < 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x + self.view.frame.width
})
}
}
if (sender.direction == .left) {
if self.Toolbar.center.x > 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x - self.view.frame.width
})
}
}
}
}

Resources