PhoneGap – Detect if an app runs on a mobile or browser using JavaScript

PhoneGap – Detect if an app runs on a mobile or browser using JavaScript

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

So I wrote my own solution. It appear that there is a very simple way to achieve this. After the event deviceready has been triggered (as described on the PhoneGap’s API Docs), all you have to do is:

document.addEventListener("deviceready", function(e){
    if ( device ) {
        alert("Running on PhoneGap!");
    } else {
        alert("Not Running on PhoneGap!");
    }
}, false);

When the deviceready event is being triggered, it tell us that all native components are loaded and are ready to use. Which means, that there is no way to determine whether the page was loaded from PhoneGap or not, using the PhoneGap plugin itself.

You can always test against browser’s User Agent, but it isn’t a good verification, because it is always possible to open this same page through mobile’s browser, that have the same User Agent as the one that has been loaded from PhoneGap.

Let’s give a typical example, that describes the case better.
Let’s say that I want to perform an action when the device is ready and the document is ready.
Of course, you can do this using old-fashioned way, like counters, event inside event or maybe other creative ways.
Well, they will all work, but mostly with complications, and all of them rely on events, which brings us to the initial problem.

With a little thinking and testing, I found that there is a difference between environments. The URI that loads the HTML file from PhoneGap is different from the one that is loaded outside of PhoneGap (but still on mobile device).

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

The URI that is loaded outside of PhoneGap looks like this: http://some.domain.com/some/path/index.html

The major difference, is the protocol. PhoneGap uses a local file URI, whereas the browser uses the HTTP, HTTPS or maybe even an FTP protocol, but never a FILE protocol.

Now, the work is even easier than I thought. All I have to do is check whether the protocol is file:

if ( window.location.protocol === "file:" ) {
    alert("Running on PhoneGap!");
} else {
    alert("Not Running on PhoneGap!");
}

But, now there’s another problem. What if I open the index.html file in a browser, locally from my PC, or even on my mobile davice using some other way? The protocol will also be file. Since it’s not loaded from PhoneGap, the script will pass and it will detect as we have loaded it from PhoneGap, not what we need.

However, I mentioned a slight difference between the two URIs, the one loaded from PhoneGap looks like this: file:///.../index.html, and the one loaded outside from PhoneGap looks like this: file://.../index.html or like this file:////.../index.html (depends on the browser).
Note, that there is a difference in the number of slashes after the protocol. 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 loaded from where.

Let’s compound all ways and hints together and write the full test case.

  1. There is a constant in a window scope that indicates whether it is running in a PhoneGap context.
  2. Verify the file protocol.
  3. Verify the number of slashes after the file protocol.
  4. Verify that the page is running on a mobile device.

The following function covers them all:

/**
* 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("Not Running on PhoneGap!");
}

This is very useful, especially if you are developing a hybrid application for a mobile using PhoneGap, and you are not always want to use the emulator/simulator, but test it on the browser.

Hope it saves 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 in the comments.

12 comments

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?

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

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

That’s it.
Good luck!

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)

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

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:


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.