Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with dynamically loaded phonegap.js

I'm trying to dynamically load the phonegap javascript file (so that I can choose not to load it in debug mode when I'm using Ripple) but I'm running in to some issues.

I load the jquery and jquerymobile javascript libraries using a normal script tag. In another script block, I do:

function onDeviceReady() { 
    alert("Device Ready!"); 
} 
$(document).ready(function() { 
    alert("doc ready!"); 
    $.getScript("js/phonegap.0.9.5.1.js", function() {alert("Got Phonegap!");}); 
    document.addEventListener("deviceready", onDeviceReady, false); 
}); 

This code alerts that it "Got Phonegap!" but never alerts "Device Ready". Using jsconsole.com, I can see that the PhoneGap javascript object exists. However, trying to call device.uuid (or other simple phonegap API calls) fails. It's almost like PhoneGap didn't fully initialize. Doesn't seem like that should be the case though. Am I missing something? Thanks!

like image 276
Max Avatar asked Jul 21 '11 21:07

Max


2 Answers

Finally I got it working without using any external library.

THE PROBLEM
For a multiplatform Phonegap project, two are the parts that differ from one platform to another:

  • The encapsulating project
  • The Javacript Phonegap file.

Those encapsulating projects typically do not change much over the course of the project. It would be desirable to have a single HTML5 codebase that one could directly paste (or using build scripts) onto the platform-dependent projects. Since the javascript phonegap library is inside the set of web files, it's really painfull to replace the correct file each time.

MY SOLUTION
In my project I have several cordova files, one for each target platform:

  • cordova.android.js
  • cordova.ios.js
  • cordoba.bb.js ...

(Notice how every one of these files is included in the app even if it is not used. For me it's not a problem, since the scripts are bundled in the app and only the one for the correct platform is loaded to memory).

In my pages, instead of a script tag for phonegap, I placed the loader module:

<script src="phonegap-loader.js"></script>

And this would be the phonegap-loader.js script. I make use of user-agent detection to dynamically and synchronously load the script:

    (function(){
        var useragent = navigator.userAgent;


        if(/Android/i.test(useragent)){
            loadScript('cordova.android.js');
        } else if((/iPhone/i.test(useragent)) || (/iPad/i.test(useragent))){
            loadScript('cordova.ios.js');
        }
        ...
        // Else desktop browser is assumed and no phonegap js is loaded


        function loadScript(url){
            // synchronous load by @Sean Kinsey 
            // https://stackoverflow.com/a/2880147/813951
            var xhrObj =  new XMLHttpRequest();
            xhrObj.open('GET', url, false);
            xhrObj.send('');
            var se = document.createElement('script');
            se.text = xhrObj.responseText;
            document.getElementsByTagName('head')[0].appendChild(se);
        }
    })();

Its really important to load the script SYNCHRONOUSLY. This gave me innumerable headaches. Before realising this I tried adding scripts tags at the bottom of the head, and using $.getScript, but none worked, since ondeviceReady was not fired. Looks like the only valid approach to ensure the Phonegap script is executed when loaded dynamically is the one shown in this amazing answer by @Sean Kinsey (all kudos to him).

The only drawback is that the script is inlined, but for me is a cheap price to pay for having the core HTML5 app finally isolated from the containers.

like image 84
Mister Smith Avatar answered Nov 16 '22 02:11

Mister Smith


I was facing the similar issue where in which I need to load the PhoneGap and dependent plugin files based on the platform type. I went through the PhoneGap source and found that it uses the windows/browser events to load and prepare the objects. If I call the browser events manually then it initializes the PhoneGap objects (API and Plugins) I needed to run my application.

The following code which is using Yabble has worked for me now:

<html>
<head>
<script
    src="https://raw.github.com/jbrantly/yabble/master/lib/yabble.js"></script>

<script>
    require.setModuleRoot("js");
    require.useScriptTags();

    require.ensure([ "jquery", "phonegap" ], function(require) {

        // Trigger PhoneGap Initialization
        PhoneGap.onPhoneGapInit.fire();

        // Load PhoneGap Plugins
        require.ensure([ "plugin1" ], function() {
            $("#console").append("Plugin1 loaded<br>");
        });

        // Both following functions will work only if PhoneGap is loaded/initialized and Plugin is successfully registered

        // Check PhoneGap device object
        $("#checkDevice").click(function() {
            console.log(JSON.stringify(device));
        });

        // Call Native Plugin
        $("#callPlugin").click(function() {
            window.plugins.plugin1.call();
        });
    });
</script>
</head>
<body>
    <div id="console"></div>

    <input type="button" id="checkDevice" value="Check Device">
    <input type="button" id="callPlugin" value="Call Plugin">
</body>
</html>

Both Device info and Plugin calls is working fine on Android. Although I have not checked all the PhoneGap API but as of now I need only these two to work and they are working.

Edit

In Phonegap 1.5/Cordova, PhoneGap.onPhoneGapInit.fire(); is not available due to API change. In my current test most of the required objects are available without any change after loading the JS dynamically. Updated test is available at this gist - Cordova Lazy Load Test

like image 3
dhaval Avatar answered Nov 16 '22 02:11

dhaval