Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Wednesday, December 23, 2015

PhoneGap: Detect if running on desktop browser

PhoneGap: Detect if running on desktop browser


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.

Answer by GeorgeW for PhoneGap: Detect if running on desktop browser


Aarons, try

if (PhoneGap.available){      do PhoneGap stuff;  }  

Answer by Ngoc Dao for PhoneGap: Detect if running on desktop browser


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.

Answer by Zougi for PhoneGap: Detect if running on desktop browser


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  }  

Answer by mkirkpatrick for PhoneGap: Detect if running on desktop browser


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

Answer by Rob for PhoneGap: Detect if running on desktop browser


This works for me (running 1.7.0)

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

Tested on desktop Chrome and Safari.

Answer by Wytze for PhoneGap: Detect if running on desktop browser


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                      }                  }              }      }    }  

Answer by andyjamesdavies for PhoneGap: Detect if running on desktop browser


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();  }  

Answer by Zorayr for PhoneGap: Detect if running on desktop browser


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);          }      });  }  

Answer by Yuval for PhoneGap: Detect if running on desktop browser


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

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

var isPhoneGap = ! /^http/.test(document.location.protocol);  

Answer by skybondsor for PhoneGap: Detect if running on desktop browser


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.')     }  

Answer by Austin France for PhoneGap: Detect if running on desktop browser


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.

Answer by cobberboy for PhoneGap: Detect if running on desktop browser


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

Answer by Jim H. for PhoneGap: Detect if running on desktop browser


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 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!      }  }  

Answer by MistereeDevlord for PhoneGap: Detect if running on desktop browser


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.]

Answer by SlavikMe for PhoneGap: Detect if running on desktop browser


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 (cordova || PhoneGap || 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:

    

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. :-)

Answer by Deminetix for PhoneGap: Detect if running on desktop browser


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/

Answer by Al Renaud for PhoneGap: Detect if running on desktop browser


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.

Answer by user1394625 for PhoneGap: Detect if running on desktop browser


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.

Answer by OSP for PhoneGap: Detect if running on desktop browser


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

                     

Ease your work! :)

Answer by B T for PhoneGap: Detect if running on desktop browser


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:

                    

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.

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.