Issue with dynamically loaded phonegap.js - javascript

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!

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.

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

1) have you tried calling addEventListener before getScript ?
2) also, do you use the correct phonegap.js for your device ? (when using iphone phonegap.js on android i had the same 'silent' behaviour)

The deviceready event is a special event handled by code in phonegap.js by duck punching document.addEventListener so phonegap.js has to be loaded before you can attach an event to deviceready.
Try this:
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);
});
});

I was able to simulate correct PhoneGap initialization workflow after injecting it dynamically by running the following javascript code right after injecting phonegap.js script.
if (document.readyState == "complete") {
PhoneGap.onDOMContentLoaded.fire();
}

Related

How do i redirect to an external site with phonegap inside the app

I have a single page in my phonegap app , that i want to redirect to an external page after some seconds , but it keeps redirecting outisude the app.But i want it to open in the app
Here is my code
<script type="text/javascript">
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
// Now safe to use the Codova API
setTimeout( window.location="http://www.autojosh.com" , '7000') ; }
</script>
I have tried almost everything i know its not working please help
If you want to open the link inside your app, first of all, you need to install InAppBrowser plugin:
cordova plugin add cordova-plugin-inappbrowser
when you have the plugin, the following code will open the page in a new window inside the app.
window.open('http://your-page.com', '_blank', 'location=no,hidden=yes,toolbar=no');
Not for OP since this is so old, but for anyone looking for the same, the way to enable navigation to external URLs inside the main webview is by adding the following to the config.xml file:
<allow-navigation href="https://*/*" />
Set https or http accordingly.
Unlike with the InAppBrowser, this way the page can access the Cordova API, if you upload and include the JS files for the platform you're using.

Meteorjs load html script resource in template (not in body)

I am using the jsplumbtoolkit framework in order to load in several script html templates into my meteorjs application in order to create the appropriate divs/dialogues options necessary as a part of the api. After some troubleshooting I determined the issue seemed to be that Meteorjs was not loading my html script through the onRendered function that I supplied it with.
To give you a better idea of the problem
//Due to Meteorjs not able to load scripts directly in the template, I added the script load to my onRendered function in my template js
Template.mytemplate.onRendered(function(){
$(document).ready(function() {
var script = document.createElement("script");
script.type="text/x-jtk-templates";
script.src = "templates/workflowtemplate.html";
$("#rulesscripttemplate").replaceWith(script);
});
})
workflowtemplate.html is in the appropriate meteorjs directory /public/templates/workflowtemplate.html and I am assuming the directory is correct.
This is properly loaded when I check my client Mozilla developer kit as well
<script type="text/x-jtk-templates" src="templates/templaterulesworkflow.html"></script>
Is there a better way to confirm that this resource was infact loaded to the client through mozilla?
Figured it out. had to add the <script type="text/x-jtk-templates" src="templates/templaterulesworkflow.html"></script> to the tag of my application. That resolved the issue.

Why does Cordova 2.7.0 JS seemingly no longer work on remote pages?

Background
I'm attempting to upgrade an iOS app built on Cordova 2.0 to version 2.7.
It's basically a welcome screen that points to a remote search engine (please withhold comments about app validity and likely approval, as we're past that), and we were using the ChildBrowser plugin to enable opening links in a sub browser so as not to trap the user in the Cordova webview.
Cordova 2.7 has a feature called InAppBrowser I am hoping to use instead of ChildBrowser. InAppBrowser does essentially the same thing, aside from missing a button to open in Safari.
Problem
The existing app's remote webpages include the Cordova JS (as well as that for the ChildBrowser plugin) and it works fine for opening links in the sub browser.
My test Cordova 2.7 app doesn't seem to load the Cordova JS correctly when it's being loaded from a remote web page.
I tried using this exact same HTML on the embedded start page and a remote start page:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://mydomain.com/mobile/cordova-2.7.0.js"></script>
</head>
<body>
<script>
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
alert("Ready!!");
}
</script>
</body>
</html>
To test this as the embedded start page, I put this line in config.xml:
<content src="index.html" />
When I run the app, I promptly get the "Ready!" alert.
To test this as the remote start page (I'm aiming to link to the remote page in the final app, I am just using it as the start page for testing. The result is the same if I link from the embedded page.), I put this line in config.xml:
<content src="http://mydomain.com/mobile/index.php" />
When I run the app, I just get the blank screen and no alert.
Further, in cordova-2.7.0.js L. 6255, I changed
console.log('deviceready has not fired after 5 seconds.');
to
alert('deviceready has not fired after 5 seconds.');
With that change, running the app using the remote start page causes the blank page, and then after five seconds, I get the alert "deviceready has not fired after 5 seconds.". So this tells me Cordova JS is not starting correctly. Needless to say, I can't get InAppBrowser to launch links in the sub browser on the remote site, but I can get it working just fine on the embedded start page.
Anyone have any ideas of where to go from here? This is a pretty simplistic example, so I'm assuming this is a Cordova settings problem or a change in the functionality. I appreciate any thoughts, thanks!
Yes, something broke in 2.7 - related to our cordova-cli work. See: https://issues.apache.org/jira/browse/CB-3029
The fix is to add an empty file called "cordova_plugins.json" in your root folder.
I had a similar problem relating to upgrading to Cordova 2.7. However my problem was all my console.logs stopped firing when running the app. I couldn't figure out why for the life of me this was happening. I thought it was because I upgraded jquery.mobile. That wasn't it. I then thought it was an .htaccess issue, that wasn't it either. It turns out, it was Cordova 2.7 that was causing this problem.
I did try adding the .json file on my server, that did not fix the issue.
The fix was going into the 2.7 source and commenting out the following code:
/*comment out this as it is breaking console.logs
var xhr = new context.XMLHttpRequest();
xhr.onload = function() {
// If the response is a JSON string which composes an array, call handlePluginsObject.
// If the request fails, or the response is not a JSON array, just call finishPluginLoading.
var obj = this.responseText && JSON.parse(this.responseText);
if (obj && obj instanceof Array && obj.length > 0) {
handlePluginsObject(obj);
} else {
finishPluginLoading();
}
};
xhr.onerror = function() {
finishPluginLoading();
};
xhr.open('GET', 'cordova_plugins.json', true); // Async
xhr.send();
*/
Replace entire block with a call to the following function:
finishPluginLoading();
My logs are now working again. Only took me 3 days scratching my head.
Hope this helps someone with a similar problem.
If you embed Cordova in the external web page, there will be no way to open the InAppBrowser from within your hybrid app, so Cordova will not be able to load. This is because the InAppBrowser requires Cordova to be fully loaded and initialized before it can be used to fetch a remote page. You need to use your HTML page that you have, with the <script type="text/javascript" src="http://mydomain.com/mobile/cordova-2.7.0.js"></script> as the main entry point for your app. Then you can use the InAppBrowser to open up your remote page. (You could probably do this in the onDeviceReady(), not sure if it would "flash" the page first though.) I don't think the remote page should have any Cordova code in it at all. I'm not sure if it would be possible to even interact with Cordova from the remote page due to the Same Origin Policy (probably you could use features of the InAppBrowser to inject "bridge" code though to get around this.)
As Shazron mentioned the problem is the issue with the file"cordova_plugins.json".
To solve the problem not changing the code you can create the "cordova_plugins.json" file in the root folder and insert a content between quotation marks inside this file.
Mine for example has the following content:
"Just a dummy file required since Cordova 2.6.0"
create a file cordova_plugins.json that contains {}. then go to cordova-2.7.0.js and comment this line require('cordova/channel').onNativeReady.fire(); then when development done, add it back
Like me if you are using Cordova 5.1.1 and want to access native functionality after redirect then copy cordova.js, cordova_plugins.js and plugins folder which is at \platforms\platform_name\assets\www\ and put them on server, finally reference cordova.js inside your html. After every plugin add make sure to update these files and folder.

Most efficient and reliable method to detect if app is running in phonegap via JavaScript

What is the most efficient and reliable method to detect if an app is running in phonegap, or simply inside of a mobile/desktop browser with JavaScript? I am attempting to eliminate any of the issues that prevent me from testing/debugging my phonegap apps in any browser (desktop or mobile), and create a truly universal code base for my apps.
I intend on structuring my functions with phonegap specific calls like so:
if (phonegapisrunning) {
// phonegap specific javascript calls here
}
else {
// standard javascript calls here
}
While searching for a solution I came across this thread:
PhoneGap: Detect if running on desktop browser.
While this thread discusses this issue, I do not see a clear answer to which method is the most efficient/reliable. Should I bind to the onDeviceReady() event? Should I check window.device? Is there a more efficient or reliable way to check if an app is running in phonegap via JavsScript?
And this thread which mentions the Ripple Chrome Plugin:
Phonegap web app in regular desktop browsers
The Ripple tools looks like it could be a valuable tool for testing. But I am trying to make my phonegap apps run in a desktop browser without a plugin.
If it is determined that the app is not running in phonegap, I would then use useragent sniffing to determine if browser is desktop or mobile, and further separate any code if needed.
I've seen many answers about checking the user agent. Though those are useful for comparing which platform on which a page was loaded, they still do not differentiate whether running within a cordova app's browser or within a regular web browser. After a whole bunch of digging in the android cordova javascript file, I found that the following variable is set when running in a cordova app:
window._cordovaNative
Looking through the ios cordova javascript, I found:
window._nativeReady
Throw these alerts in your page before you ever load any cordova javascripts or check any user agents, etc. and compare results between loading from a web browser and loading from a cordova app that gets dynamic content:
alert("Android: " + window._cordovaNative);
alert("iOS: " + window._nativeReady);
I guess the other devices' phonegap files have different global variables, but for now, this is going to work great for me -- I hope it works well for you!
My suggestion is to create/call your javascript functions outside of the onDeviceReady Phonegap call.
Or maybe check what version of Cordova / Phonegap is running e.g.:
var string = device.cordova; // or device.phonegap
if (string == null) {
//do non phonegappy stuff here
} else {
//do phonegappy stuff
}
While it may not be the cleanest solution, a simple and reliable method is to create/set a global variable on deviceready:
var isCordovaReady = true;
Then:
if (isCordovaReady) {
// do cordova/phonegap stuff
}
else {
// do non cordova/phonegap stuff here
}
I posted the top answer for: PhoneGap: Detect if running on desktop browser
Although this isn't heavily documented and somewhat controversial I've been able to use this chunk of code for all my projects:
if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/)) {
document.addEventListener("deviceready", onDeviceReady, false); //phone
} else {
onDeviceReady(); //this is the browser
}
You can modify it a bit to work for your projects like so:
var phonegapisrunning = false;
if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/)) {
document.addEventListener("deviceready", onDeviceReady, false); //phone
//change to true
phonegapisrunning = true;
} else {
onDeviceReady(); //this is the browser
}
Hope this helps !

Facebook's all.js not compatible with $.getScript()

I am trying to include Facebook's Javascript SDK (the all.js file from http://connect.facebook.com/en_US/all.js) dynamically vis javascript for my web app. I have used the following code.
$.getScript('http://connect.facebook.com/en_US/all.js', function() {
alert('Facebook script has loaded');
});
When this is executed, currently I find that the page never alerts. My main aim is to load the Facebook JS SDK programatically. Kindly let me know if there is something wrong in what I am doing or is there any other way to achieve it.
The url is wrong, change to:
'http://connect.facebook.net/en_US/all.js'
Also see this jsfiddle.

Categories