3

I am implementing wkwebview in an app that was using UIWebView. I am unable to get javascript to execute when pointing to a local html file that has the javascript embedded within it. The javascript is stripped to do a simple alert and load a basic google map. None of that is getting executed. Do I need to run a local server? GCDWebserver..

I should add, the html/javascript works in safari, google browser no problem.

Solutions attempted include: 1. AppTransportSecuritySettings AllowArbitrary loads. 2. ViewController.swift webview.configuration.preferences.javaScriptEnabled = true 3. This question addresses the issue and says is was fixed in iOS 10.3 Load Javascript files through HTML file on WKWebView in iOS The simulator is running 12.1 4. This question also addresses the issue with an answer of requiring GCDWebserver to be able to execute javascript using wkwebview. WKWebView not executing any js code This however was also solved in a laster version of iOS. Here is some code:

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
    //@IBOutlet var googleMap: WKWebView!
    var webview: WKWebView!

     override func loadView() {
         webview = WKWebView()
         webview.navigationDelegate = self
         view = webview
     }
    override func viewDidLoad() {
        super.viewDidLoad()
        //let url = URL(string: "https://schallerf1.com")!
        let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "www")!
        webview.load(URLRequest(url: url))
        webview.allowsBackForwardNavigationGestures = true
        let request = URLRequest(url: url)
        webview.configuration.preferences.javaScriptEnabled = true
        webview.load(request)
    }
}
<!DOCTYPE html>
<html>
    <head>
        <title>Simple Map</title>
        <meta name="viewport" content="initial-scale=1.0">
            <meta charset="utf-8">
                <style>
                    /* Always set the map height explicitly to define the size of the div
                     * element that contains the map. */
                #map {
                    height: 100%;
                }
                /* Optional: Makes the sample page fill the window. */
                html, body {
                    height: 100%;
                    margin: 0;
                    padding: 0;
                }
                </style>
                </head>
    <body>
        <b>WHYYYYYYYYYY!!!!</b>
        <div style="height:100%;width:100%;" id="map"></div>
        <script type="text/javascript">
            var name = "TESTTESTTEST";
            alert('code: '    + name + '\n');
            var map;
            function initMap() {
                map = new google.maps.Map(document.getElementById('map'), {
                                          center: {lat: 39.976068, lng: -83.003297},
                                          zoom: 8
                                          });
            }
        </script>
        <script async defer src="https://maps.googleapis.com/maps/api/js?key=xxxxxxxxxxxxxxxxxx&callback=initMap"></script>
    </body>
</html>

None of the javascript works, I should get an alert and a simple google map should display. Do I need to look into the local web server GCDWebserver?

1 Answers1

0

You should be calling your javascript in this WKNavigationDelegate method, which is called when the webview finishes loading.

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.evaluateJavaScript("initMap()", completionHandler: { (value, err) in
        // Handle response here.
    })
}

Also, I'm not sure why you're calling two different webview.load() requests - maybe don't do that?

jake
  • 1,226
  • 8
  • 14
  • Thank you Jake for taking the time to answer. I implemented the WkNavigationDelegate as suggested. Still do not appear to be executing javascript. My index.html file does a window.load on main.html. Thus the initMap() function is not found from main.html. I added a test function into index.html with an alert `alert('code:' + name + ' \n')` and a console.log `console.log("i should see this in the console");`, but they are not getting executed even though the function is found. Any thoughts? – Chris Schaller Jun 14 '19 at 15:09
  • Try printing out `value` and `err` in the `completionHandler` of that function above (`evaluateJavaScript`). What does it say? – jake Jun 14 '19 at 17:56
  • Hi Jake. Value returns nothing, err returns nil. Here is the output from the console; Optional(Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=1, WKJavaScriptExceptionMessage=ReferenceError: Can't find variable: initMap, WKJavaScriptExceptionColumnNumber=8, WKJavaScriptExceptionSourceURL=file:///Users/schallerf1/Library/Developer/CoreSimulator/Devices/data/Containers/Bundle/Application/30497599-5839-4A2C-87F7-CC2D8F4F16DA/HistOrigin.app/www/index.html, NSLocalizedDescription=A JavaScript exception occurred}) nil – Chris Schaller Jun 14 '19 at 20:53
  • Key message here is "Can't find variable: initMap" - it's not finding your JS `function` anywhere. Make sure you're loading the correct source. Try removing the `subdirectory: "www"` from your resource url. Instead: `Bundle.main.url(forResource: "index", withExtension: "html")!` – jake Jun 14 '19 at 21:38
  • Removed subdirectory www as suggested. got this error on that line: _Unexpectedly found nil while unwrapping an Optional value_ . To clarify, index.html does window.load on main.html. main.html contains html, and map javascript. Added javascript includes from the larger project, they seem to load as seen in this image. I see maps.googleapis.com in red. Im thinking this could be a google maps api key issue, but I have already tried keys specifically for an iOS app and a open key. ![Web Inspector image](https://drive.google.com/file/d/1GG3gF4REGIlXGq9rhD97eS_wIh5hkJVI/view?usp=sharing) – Chris Schaller Jun 17 '19 at 20:16
  • oops I added wrong image this is the correct one ![web inspector view](https://drive.google.com/file/d/1A3zsUR8Q--mu1NgmdFcmioo0w1w2D7iM/view?usp=sharing) – Chris Schaller Jun 17 '19 at 20:38
  • Why not just load main.html instead of index.html in the first place? That sounds like your problem. – jake Jun 17 '19 at 21:45
  • 1
    Jake, your suggestion of eliminating the index.htm file to point directly to the main.html file is the answer to this question. Im on to the next obstacle now, but that is a new question. Thank you very much for your time and effort. – Chris Schaller Jun 19 '19 at 12:44