PhoneGap: Detect if running on desktop browser

后端 未结 30 2724
时光取名叫无心
时光取名叫无心 2020-11-29 15:47

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

相关标签:
30条回答
  • 2020-11-29 16:00

    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"));
    }
    
    0 讨论(0)
  • 2020-11-29 16:00

    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();
        }
    });
    
    0 讨论(0)
  • 2020-11-29 16:00

    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 讨论(0)
  • 2020-11-29 16:01

    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.
    0 讨论(0)
  • 2020-11-29 16:01

    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");
    }
    
    0 讨论(0)
  • 2020-11-29 16:01

    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.

    0 讨论(0)
提交回复
热议问题