Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript not executed in WKWebView

Since I'm going a bit crazy with this one, I've decided to give it another try and post about it here.

So...

I have a simple Swift/Cocoa application with a WKWebView in it.

I load a local HTML file (which - along with the rest of the .css/.js dependencies - is being copied to the bundle inside a /web folder).

Here's the complete code:

<!DOCTYPE html>
<html>
    <head>
        <title>IBAN Validator</title>
        <meta name="viewport" content="width=device-width"/>
        <meta charset="UTF-8">

        <link href="style/font-awesome.min.css" type="text/css" rel="stylesheet"/>
        <link href="style/electriq.css" type="text/css" rel="stylesheet"/>
        <link href="style/custom.css" type="text/css" rel="stylesheet" />
    </head>
    <body>
        <!-- window/ -->
        <div class="window">
            <div class="content" style="text-align: center">
                <div class="panel">
                    <input id="iban" type="text" style="text-align:center;"><br/>
                    <div style="position: relative; max-width: 150px; width: 100%; margin: 0 auto">
                        <a id="validateButton" href="#" class="button" style="width:150px;">Validate</a>
                        <span id="resultValid" style="position:absolute; left: calc(100% + 20px); top: 10%; color: green; font-size: 20px; display:none;"><i class="fa fa-check"></i></span>
                        <span id="resultInvalid" style="position:absolute; left: calc(100% + 20px); top: 10%; color: red; font-size: 20px; display:none;"><i class="fa fa-close"></i></span>
                    </div>
                </div>
            </div>
        </div>
        <!-- /window -->

        <div id="loader_overlay" style="padding-top:10%">
            <i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i><br/>
        </div>

        <!-- scripts/ -->
        <script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
        <script src="jquery.min.js" type="text/javascript"></script>
        <script>
            if (typeof window.jQuery !== 'undefined') {
                window.document.getElementById("loader_overlay").innerHTML += ".";
            } else {
                window.document.getElementById("loader_overlay").innerHTML += "x";
            }
        </script>
        <script src="handlebars.min.js" type="text/javascript"></script>
        <script>
            if (typeof window.Handlebars !== 'undefined') {
                window.document.getElementById("loader_overlay").innerHTML += ".";
            } else {
                window.document.getElementById("loader_overlay").innerHTML += "x";
            }
        </script>
        <script src="bridgecommander.js" type="text/javascript"></script>
        <script>
            if (typeof window.BridgeCommander !== 'undefined') {
                window.document.getElementById("loader_overlay").innerHTML += ".";
            } else {
                window.document.getElementById("loader_overlay").innerHTML += "x";
            }
        </script>
        <script src="iban.js" type="text/javascript"></script>
        <script>
            if (typeof window.IBAN !== 'undefined') {
                window.document.getElementById("loader_overlay").innerHTML += ".";
            } else {
                window.document.getElementById("loader_overlay").innerHTML += "x";
            }
        </script>
        <!-- <script src="app.js" type="text/javascript"></script> -->
        <script>

            // Generated by CoffeeScript 2.0.2
            var doValidate;

            window.appLoaded = true;
            window.document.getElementById("loader_overlay").innerHTML += ".";
            BridgeCommander.call("echo", "Before: onload");
            window.document.getElementById("loader_overlay").innerHTML += ".";

            window.onload = function() {
              BridgeCommander.call("echo", "Inside: onload");
              document.getElementById("loader_overlay").style.display = 'none';
              return $("#validateButton").on("click", doValidate);
            };
            window.document.getElementById("loader_overlay").innerHTML += ".";
            BridgeCommander.call("echo", "After: onload");

            doValidate = function() {
              var iban, valid;
              iban = $("#iban").val();
              valid = IBAN.isValid(iban);
              if (valid) {
                $("#resultValid").show();
                $("#resultInvalid").hide();
                $("#validateButton").removeClass("invalid").addClass("valid");
                BridgeCommander.call("echo", `Validating: ${iban}, Result: valid`);
              } else {
                $("#resultValid").hide();
                $("#resultInvalid").show();
                $("#validateButton").removeClass("valid").addClass("invalid");
                BridgeCommander.call("echo", `Validating: ${iban}, Result: invalid`);
              }
              setTimeout(function() {
                $("#validateButton").removeClass("valid").removeClass("invalid");
                $("#resultValid").hide();
                return $("#resultInvalid").hide();
              }, 3000);
              return false;
            };
            window.document.getElementById("loader_overlay").innerHTML += ".";

            if (typeof window.appLoaded !== 'undefined') {
                window.document.getElementById("loader_overlay").innerHTML += ".";
            } else {
                window.document.getElementById("loader_overlay").innerHTML += "x";
            }
        </script>
        <script>if (window.module) module = window.module;</script>
        <!-- /scripts -->
    </body>

</html>

Important Note: Here (meaning on my Mac - and everyone's Mac with 10.3.1 I've tried this on) everything works fine. When I upload the exact same binary to the App Store for review, I keep getting the same "error" screenshot, signifying none of the code within my last <script></script> block gets executed. (after the window.appLoaded = true part).


What could be going on? I've literally tried anything to debug this (hence, the numerous window.document.getElementById thing, adding dots to make sure everything worked), but still nothing.

As you can see, I'm loading several scripts (which according to my tests load fine), and I also have several pieces of inline JS code (which still work fine). Except for the last one! (which, no matter what, even from an external file, seems to refuse to load...)

Again, I thought about sth being cached, I don't know, but I remind you that it - apparently -- works everywhere apart from the Review team's machine :S

Any idea would be welcome!


P.S. In case something is not clear, please feel free to ask me anything


Update: (28/11/2017) Tried the whole thing with a simple - old-style - WebView (in case it had to do with the WKWebView) and still my app gets rejected. Or to be precise, my app (exact version, same everything) runs fine everywhere, except for the guy that reviews it.

like image 423
Dr.Kameleon Avatar asked Nov 20 '17 08:11

Dr.Kameleon


People also ask

Is WKWebView deprecated?

Since then, we've recommended that you adopt WKWebView instead of UIWebView and WebView — both of which were formally deprecated. New apps containing these frameworks are no longer accepted by the App Store.

How do I refresh WKWebView?

The WKWebView already contains a scrollview. All you need to do is create the refresh control, assign a target function that will get called when a user initiates a refresh, and attach the refresh control to the scrollview.

How do I use WKWebView?

Here's how: Open the XIB or Storyboard you want to add the web view to in Interface Builder. Find the web view or WKWebView in the Object Library at the bottom-left of Interface Builder. Drag-and-drop a WKWebView object from the Object Library to your view controller's canvas, and adjust its size and position.


1 Answers

This could be because the browser does not know how to parse the contents of the script tags

<script></script> tags require the type attribute on them most browsers will assume it's the same as the last one but as none of your code containing script tags specifies the type it might not know how to parse them the script support more than javascript for example VBScript to whenever you open a <script> for javascript it should be <script type="text/javascript">

The other problem could be the window.onload I would recommend you change it to the DOMContentLoaded event and use a closure to make sure it executes the code.

More so why are you not loading jQuery in the head tag where it's supposed to be loaded move <script src="jquery.min.js" type="text/javascript"></script> to inside the <head></head>.

Following on from this if you have jQuery why are you mixing jQuery and pure Javascript if you have jQuery use it's smaller code and cleaner

 (function($){
     $(function(){
         window.appLoaded = true;
         $("loader_overlay").append(".");
         BridgeCommander.call("echo", "Before: onload");
         $("loader_overlay").append(".");

         $("loader_overlay").append(".");
         BridgeCommander.call("echo", "After: onload");

         function doValidate() {
             var iban, valid;
             iban = $("#iban").val();
             valid = IBAN.isValid(iban);
             if (valid) {
                 $("#resultValid").show();
                 $("#resultInvalid").hide();
                 $("#validateButton").removeClass("invalid")
                                     .addClass("valid");
                 BridgeCommander.call("echo", `Validating: ${iban}, Result: valid`);
             } else {
                 $("#resultValid").hide();
                 $("#resultInvalid").show();
                 $("#validateButton").removeClass("valid")
                                     .addClass("invalid");
                 BridgeCommander.call("echo", `Validating: ${iban}, Result: invalid`);
             }

             setTimeout(function() {
                 $("#validateButton").removeClass("valid")
                                     .removeClass("invalid");
                 $("#resultValid").hide();
                 return $("#resultInvalid").hide();
             }, 3000);
             return false;
        };

         (function(doValidate) {
             BridgeCommander.call("echo", "Inside: onload");
             $("loader_overlay").css("display",'none');
             return $("#validateButton").on("click", doValidate);
         })(doValidate);

         window.document.getElementById("loader_overlay").innerHTML += ".";

         if (typeof window.appLoaded !== 'undefined') {
             window.document.getElementById("loader_overlay").innerHTML += ".";
         } else {
             window.document.getElementById("loader_overlay").innerHTML += "x";
         }
         if (window.module){ module = window.module; }
    });
});

On another note please get rid of all your file loading checks. so all of the following code blocks

if (typeof window.Handlebars !== 'undefined') {
    window.document.getElementById("loader_overlay").innerHTML += ".";
} else {
    window.document.getElementById("loader_overlay").innerHTML += "x";
}

They are only needed for debugging and you know it's Web Kit if the file loads on one it loads on all. so you don't need these check's they are just using phone processing power and adding work to your app for no good reason. other than to put a . in the overlay...

and again all <script src=... should be inside the <head> tags, in this case, all of your code should be inside the script tags and using jQuery read as my above version does.

How are you testing this App on the Mac are you using the iPhone emulator? or a real iPhone to test i would always recommend the latter. and have you tested in on one of these as you don't seem to say you have, if not get a device registered for testing on your developer account create the keys to test and build a test version then use Safari or chromes remote debugging tools on the WebView and make sure it all works.

like image 128
Barkermn01 Avatar answered Nov 14 '22 22:11

Barkermn01