Opened 8 years ago

Closed 5 years ago

#14062 closed enhancement (fixed)

Better dojo/ready and has() integration with PhoneGap runtime

Reported by: Chris Mitchell Owned by: cjolif
Priority: high Milestone: 2.0
Component: Core Version: 1.6.1
Keywords: phonegap 1.9 Cc: Rawld Gill, Adam Peller, todkap@…, cjolif, Eric Durocher, pmuellr
Blocked By: Blocking:

Description

Dojo and PhoneGap? both have their own event to acknowledge when the page is ready. We are finding that the dojo.ready is too early for things like deviceDetection APis when running within a PhoneGap? container and it would be better off being done inside of the PG deviceReady method.(http://docs.phonegap.com/phonegap_events_events.md.html)

Dojo mobile runs just fine when you follow phone gap's instructions, but doing this makes application code that can't run in both pg and browser environments. We'd like dojo.ready() to just detect pg and do the right thing. Including adding a has("phonegap") test for the pg environment being available.

Like Adobe AIR environment on the desktop, Dojo ready() module should be able to detect that the page is running inside of a PhoneGap? runtime and align these two methods.

This would make code more portable when migrating from the Mobile Web Model to the Hybrid Web Model.

Attachments (3)

www.zip (2.4 KB) - added by Paul Christopher 8 years ago.
Show case for a "phonegap-compat.js" file approach
14062.patch (2.6 KB) - added by Eric Durocher 7 years ago.
Add Phonegap support to dojo/ready - Eric Durocher (IBM, CCLA)
deviceReady.js (609 bytes) - added by Richard Backhouse 7 years ago.
Cordova deviceReady AMD plugin that works in a similar way to dojo/domReady

Download all attachments as: .zip

Change History (32)

comment:1 Changed 8 years ago by Adam Peller

Cc: Adam Peller added

comment:2 Changed 8 years ago by Paul Christopher

My workaround for this is the following:

I always include a "phonegap-compat.js" file in the header right underneath the phonegap-1.0.0.js include (see www.zip for more details).

The compat file just defines a new function "dojo.onDeviceReady" like so:

dojo.onDeviceReady = function(callback){

if (typeof PhoneGap == 'undefined') {

dojo.addOnLoad(callback);

} else {

document.addEventListener("deviceready", callback, false);

}

};

In the main html file I always use dojo.onDeviceReady instead of dojo.ready/dojo.addOnLoad. This works fine for me.

But this only solves a small part of a much larger problem you are faced with when developping a phonegap app. Phonegap offers a quite comprehensive API to access native device functionality (like geo location, accelerometer, local file system etc., see http://docs.phonegap.com/en/1.1.0/index.html). You also need to provide some wrappers for these API functions to make the app portable from normal browser environments to a phonegap environment.

In my phonegap-compat.js file I always do some kind of monkey patching therefore:

(function(){

if (typeof PhoneGap == 'undefined') {

navigator.notification = {};

navigator.notification.alert = function(msg) {

alert(msg);

};

}

})();

So I can always use navigator.notification.alert in the main html file. It then displays a device native dialog in a phonegap environment and a normal browser alert dialog in a browser environment.

But what would be the correct wrapper for an accelerometer call or a call to the device's contact database? Does a single, all-embracing, generic solution exist for these cases as shown in the alert dialog example? I think: no.

Therefore: It remains the question whether it makes really sense to integrate all these things into dojo or to leave these things separated (as shown above) and just set some best-pratice examples (by a tutorial) using the phonegap-compat.js file approach.

All in all: It is still a desideratum of dojox-mobile-documentation, on how to develop, debug, and port an app to phonegap and back to normal browser environments during the development process.

This includes the issue about phonegap's onDeviceReady and dojo.ready.

This includes the problem of the need to do a custom build [So as to ease the development process and cross device testing, I don't use a custom build at the moment. I just delete all unnecessary files in the dojo folder. So the app is about 1MB. But this works fine for me with the iPad.]

This includes the yet unanswered question on how to do a bigger app at the moment with dojox.mobile e.g. for the iPad [You cannot mess all parts of the code into one single html file. A working application controller like dojox.app is still missing and lacks important features, see http://bugs.dojotoolkit.org/ticket/13873. And splitting up the app into several html files is prone to problems, see http://bugs.dojotoolkit.org/ticket/13996.]

Last edited 8 years ago by Paul Christopher (previous) (diff)

Changed 8 years ago by Paul Christopher

Attachment: www.zip added

Show case for a "phonegap-compat.js" file approach

comment:3 Changed 8 years ago by Paul Christopher

Someone has already done a dojox.phonegap module: https://github.com/foobarfighter/dojox/tree/master/phonegap

comment:4 Changed 8 years ago by Chris Mitchell

Cc: todkap@… added

comment:5 Changed 8 years ago by Chris Mitchell

Looks like Ben's module is still 1.6, we'll need to rework for 1.7/AMD.

comment:6 in reply to:  2 Changed 8 years ago by Chris Mitchell

I don't think we need to wrap all the phonegap api's, I'd prefer that they were completely independent; however, making sure dojo initialization waits for device ready would be nice to integrate into the dojo/ready module.

Replying to Paul Christopher:

My workaround for this is the following:

I always include a "phonegap-compat.js" file in the header right underneath the phonegap-1.0.0.js include (see www.zip for more details).

The compat file just defines a new function "dojo.onDeviceReady" like so:

dojo.onDeviceReady = function(callback){

if (typeof PhoneGap == 'undefined') {

dojo.addOnLoad(callback);

} else {

document.addEventListener("deviceready", callback, false);

}

};

In the main html file I always use dojo.onDeviceReady instead of dojo.ready/dojo.addOnLoad. This works fine for me.

But this only solves a small part of a much larger problem you are faced with when developping a phonegap app. Phonegap offers a quite comprehensive API to access native device functionality (like geo location, accelerometer, local file system etc., see http://docs.phonegap.com/en/1.1.0/index.html). You also need to provide some wrappers for these API functions to make the app portable from normal browser environments to a phonegap environment.

In my phonegap-compat.js file I always do some kind of monkey patching therefore:

(function(){

if (typeof PhoneGap == 'undefined') {

navigator.notification = {};

navigator.notification.alert = function(msg) {

alert(msg);

};

}

})();

So I can always use navigator.notification.alert in the main html file. It then displays a device native dialog in a phonegap environment and a normal browser alert dialog in a browser environment.

But what would be the correct wrapper for an accelerometer call or a call to the device's contact database? Does a single, all-embracing, generic solution exist for these cases as shown in the alert dialog example? I think: no.

Therefore: It remains the question whether it makes really sense to integrate all these things into dojo or to leave these things separated (as shown above) and just set some best-pratice examples (by a tutorial) using the phonegap-compat.js file approach.

All in all: It is still a desideratum of dojox-mobile-documentation, on how to develop, debug, and port an app to phonegap and back to normal browser environments during the development process.

This includes the issue about phonegap's onDeviceReady and dojo.ready.

This includes the problem of the need to do a custom build [So as to ease the development process and cross device testing, I don't use a custom build at the moment. I just delete all unnecessary files in the dojo folder. So the app is about 1MB. But this works fine for me with the iPad.]

This includes the yet unanswered question on how to do a bigger app at the moment with dojox.mobile e.g. for the iPad [You cannot mess all parts of the code into one single html file. A working application controller like dojox.app is still missing and lacks important features, see http://bugs.dojotoolkit.org/ticket/13873. And splitting up the app into several html files is prone to problems, see http://bugs.dojotoolkit.org/ticket/13996.]

comment:7 Changed 8 years ago by Chris Mitchell

we can add has() feature tests for the phonegap api's, so that their use can be guarded in non-pg env's

comment:8 Changed 8 years ago by Chris Mitchell

Summary: Better dojo.ready integration with PhoneGap runtimeBetter dojo/ready and has() integration with PhoneGap runtime

comment:9 Changed 8 years ago by Paul Christopher

I'm not quite sure, if "has"-support is really that useful. As a mobile app developper, you don't want to bloat you code with statments like so:

if(has(nativeAlertBoxSupport)){
  phonegap.alert(msg);
} else {
  alert(msg);
}

You want to keep code size to a minimum. Thus you add some wrappers so as to be able to develop and test your app on a desktop environment, too. But you will throw these wrappers away if you "go mobile". You can do this now, see www.zip - without any changes to dojo core. If you go mobile you simply delete the phonegap-compat.js, but you keep the file on desktop environments. This reduces code size and keeps things separated.

IMHO you don't need a dojo "ready/addOnLoad" support, too. You can easily do that now without bloating the core code of dojo, see www.zip as an example.

Therefore my plead is: Give the app developpers some best-pratice examples (such as www.zip) on how to develop an app and avoid code bloating of the dojo core code.

There might be other frameworks than PhoneGap, that will allow for device-native app development. Do you want to support them, too?

There might be also changes to the PhoneGap API and event system calling for changes in dojo (if ready and has support is built in). Do you really want that?

Dojo you really want to mix up distinct event types, namely dojo.ready on the one hand (DOM-initialization and dependency loading) and deviceReady on the other hand (i.e. the initialization of a foreign javascript library that prepares the device for being accessed and used)?

Last edited 8 years ago by bill (previous) (diff)

comment:10 Changed 8 years ago by bill

Paul, during a mobile specific build

if(has(nativeAlertBoxSupport)){
  phonegap.alert(msg);
} else {
  alert(msg);
}

is converted to

phonegap.alert(msg);

There's no bloating as you have implied. You do need to define your build correctly, listing predefined values for all the has flags.

comment:11 Changed 7 years ago by cjolif

Cc: cjolif added

comment:12 Changed 7 years ago by cjolif

Cc: Eric Durocher added
Owner: set to cjolif
Status: newassigned

comment:13 Changed 7 years ago by cjolif

An option is to provide a specific PhoneGap ready plugin module that application developers can use in conjunction with dojo/ready or alone.

Changed 7 years ago by Eric Durocher

Attachment: 14062.patch added

Add Phonegap support to dojo/ready - Eric Durocher (IBM, CCLA)

comment:14 Changed 7 years ago by Eric Durocher

I am attaching a patch as support for further discussion on this. The patch adds (transparent) Phonegap support in the dojo/ready module: when a Dojo application is wrapped as a Phonegap app, dojo.ready will wait for the 'deviceready' event fired by Phonegap, in addition to the usual "DOM ready" event. This implies the following changes:

  • additional detection of Phonegap in dojo/sniff (as well as BlackBerry? - Android and iOS were already there)
  • new dojo/phonegapReady.js module that implements the callback queue for Phonegap's 'deviceready' event
  • test in dojo/ready to use phonegapRead when phonegap is present.

I realize this is pretty intrusive, any better idea on how to support Phonegap transparently in a less intrusive manner will be very welcome!

comment:15 Changed 7 years ago by Chris Mitchell

i think it's probably more appropriate now to use "cordova" rather than phone gap in these files.

Also, we should add specific has() feature tests for each of the 13 or so phonegap api's...either in sniff or a separate cordovaSniff module.

-Chris

comment:16 Changed 7 years ago by cjolif

If we pick the latest solution the dojo/phonegap(or cordova)Ready plugin should be loaded only when needed by the dojo/ready plugin to avoid forcing its inclusion (i.e. only when has("phonegap") is true) in all cases.

Last edited 7 years ago by cjolif (previous) (diff)

comment:17 Changed 7 years ago by Eric Durocher

@chrism: you are right, if we reach an agreement on the feature I will refactor using 'cordova' as a base name for everything.

@cjolif: this would be better, yes, but this would require to detect phonegap in dojo.js instead of sniff (sniff is not required by dojo/ready currently, so you can only test things that come directly from the config in dojo.js, like "host-browser")... Or require dojo/sniff from dojo/ready? Seems even more intrusive...

comment:18 in reply to:  17 Changed 7 years ago by cjolif

Replying to edurocher:

@cjolif: this would be better, yes, but this would require to detect phonegap in dojo.js instead of sniff (sniff is not required by dojo/ready currently, so you can only test things that come directly from the config in dojo.js, like "host-browser")... Or require dojo/sniff from dojo/ready? Seems even more intrusive...

Well sniff is not required directly by dojo/ready but when you require dojo/phonegapReady in dojo/ready which itself requires dojo/sniff you do require it indirectly? So I don't think requiring it directly is more intrusive than indirectly especially if that avoid requiring phonegapReady when you don't need it?

That said I'm still not fully convinced we should go that far. I would need, as you know, as example of a Dojo application _not_ using phonegap API that fails in phonegap because of our lack of waiting for phonegap events.

comment:19 Changed 7 years ago by pmuellr

I don't understand why Dojo needs to be aware of PhoneGap/Cordova?. Nor vice versa.

What PROBLEM are we trying to fix here? Everything should JUST WORK.

There's a future-looking feature of being able to author Cordova plugins as Dojo modules - we aren't close to there yet, so for now, there are at least two separate module loaders in play (Cordova's and Dojo's), but THIS SHOULDN'T BE A PROBLEM. Every module can only load modules from the loader it was loaded from - and that's not great - but ... basic things should work anyway.

Having said all that - running Dojo 1.7.2 unpatched w/Cordova 1.6.0 on iOS currently "does not work". The Cordova deviceReady does not fire. Comment out Dojo bits of the Cordova app - and everything works. Debugging that now.

Does anyone know why this might be the case? I've instrumented Cordova to death, and now I'm looking at instrumenting Dojo (egads!) so I can figure out what's going on. I'm running with a plain old release, no build, presumably modules loaded async via <script src=> or equivalent.

comment:20 in reply to:  19 Changed 7 years ago by cjolif

Replying to pmuellr:

What PROBLEM are we trying to fix here? Everything should JUST WORK.

First this is not AMD related.

It was reported to us that running a pure Dojo application (no use of PhoneGap APIs) in a PhoneGap container might fail if that application starts before the PhoneGap deviceDetection is ready. Thus the idea of waiting for this event when in a PhoneGap container to start the Dojo application itself.

I must admit (just as you?) I'm skeptical here (see my comment here: http://bugs.dojotoolkit.org/ticket/14062?replyto=19#comment:17) and so I'd like to see an example of how it fails. But if it indeed fails then we obviously have to something to make it work we can't just tell to people: "hey you are in PhoneGap container you need to modify your app for it to work".

Last edited 7 years ago by cjolif (previous) (diff)

comment:21 Changed 7 years ago by cjolif

Milestone: 1.81.9

comment:22 Changed 7 years ago by pmuellr

I've been having some discussions with folks on the issue of "naturally" handling Cordova and Dojo.

I think what we've concluded would be nice would be a deviceReady! plugin that you could use in your define(), require(), etc calls. Since folks seem to be moving to the AMD-style of Dojo usage.

Basically the same as comment:13 from cjolif.

The implementation doesn't need to sniff for cordova at all. Just add the event listener. If you're not using Cordova, presumably it never fires, and ... that should be ok. So the 14062.patch added by edurocher is a little overkill, but I think is the right idea.

So the basic idea of usage would be this, just to make sure we're talking about the same thing.

In your main bit of logic, after you've run the cordova.js script, you can add the deviceReady! plugin to require()s/define()s, which will resolve once deviceReady has fired (or if it already has fired). Just add this wherever you need to depend on Cordova being ready.

Having this separate from domReady is goodness, because they're two separate events, and you don't necessarily need to conflate them. Presumably, domReady will get fired before deviceReady for most platforms today. But that could change tomorrow.

I would recommend the implementation of the deviceReady! plugin actually do a require on domReady! at this point, since nearly everyone uses that pattern today (adding listener for deviceReady in their domReady callback).

comment:23 Changed 7 years ago by cjolif

Cc: pmuellr added

Changed 7 years ago by Richard Backhouse

Attachment: deviceReady.js added

Cordova deviceReady AMD plugin that works in a similar way to dojo/domReady

comment:24 Changed 7 years ago by Richard Backhouse

I have attached a simple deviceReady AMD plugin that follows what Pat was suggesting in comment 22. It has no dependency on any Dojo code and thus should be usable in any AMD environment that wants to use Cordova. It follows the pattern that dojo/domReady uses. An AMD module can use it as follows :

define(['dojo/domReady!','deviceReady!'], function() { .... do something with cordova });

The above assume no namespace for the plugin. It is expected to be found at the root of the application, however there is nothing stopping it being placed in the cordova namespace or the dojo namespace e.g

cordova/deviceReady

or

dojo/deviceReady

I've tried this out on an Android Cordova based app that also loads Dojo via AMD and it appears to work correctly.

comment:25 Changed 7 years ago by cjolif

rbackhouse, thanks for your contribution. You are under IBM CCLA, right?

comment:26 Changed 7 years ago by Richard Backhouse

@cjolif, yes I am

comment:27 Changed 7 years ago by Colin Snover

Milestone: 1.92.0

Current plan is that we are going from 1.8 to 2.0, so bulk reassigning and removing the 1.9 milestone so nobody tries to use it.

comment:28 Changed 7 years ago by Colin Snover

Keywords: 1.9 added

comment:29 Changed 5 years ago by cjolif

Resolution: fixed
Status: assignedclosed

Something like that has been done part of dcordova project (https://github.com/ibm-js/dcordova/blob/master/deviceReady.js) which might be a candidate for dojo 2 so closing this.

Note: See TracTickets for help on using tickets.