121

I'm developing a web application that uses PhoneGap:Build for a mobile version and want to have a single codebase for the 'desktop' and mobile versions. I want to be able to detect if PhoneGap calls will work (ie, is the user on a mobile device that will support PhoneGap).

I've searched and cannot believe there is no simple way of doing this. Many people have offered suggestions;

None of which work, unless you remove the PhoneGap Javascript file from the desktop version of the app, which defeats my goal of having one codebase.

So far the only solution I have come up with is browser / user agent sniffing, but this is not robust to say the least. Any better solutions welcome!

EDIT: A marginally better solution is to try calling a PhoneGap function after some small timeout - if it doesn't work, then assume the user is on a desktop web browser.

2
  • Since you're using Build, see @b-t's answer below: stackoverflow.com/a/18478002/241244 . Seems like it might be better than the accepted and top-voted answers.
    – user241244
    Commented Jul 23, 2014 at 0:39
  • I avoid run-time detection in favor of explicit build-time configuration because it's 100% effective. I simply pass a local var to my index.jade template like {isPhonegap: true}, then in the template I can conditionally include the phonegap.js script, and perform all the phonegap specific init I want. Commented Apr 16, 2015 at 19:27

31 Answers 31

117

I use this code:

if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/)) {
  document.addEventListener("deviceready", onDeviceReady, false);
} else {
  onDeviceReady(); //this is the browser
}

UPDATE

There are many other ways to detect if phonegap is running on a browser or not, here is another great option:

var app = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1;
if ( app ) {
    // PhoneGap application
} else {
    // Web page
}  

as seen here: Detect between a mobile browser or a PhoneGap application

9
  • Thanks for this - after waiting a long time to see what other people have suggested, this seems to be the best solution. Cheers. Commented Sep 27, 2012 at 23:51
  • 35
    This is not accurate, because if I will open the same page on the Device's browse, the onDeviceReady() will never call. Plus if I'll change the UserAgent in the browser (for debug purposes), onDeviceReady() will never call either. Commented Nov 6, 2012 at 13:44
  • 3
    Not sure what you're saying - but it seems that you are implying this will cause problems using the phones browser... This is a solution to test on your desktop browser not your phones.
    – sirmdawg
    Commented Nov 7, 2012 at 4:44
  • 7
    This does not help when you open the app in the device browser. Better solution: check for window.cordova. Testing in iPhone Simulator (browser) or on an Android device (browser) should detect PhoneGap, too. That’s the way I develop. But there are a lot of possibilities to get things done. ;-) Thx for posting your solution!
    – Mario
    Commented May 21, 2013 at 10:33
  • I'm confused, what about other platforms like windows phone? Do they have a userAgent that matches that regular expression? A quick google search implies not: madskristensen.net/post/Windows-Phone-7-user-agents.aspx
    – mooreds
    Commented Jun 19, 2013 at 17:25
49

I wrote a post about it a few days ago. This is the best solution you can find (until PhoneGap will release something, maybe or maybe not), it's short, simple and perfect (I've checked it in every possible way and platform).

This function will do the job for 98% of the cases.

/**
 * 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!");
}

To complete the other 2% of the cases, follow these steps (it involves a slight change on native code):

Create a file called __phonegap_index.html, with the source:

<!-- __phonegap_index.html -->
<script type="text/javascript">
    function isPhoneGap() {
        //the function's content is as described above
    }

    //ensure the 98% that this file is called from PhoneGap.
    //in case somebody accessed this file directly from the browser.
    if ( isPhoneGap() )
        localStorage.setItem("isPhoneGap","1");

    //and redirect to the main site file.
    window.location = "index.html";
</script>

Now, on native simply change the start page from index.html to __phonegap_index.html on all your PhoneGap platforms. Let's say my project name is example, the files you need to change are (as for PhoneGap version 2.2.0):

  • iOS - CordovaLibApp/AppDelegate.m
  • Android - src/org/apache/cordova/example/cordovaExample.java
  • Windows 8 - example/package.appxmanifest
  • BlackBerry - www/config.xml
  • WebOS - framework/appinfo.json
  • Bada - src/WebForm.cpp (line 56)
  • Window Phone 7 - No idea where (somebody still developing on that platform?!)

Finally, you can use it anywhere on your site, if it's running on PhoneGap or not:

if ( localStorage.getItem("isPhoneGap") ) {
    alert("Running on PhoneGap!");
} else {
    alert("Not running on PhoneGap!");
}

Hope it helps. :-)

9
  • 4
    Found this answer to be the best!
    – blong824
    Commented Feb 5, 2013 at 20:09
  • 3
    yes it works but some times the next part of code is not true /^file:\/{3}[^\/]/i.test(window.location.href) but we are using PhoneGap, for example when loading the index.html from another page, on config.xml something like this <content src="http://10.100.1.147/" />
    – vudduu
    Commented Sep 23, 2013 at 16:18
  • 3
    The expression (cordova || PhoneGap || phonegap) will throw a ReferenceError if any of those variables are not defined. You should test with typeof cordova !== undefined, right? Commented Mar 6, 2015 at 22:05
  • 1
    @rblakeley you are right. I switched the first line to: return ( typeof cordova !== undefined || typeof PhoneGap !== undefined || typeof phonegap !== undefined )
    – ethanpil
    Commented Mar 10, 2015 at 8:46
  • 1
    @rojobuffalo: Looks like the answer has since been modified, making it work as expected again (i.e. it does not throw a ReferenceError anymore due to the window prefix). Just thought I'd point this out, since this actually makes the comment chain outdated (and thus, incorrect). Commented Mar 31, 2017 at 11:03
27

I know it's been answered a while ago but "PhoneGap.available" doesn't exist anymore. You should use:

if (window.PhoneGap) {
  //do stuff
}

or since 1.7, prefer:

if (window.cordova) {
  //do stuff
}

EDIT 2019: as said in the comments, this only works if you do not include cordova lib into your desktop browser build. And of course it is a good practice to include only the strict minimum javascript/html/css files for each device you target

6
  • 18
    This is not true, because window.PhoneGap or window.cordova will allway be defined if you include the script cordova-x.x.x.js, even if it's loaded on browser. Commented Nov 6, 2012 at 13:39
  • Can you help with me an example.To simply load the index.html.What i am doing is that i have uploaded all the files under the www folder in my local server,I am loading the index.html.But the device on ready is not fired.
    – Nassif
    Commented Jun 25, 2013 at 4:37
  • 5
    This appears to be the correct answer now (with Cordova 3.4, at least). All the other methods are just a waste of time since cordova.js is injected into application with a simple <script type="text/javascript" src="cordova.js"></script> now. You don't actually point to the real file, so it doesn't get loaded when running in a browser. It's only there in a Cordova build running on a mobile device. Commented May 3, 2014 at 23:21
  • This seems like it would work particularly well if using PhoneGap Build.
    – user241244
    Commented Jul 23, 2014 at 0:24
  • 4
    @SlavikMe Don't include the cordova script in non-cordova builds. Commented Oct 7, 2014 at 23:24
22

The most trustable way we found to tell if we are in a cordova/phonegap application is to modify the cordova application's user agent using this config AppendUserAgent.

In config.xml add:

<preference name="AppendUserAgent" value="Cordova" />

Then call:

var isCordova = navigator.userAgent.match(/Cordova/i))

Why?

  1. window.cordova and document.addEventListener('deviceready', function(){}); are subject to racing conditions
  2. navigator.standalone does not work when <content src="index.html" /> is a website (Ex: <content src="https://www.example.com/index.html" /> or with cordova-plugin-remote-injection)
  3. Trying to whitelist user agents to guess if it is a real browser is very complicated. Android browsers are often custom webviews.
3
  • 2
    And we can even add the application version there! (ideally with some automated version bump logic) ex; Cordova AppName/v0.0.1 <3 So this way, you can even somehow use this for tracking (but note that anyone can modify its useragent so don't rely on this for security critical verifications)
    – GabLeRoux
    Commented Nov 11, 2016 at 18:59
  • This seems to be the most foolproof method. Second runner up seems to be testing for the absence of http:// or https:// in the document URL, but I can envision possible scenarios where that would not work.
    – JD Smith
    Commented Feb 3, 2020 at 17:44
  • This was the one that worked for me after all. Thank you! Commented Jun 3, 2021 at 8:59
14

I think this is simplest: var isPhoneGap = (location.protocol == "file:")

EDIT For some people that didn't work. Then you might try (haven't tested)

var isPhoneGap = ! /^http/.test(location.protocol);
9
  • 1
    I thought PhoneGap ran an internal server for all it's on-device files? Commented Oct 9, 2012 at 0:40
  • I like it. When developing on localhost, this is the best solution. (After trying a lot, I hope this works in all scenarios, hopefully.) Thx!
    – Mario
    Commented May 21, 2013 at 16:55
  • 1
    this doesn't work in the ripple emulator when I'm testing a remote file Commented Oct 16, 2013 at 23:38
  • Also doesn't work in WP8, protocol is "x-wmapp0:". Can't know for certain what other "protocols" will be used in the future.
    – Adrian
    Commented May 31, 2014 at 5:13
  • Well, you could also --try var isPhoneGap = ! /^http/.test(document.location.protocol)
    – Yuval
    Commented Sep 20, 2014 at 16:34
8

This works for me (running 1.7.0)

if (window.device) {
  // Running on PhoneGap
}

Tested on desktop Chrome and Safari.

3
  • 3
    This is almost the same as binding to the 'deviceready' event. If window.device is not defined, you can't tell if phonegap/cordova is slow in loading or if the event is never going to fire.
    – Wytze
    Commented May 23, 2012 at 10:36
  • 8
    window.device is not defined before the "deviceready" event triggered. Commented Nov 6, 2012 at 13:37
  • 2
    And pray that no other programmer has the happy idea of defining a new global var called "device". Commented Jun 4, 2013 at 14:42
7

Like the original poster, I'm using the phonegap build service. After two days and nearly 50 test builds, I've come up with an elegant solution that works great for me.

I couldn't use UA sniffing because I wanted to test and run in mobile browsers. I had originally settled on cobberboy's quite functional technique. This didn't work for me because the "howPatientAreWe: 10000" delay/timeout was too much of a nuisance for in-browser development. And setting it any lower would occasionally fail the test in app/device mode. There had to be another way...

The phonegap build service requires the phonegap.js file be omitted from your code repository before submitting your app's files to the service. Therefore I'm able to test for its existence to determine if running in a browser vs. app.

One other caveat, I'm also using jQueryMobile, so both jQM and phonegap had to initialize before I could begin any custom scripting. The following code is placed at the beginning of my custom index.js file for the app (after jQuery, before jQM). Also the phonegap build docs say to place <script src="phonegap.js"></script> somewhere in the HTML. I leave it out completely and load it using $.getScript() to facility testing its existence.

isPhoneGap = false;
isPhoneGapReady = false;
isjQMReady = false;

$.getScript("phonegap.js")
.done(function () {
    isPhoneGap = true;
    document.addEventListener("deviceready", function () {
        console.log("phonegap ready - device/app mode");
        isPhoneGapReady = true;
        Application.checkReadyState();
    }, false);
})
.fail(function () {
    console.log("phonegap load failed - browser only");
    isPhoneGapReady = true;
    Application.checkReadyState();
});

$(document).bind("mobileinit", function () {
    Application.mobileInit();
    $(document).one("pageinit", "#Your_First_jQM_Page", function () {
        isjQMReady = true;
        Application.checkReadyState();
    });
});

Application = {
    checkReadyState: function () {
        if (isjQMReady && isPhoneGapReady) {
            Application.ready();
        }
    },
    mobileInit: function () {
        // jQM initialization settings go here
        // i.e. $.mobile.defaultPageTransition = 'slide';
    },
    ready: function () {
        // Both phonegap (if available) and jQM are fired up and ready
        // let the custom scripting begin!
    }
}
0
6

Interestingly, many answers, but they don't include these three options:

1 – The cordova.js will set the cordova object in the global scope. If it is there then you are most likely running in a Cordova scope.

var isCordovaApp = !!window.cordova;

2 – Cordova will run your application as you would open a HTML document from your Desktop. Instead of the HTTP protocol it will use FILE. Detecting this will give you a chance to assume that your app was loaded locally.

var isCordovaApp = document.URL.indexOf('http://') === -1
  && document.URL.indexOf('https://') === -1;

3 – Use the load event of the cordova script to detect the context. The script include can be easily removed in the build process or the script loading will simply fail in a browser. So that this global variable will not be set.

<script src="../cordova.js" onload="javascript:window.isCordovaApp = true;"></script>

Credit goes to Damien Antipa from Adobe

5

I use this method:

debug = (window.cordova === undefined);

debug will be true on the browser environment, false on the device.

4

This seems to be viable and I have used it in production:

if (document.location.protocol == "file:") {
    // file protocol indicates phonegap
    document.addEventListener("deviceready", function() { $(initInternal);} , false);
}
else {
    // no phonegap, start initialisation immediately
    $(initInternal);
}

Source: http://tqcblog.com/2012/05/09/detecting-phonegap-cordova-on-startup/

3

The essence of the problem is that so long as cordova.device is undefined, your code can't be sure if that's because cordova has established that your device is not supported, or if it's because cordova is still preparing itself and deviceready will fire later (or third option: cordova didn't load properly).

The only solution is to define a waiting period, and to decide that after this period your code must assume the device is not supported. I wish cordova would set a parameter somewhere to say "We've tried finding a supported device and given up" but it seems like there is no such parameter.

Once this is established, you may want to do something specific precisely in those situations where there is no supported device. Like hiding links to the device's app market, in my case.

I've pieced together this function which should cover pretty much every situation. It lets you define a deviceready handler, a device-never-ready handler, and a waiting time.

//Deals with the possibility that the code will run on a non-phoneGap supported
//device such as desktop browsers. Gives several options including waiting a while
//for cordova to load after all.
//In:
//onceReady (function) - performed as soon as deviceready fires
//patience 
//  (int) - time to wait before establishing that cordova will never load
//  (boolean false) - don't wait: assume that deviceready will never fire
//neverReady 
//  (function) - performed once it's established deviceready will never fire
//  (boolean true) - if deviceready will never fire, run onceReady anyhow
//  (boolean false or undefined) - if deviceready will never fire, do nothing
function deviceReadyOrNot(onceReady,patience,neverReady){

    if (!window.cordova){
            console.log('Cordova was not loaded when it should have been')
            if (typeof neverReady == "function"){neverReady();}
        //If phoneGap script loaded...
        } else {
            //And device is ready by now...
            if  (cordova.device){
                callback();
            //...or it's loaded but device is not ready
            } else {
                //...we might run the callback after
                if (typeof patience == "number"){
                    //Run the callback as soon as deviceready fires
                    document.addEventListener('deviceready.patience',function(){
                        if (typeof onceReady == "function"){onceReady();}
                    })
                    //Set a timeout to disable the listener
                    window.setTimeout(function(){
                        //If patience has run out, unbind the handler
                        $(document).unbind('deviceready.patience');
                        //If desired, manually run the callback right now
                        if (typeof neverReady == 'function'){neverReady();}
                    },patience);
                //...or we might just do nothing
                } else {
                    //Don't bind a deviceready handler: assume it will never happen
                    if (typeof neverReady == 'function'){neverReady();} 
                    else if (neverReady === true){onceReady();} 
                    else {
                       //Do nothing
                    }
                }
            }
    }

}
3

The way I'm doing it with is using a global variable that is overwritten by a browser-only version of cordova.js. In your main html file (usually index.html) I have the following scripts that are order-dependent:

    <script>
        var __cordovaRunningOnBrowser__ = false
    </script>
    <script src="cordova.js"></script> <!-- must be included after __cordovaRunningOnBrowser__ is initialized -->
    <script src="index.js"></script> <!-- must be included after cordova.js so that __cordovaRunningOnBrowser__ is set correctly -->

And inside cordova.js I have simply:

__cordovaRunningOnBrowser__ = true

When building for a mobile device, the cordova.js will not be used (and instead the platform-specific cordova.js file will be used), so this method has the benefit of being 100% correct regardless of protocols, userAgents, or library variables (which may change). There may be other things I should include in cordova.js, but I don't know what they are yet.

3
  • Very interesting approach.
    – user241244
    Commented Jul 23, 2014 at 0:32
  • Though, you don't really need the initial script. You could just test for it being set at all: if ( typeof __cordovaRunningOnBrowser__ !== 'undefined' ) { stuff(); } ..right?
    – user241244
    Commented Jul 23, 2014 at 0:59
  • Right, tho it being undefined might indicate something else is wrong.
    – B T
    Commented Jul 24, 2014 at 17:55
3

Another way, based on SlavikMe's solution:

Just use a query parameter passed to index.html from your PhoneGap source. Ie, in Android, instead of

super.loadUrl("file:///android_asset/www/index.html");

use

super.loadUrl("file:///android_asset/www/index.html?phonegap=1");

SlavikMe has a great list on where to do this on other platforms.

Then your index.html can simply do this:

if (window.location.href.match(/phonegap=1/)) {
  alert("phonegap");
}
else {
  alert("not phonegap");
}
1
  • 1
    I'm using Cordova 3.4.1 and there it's even simpler: You only need to change the <content src="index.html" /> option in the config.xml file to <content src="index.html?cordova=1" />. So far it seems to work and is by far the best solution suggested here.
    – Martin M.
    Commented May 22, 2014 at 20:40
2

To keep one codebase, what's of interest is the "platform" the code is running on. For me this "platform" can be three different things:

  • 0: computer-browser
  • 1: mobile-browser
  • 2: phonegap/cordova

The way to check for the platform:

var platform;
try {
 cordova.exec(function (param) {
   platform = 2;
  }, function (err) {}, "Echo", "echo", ["test"]);
} catch (e) {
  platform = 'ontouchstart' in document.documentElement ? 1 : 0;
}

Note:

  • This has to be run only after cordova.js has been loaded (body onload(...), $(document).ready(...))

  • 'ontouchstart' in document.documentElement will be present in laptops and desktop monitors that have a touch-enabled screen so it would report a mobile-browser even though it is a desktop. There are different ways to make a more precise check but I use it because it still takes care of 99% of the cases I need. You can always substitute that line for something more robust.

1
  • 1
    I suggest using typeof cordova !== 'undefined' instead of fishing for an exception.
    – krakatoa
    Commented Mar 25, 2014 at 17:21
1

Aarons, try

if (PhoneGap.available){
    do PhoneGap stuff;
}
1
  • No, I did not. Look at the phonegap-1.1.0.js source code. PhoneGap.available = DeviceInfo.uuid !== undefined;
    – GeorgeW
    Commented Jan 28, 2012 at 2:00
1

GeorgeW's solution is OK, but even on real device, PhoneGap.available is only true after PhoneGap's things has been loaded, e.g. onDeviceReady in document.addEventListener('deviceready', onDeviceReady, false) has been called.

Before that time, if you want to know, you can do like this:

runningInPcBrowser =
    navigator.userAgent.indexOf('Chrome')  >= 0 ||
    navigator.userAgent.indexOf('Firefox') >= 0

This solution assumes that most developers develop using Chrome or Firefox.

1
  • OP is looking for a solution for a production website, not just dev. Commented Oct 16, 2013 at 23:45
1

I have the same issue.

I am leaning towards adding #cordova=true to the URL loaded by the cordova client and testing for location.hash.indexOf("cordova=true") > -1 in my web page.

1
  • In the end, I went the route suggested by Al Renaud in his 4th point, and let the build script decide. It uncomments a flag in index.html when copying the website code into the android assets folder. // UNCOMMENT-ON-DEPLOY: window._appInfo.isCordova = true; When the build script copies index.html into my android assets/www folder, I run ed on it to remove the // UNCOMMENT-ON-DEPLOY: string. # Massage index.html to tell it is running cordova ed "$DEST/index.html" <<-EOF 1,\$s/\/\/ UNCOMMENT-ON-DEPLOY: // w q EOF Commented Jan 30, 2013 at 10:11
1

The following works for me with the most recent PhoneGap / Cordova (2.1.0).

How it works:

  • Very simple in concept
  • I inverted the logic of some of the above timeout solutions.
  • Register for the device_ready event (as recommended by the PhoneGap docs )
    • If the event has still NOT fired after a timeout, fallback to assuming a browser.
    • In contrast, the other solutions above rely on testing some PhoneGap feature or other, and watching their test break.

Advantages:

  • Uses the PhoneGap-recommended device_ready event.
  • The mobile app has no delay. As soon as the device_ready event fires, we proceed.
  • No user-agent sniffing (I like testing my app as a mobile website so browser sniffing wasn't an option for me).
  • No reliance on undocumented (and therefore brittle) PhoneGap features/properties.
  • Keep your cordova.js in your codebase even when using a desktop or mobile browser. Thus, this answers the OP's question.
  • Wytze stated above: 'I wish cordova would set a parameter somewhere to say "We've tried finding a supported device and given up" but it seems like there is no such parameter.' So I provide one here.

Disadvantages:

  • Timeouts are icky. But our mobile-app logic doesn't rely on a delay; rather, it is used as a fallback when we're in web-browser mode.

==

Create a brand new blank PhoneGap project. In the provided sample index.js , replace the "app" variable at the bottom with this:

var app = {
    // denotes whether we are within a mobile device (otherwise we're in a browser)
    iAmPhoneGap: false,
    // how long should we wait for PhoneGap to say the device is ready.
    howPatientAreWe: 10000,
    // id of the 'too_impatient' timeout
    timeoutID: null,
    // id of the 'impatience_remaining' interval reporting.
    impatienceProgressIntervalID: null,

    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // `load`, `deviceready`, `offline`, and `online`.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
        // after 10 seconds, if we still think we're NOT phonegap, give up.
        app.timeoutID = window.setTimeout(function(appReference) {
            if (!app.iAmPhoneGap) // jeepers, this has taken too long.
                // manually trigger (fudge) the receivedEvent() method.   
                appReference.receivedEvent('too_impatient');
        }, howPatientAreWe, this);
        // keep us updated on the console about how much longer to wait.
        app.impatienceProgressIntervalID = window.setInterval(function areWeThereYet() {
                if (typeof areWeThereYet.howLongLeft == "undefined") { 
                    areWeThereYet.howLongLeft = app.howPatientAreWe; // create a static variable
                } 
                areWeThereYet.howLongLeft -= 1000; // not so much longer to wait.

                console.log("areWeThereYet: Will give PhoneGap another " + areWeThereYet.howLongLeft + "ms");
            }, 1000);
    },
    // deviceready Event Handler
    //
    // The scope of `this` is the event. In order to call the `receivedEvent`
    // function, we must explicity call `app.receivedEvent(...);`
    onDeviceReady: function() {
        app.iAmPhoneGap = true; // We have a device.
        app.receivedEvent('deviceready');

        // clear the 'too_impatient' timeout .
        window.clearTimeout(app.timeoutID); 
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        // clear the "areWeThereYet" reporting.
        window.clearInterval(app.impatienceProgressIntervalID);
        console.log('Received Event: ' + id);
        myCustomJS(app.iAmPhoneGap); // run my application.
    }
};

app.initialize();

function myCustomJS(trueIfIAmPhoneGap) {
    // put your custom javascript here.
    alert("I am "+ (trueIfIAmPhoneGap?"PhoneGap":"a Browser"));
}
1

I've stumbled on this problem several months ago when beginning our app, because we wanted the app to be "browser-compatible" also (with the understanding that some functionality would be blocked in that scenario: audio recording, compass, etc.).

The only 100% (and I insist on the 100-hundred-percent condition) solution to PRE-determine the app execution context was this:

  • initialize a JS "flag" variable to true, and change it to false when in an all-web context;

  • therefore you can use a call like "willIBeInPhoneGapSometimesInTheNearFuture()" (that's PRE-PG, of course you still need a POST-PG method of checking if you can call PG APIs, but that one is trivial).

  • Then you say: "but how do you determine the execution context?"; the answer is: "you don`t" (because I don't think you can reliably, unless those brilliant folks at PG would do it in their API code);

  • you write a build script that does it for you: one codebase with two variants.

1

Not really an answer to the question, butwhen I test in a desktop browser, I just set a localstorage value to make the browser load the app dispite deviceready not fireing.

function main() {

    // Initiating the app here.
};

/* Listen for ready events from pheongap */
document.addEventListener("deviceready", main, false);

// When testing outside ipad app, use jquerys ready event instead. 
$(function() {

    if (localStorage["notPhonegap"]) {

        main();
    }
});
1

None of which work, unless you remove the PhoneGap Javascript file from the desktop version of the app, which defeats my goal of having one codebase.

Another option would be to use merges folder, see screenshot below.

You can add platform-specific files / override default ones.

(it should do the trick in some scenarios)

enter image description here


In other words: Rather than detecting the browser, you just don't include certain files for desktop build / attach certain files for iOS only.

1

Detect desktop browser even if emulate device is active

Works in Windows and Mac machines. Need to find a solution for linux View details

var mobileDevice = false;
if(navigator.userAgent.match(/iPhone|iPad|iPod|Android|BlackBerry|IEMobile/))
    mobileDevice = true; 

if(mobileDevice && navigator.platform.match(/Win|Mac/i))
    mobileDevice = false; // This is desktop browser emulator

if(mobileDevice) {
    // include cordova files
}
0

I've actually found a combination of two of the techniques listed here has worked the best, firstly check that cordova / phonegap can be accessed also check if device is available. Like so:

function _initialize() {
    //do stuff
}

if (window.cordova && window.device) {
    document.addEventListener('deviceready', function () {
      _initialize();
    }, false);
} else {
   _initialize();
}
0

Try this approach:

/**
 * Returns true if the application is running on an actual mobile device.
 */
function isOnDevice(){
    return navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/);
}

function isDeviceiOS(){
    return navigator.userAgent.match(/(iPhone)/);
}

/**
 * Method for invoking functions once the DOM and the device are ready. This is
 * a replacement function for the JQuery provided method i.e.
 * $(document).ready(...).
 */
function invokeOnReady(callback){
    $(document).ready(function(){
        if (isOnDevice()) {
            document.addEventListener("deviceready", callback, false);
        } else {
            invoke(callback);
        }
    });
}
0

I use a combination of what GeorgeW and mkprogramming suggested:

   if (!navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/)) {
      onDeviceReady();
   } else if (Phonegap.available){
      onDeviceReady();
   } else {
      console.log('There was an error loading Phonegap.')
   }
0

I guess in someways they aren't that different are they? Ha Ha... not funny. Who didn't think this wouldn't be a problem? Here's the simplest solution for your considerations. Push different files to your server then you do to PhoneGap. I'd also temporarily go with the http: check suggested above.

var isMobileBrowserAndNotPhoneGap = (document.location.protocol == "http:");

My interest is in pushing the browsers navbar up, so really I can just delete the isolated script's tag and press rebuild [in DW] (they'll be some cleanup for deployment anyway so this can be one of those tasks.) Anyway I feel it's a good option (considering not much else is available) to efficiently just manually comment out things with isMobileBrowserAndNotPhoneGap when pushing to PG). Again for me in my situation I will simple delete the tag for the (isolated code) file that pushes up the navbar when it's a mobile browser (it will be that much faster and smaller). [So ya if you can isolated the code for that optimized but manual solution.]

0

Slightly modified, but works for me perfectly without any issues.

Intent is to load Cordova only when on embedded device, not on a desktop, so I completely avoid cordova on a desktop browser. Testing and development of the UI and MVVM and so is then very comfortable.

Put this code eg. in file cordovaLoader.js

function isEmbedded() {
    return  
    // maybe you can test for better conditions
    //&& /^file:\/{3}[^\/]/i.test(window.location.href) && 
     /ios|iphone|ipod|ipad|android/i.test(navigator.userAgent);
}

if ( isEmbedded() )
{
   var head= document.getElementsByTagName('head')[0];
   var script= document.createElement('script');
   script.type= 'text/javascript';
   script.src= 'cordova-2.7.0.js';
   head.appendChild(script);
}

Then instead of including cordova javascript itself include cordovaLoader.js

<head>
  <script src="js/cordovaLoader.js"></script>
  <script src="js/jquery.js"></script>
  <script src="js/iscroll.js"></script>
  <script src="js/knockout-2.3.0.js"></script>
</head> 

Ease your work! :)

0
if ( "device" in window ) {
    // phonegap
} else {
    // browser
}
0

Just for info the way in PhoneGap 3.x Mobile Application Development Hotshot

var userLocale = "en-US";
function startApp()
{
// do translations, format numbers, etc.
}
function getLocaleAndStartApp()
{
    navigator.globalization.getLocaleName (
        function (locale) {
            userLocale = locale.value;
            startApp();
        },
        function () {
            // error; start app anyway
            startApp();
        });
}
function executeWhenReady ( callback ) {
    var executed = false;
    document.addEventListener ( "deviceready", function () {
        if (!executed) {
            executed = true;
            if (typeof callback === "function") {
                callback();
            }
        }
    }, false);
    setTimeout ( function () {
        if (!executed) {
            executed = true;
            if (typeof callback === "function") {
                callback();
            }
        }
    }, 1000 );
};
executeWhenReady ( function() {
    getLocaleAndStartApp();
} );

and in YASMF framework

https://github.com/photokandyStudios/YASMF-Next/blob/master/lib/yasmf/util/core.js#L152

0

I was trying with the window objects but it didn't worked as I was opening the remote url in the InAppBrowser. Couldn't get it done. So the best and easiest way to achieve it was to append a string to the url which you need to open from the phonegap app. Then check if the document location has string appended to it.

Below is the simple code for it

var ref = window.open('http://yourdomain.org#phonegap', '_blank', 'location=yes');

You will see a string is added to the url "#phonegap".So in the domain url add the following script

if(window.location.indexOf("#phonegap") > -1){
     alert("Url Loaded in the phonegap App");
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.