RSS
 

PhoneGap – Detect if the application runs on mobile or browser using JavaScript before the “deviceready” and document “ready” events are triggered

05 Nov

I spent hours to find out how to do it. And believe me or not, I found nothing on the whole internet about how to solve it.

Actually there is a simple way to do that after the event “deviceready” has been triggered (as described on the PhoneGap’s API Docs), it is simple as:

1
2
3
4
5
6
7
document.addEventListener("deviceready", function(e){
if ( device ) {
alert("Running on PhoneGap!");
} else {
alert("Running NOT on PhoneGap!");
}
}, false);


The “deviceready” trigger, tell us when all native components are loaded and ready to use. Which means, that there is no way to determine whether the page loaded from PhoneGap or not using the PhoneGap plugin itself. You can check the UserAgent, but it is not always true, because it is possible to open the page through the mobile’s browser which is the same UserAgent as loaded from PhoneGap.

Let’s give a typical example, that describes the case better. Let’s say I want to perform an action when the device is ready and the document is ready, both together. Of course you can do this using old-fashioned way, like using counters, event inside event or other creative ways.
Well, they will all work, but with a lot of complications and code, and all of them relies on events, which is not what I need.

With a little thinking and testing, I found a difference between the environments. The URL that loading the HTML file from PhoneGap is different from the one loaded not from PhoneGap.

The URL loaded from PhoneGap looks like this:
(iPhone) file:///var/mobile/Applications/.../App.app/www/index.html
(Android) file:///android_asset/www/index.html

The URL that is loaded NOT from PhoneGap looks like this: http://www.myappsite.com/index.html

See the difference? That’s right! the protocols are different.

So, basically it’s easy now, right? The script should be as follows:

1
2
3
4
5
if ( window.location.protocol === "file:" ) {
alert("Running on PhoneGap!");
} else {
alert("Running NOT on PhoneGap!");
}

But, there’s another problem. What if I opened an HTML file from some folder on my PC? It opens the file using default browser, and the protocol is also “file:”, but it’s not loaded from PhoneGap, and the script will pass not to the right section, not the one we needed, that’s bad.

However, I mentioned a slight difference between the two URLs, the one is loaded from PhoneGap looks like this: file:///.../index.html, and the one loaded not from PhoneGap looks like this: file://.../index.html or like this file:////.../index.html (depends on the browser).

See the difference again? The number of slashes after the protocol is different. Somehow the local files on the mobile got three slashes compared to two or four on the PC. For me that’s enough to determine who is who and what is what. So, my final script to perform this check is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Determine whether the file loaded from PhoneGap or not
*/

function isPhoneGap() {
return (window.cordova || window.PhoneGap || window.phonegap)
&& /^file:\/{3}[^\/]/i.test(window.location.href)
&& /ios|iphone|ipod|ipad|android/i.test(navigator.userAgent);
}

if ( isPhoneGap() ) {
alert("Running on PhoneGap!");
} else {
alert("Running NOT on PhoneGap!");
}

This is very useful, especially if you developing a hybrid application for mobile running PhoneGap, and you not always wish to use the phone emulator/simulator, but Chrome or Safari.

Hope it saved someones time and headache. :-)
Good Luck!

—-
Update:
Note, that this article is talking about testing environment when the developing process includes a local server.
This will not work on remote files! To make it work on remote files, please see my reply to a similar question below.

 

Tags: , , , , , , , , , , , , , , , , , , , , , , , ,

Leave a Reply

 

 
  1. Ariel

    November 25, 2012 at 09:37

    Great stuff! very helpful! :)

     
    • Slavik Meltser

      November 26, 2012 at 21:24

      I’m glad.

       
  2. Edgarin

    September 23, 2013 at 18:26

    Hi, I have a phonegap application that loads a remote url, so it does not use the file protocol.
    How can I deal with that case?

     
    • Slavik Meltser

      September 23, 2013 at 21:03

      Just add a hash to the URL you call on your PhoneGap application.
      Lets say the hash you adding is “#phonegap”.
      Then in your remote page, write your detection:

      1
      2
      3
      4
      5
      if ( window.location.hash === "#phonegap" ) {
          alert("Running on PhoneGap!");
      } else {
          alert("Running NOT on PhoneGap!");
      }

      That’s it.
      Good luck!

       
  3. louis

    April 15, 2014 at 12:50

    Hi I get a “cordova is not defined” with your code. Do youknow why ?
    Thanks

     
    • Slavik Meltser

      April 16, 2014 at 17:49

      Hi Louis,

      Thank you for letting me know about the issue.
      I’ve updated the code that fixes the problem (see line 5), just replace the line with this one:
      return (window.cordova || window.PhoneGap || window.phonegap)

       
  4. louis

    April 16, 2014 at 10:28

    Hi Slavik, on this line
    return (cordova || PhoneGap || phonegap)
    the “.test()” is missing, right ,

     
  5. Håkan Öström

    September 8, 2014 at 21:17

    Loading the HTML page directly in browser will yield three slashes for me, both on mac and windows. So the protocol-test is not bullet-proof imho.
    But I figured the hash-way can also be used on the starting page of the phonegap app, since config.xml specifies how phonegap should load. Like so:
    <content src=”index.html#phonegap” />