PhoneGap: обнаружение при работе в настольном браузере - PullRequest
116 голосов
/ 09 ноября 2011

Я занимаюсь разработкой веб-приложения, которое использует PhoneGap: сборка для мобильной версии и хочу иметь одну кодовую базу для «настольной» и мобильной версий. Я хочу быть в состоянии определить, будут ли работать вызовы PhoneGap (т. Е. Пользователь на мобильном устройстве, которое будет поддерживать PhoneGap).

Я искал и не могу поверить, что не существует простого способа сделать это. Многие люди предлагали свои предложения;

Ничего из этого не работает, если только вы не удалите файл PhoneGap Javascript из настольной версии приложения, что противоречит моей цели иметь одну кодовую базу.

Пока что единственное решение, которое я придумала, - это анализировать браузер / пользовательский агент, но это, по меньшей мере, не надежно. Любые лучшие решения приветствуются!

РЕДАКТИРОВАТЬ: Немного лучшим решением является попытка вызова функции PhoneGap после небольшого тайм-аута - если он не работает, то предположим, что пользователь находится в настольном веб-браузере.

Ответы [ 31 ]

3 голосов
/ 23 мая 2012

Суть проблемы заключается в том, что до тех пор, пока cordova.device не определен, ваш код не может быть уверен в том, что это связано с тем, что cordova установила, что ваше устройство не поддерживается, или потому, что cordova все еще готовится и устройство ужесработает позже (или третий вариант: cordova не загрузился должным образом).

Единственное решение - определить период ожидания и решить, что после этого периода ваш код должен предполагать, что устройство не поддерживается.Я бы хотел, чтобы Кордова установила параметр где-нибудь, чтобы сказать: «Мы попытались найти поддерживаемое устройство и отказались», но похоже, что такого параметра нет.

Как только это установлено, вы можете захотеть что-то сделатьКонкретно именно в тех ситуациях, когда нет поддерживаемого устройства.В моем случае, как сокрытие ссылок на рынок приложений устройства.

Я собрал эту функцию, которая должна охватывать практически все ситуации.Он позволяет вам определить обработчик устройства, устройство никогда не готовое и время ожидания.

//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 голосов
/ 17 сентября 2013

Другой способ, основанный на решении SlavikMe:

Просто используйте параметр запроса, переданный в index.html из вашего источника PhoneGap.То есть в Android вместо

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

используйте

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

SlavikMe имеет большой список того, где это можно сделать на других платформах.* можно просто сделать это:

if (window.location.href.match(/phonegap=1/)) {
  alert("phonegap");
}
else {
  alert("not phonegap");
}
3 голосов
/ 28 августа 2013

Я использую глобальную переменную, которая перезаписывается версией cordova.js только для браузера.В вашем основном HTML-файле (обычно index.html) у меня есть следующие сценарии, которые зависят от порядка:

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

А внутри cordova.js у меня просто:

__cordovaRunningOnBrowser__ = true

КогдаПри создании для мобильного устройства файл cordova.js использоваться не будет (вместо этого будет использоваться специфичный для платформы файл cordova.js), поэтому преимущество этого метода в том, что он на 100% корректен независимо от протоколов, пользовательских агентов или библиотечных переменных.(что может измениться).Могут быть и другие вещи, которые я должен включить в cordova.js, но я пока не знаю, чем они являются.

2 голосов
/ 17 марта 2013

Чтобы сохранить одну кодовую базу, нас интересует «платформа», на которой выполняется код. Для меня эта «платформа» может быть тремя разными вещами:

  • 0: компьютер-браузер
  • 1: мобильный браузер
  • 2: phonegap / cordova

Способ проверки платформы:

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

Примечание:

  • Этот запуск должен выполняться только после загрузки cordova.js (загрузка тела (...), $ (документ) .ready (...))

  • 'ontouchstart' в document.documentElement будет присутствовать в ноутбуках и настольных мониторах с сенсорным экраном, поэтому он будет сообщать о мобильном браузере, даже если это рабочий стол. Существуют разные способы сделать более точную проверку, но я использую ее, потому что она по-прежнему заботится о 99% случаев, которые мне нужны. Вы всегда можете заменить эту строку на что-то более надежное.

1 голос
/ 26 ноября 2012

Я столкнулся с этой проблемой несколько месяцев назад, когда запускал наше приложение, потому что мы хотели, чтобы приложение также было "browser-compatible" (при том понимании, что некоторые функции будут заблокированы в этом сценарии: аудиозапись, компас,так далее.).

Единственное 100% (и я настаиваю на 100-процентном условии) решение для PRE-определения контекста выполнения приложения было следующим:

  • инициализироватьПеременная JS "flag" устанавливается в true и изменяется на false в контексте всего веба;

  • , поэтому вы можете использовать вызов типа "willIBeInPhoneGapSometimesInTheNearFuture()" (это PRE-PG, конечно, вам все еще нужен метод проверки POST-PG, если вы можете вызывать API-интерфейсы PG, ноэто тривиально).

  • Тогда вы говорите: «but how do you determine the execution context?»;Ответ таков: «Вы этого не делаете» (потому что я не думаю, что вы можете сделать это надежно, если только эти блестящие люди из PG не сделают это в своем API-коде);

  • вы пишете скрипт сборки, который делает это за вас: одна кодовая база с двумя вариантами.

1 голос
/ 07 февраля 2012

Решение GeorgeW в порядке, но даже на реальном устройстве PhoneGap.available верно только после загрузки вещей PhoneGap, например, Вызов onDeviceReady в document.addEventListener ('deviceready', onDeviceReady, false).

До этого времени, если вы хотите знать, вы можете сделать так:

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

Это решение предполагает, что большинство разработчиков разрабатывают с использованием Chrome или Firefox.

1 голос
/ 05 октября 2012

Следующее работает для меня с самой последней PhoneGap / Cordova (2.1.0).

Как это работает:

  • Очень просто в концепции
  • Я перевернул логику некоторых из приведенных выше решений по тайм-ауту.
  • Зарегистрируйтесь дляСобытие device_ready (как рекомендовано документами PhoneGap )
    • Если событие все еще не сработало после истечения времени ожидания, отступите к предположению браузера.
    • В отличие от другихПриведенные выше решения основаны на тестировании какой-либо функции PhoneGap и других и отслеживании их тестового перерыва.

Преимущества:

  • Использование рекомендованного PhoneGap события device_ready.
  • Мобильное приложение не имеет задержки.Как только сработает событие device_ready, мы продолжаем.
  • Никакого анализа пользовательского агента (мне нравится тестировать мое приложение в качестве мобильного веб-сайта, поэтому поиск кода в браузере для меня не вариант).
  • Не полагайтесь на недокументированные (и, следовательно, хрупкие) функции / свойства PhoneGap.
  • Сохраняйте свои cordova.js в своей кодовой базе даже при использовании настольного или мобильного браузера.Таким образом, это отвечает на вопрос ОП.
  • Wytze сказал выше: «Я бы хотел, чтобы Кордова установила параметр где-нибудь, чтобы сказать:« Мы пытались найти поддерживаемое устройство и отказались », но, похоже, такого нетпараметр «.Поэтому я привожу один из них здесь.

Недостатки:

  • Тайм-ауты непривычны.Но логика нашего мобильного приложения не зависит от задержки;скорее он используется как запасной вариант, когда мы находимся в режиме веб-браузера.

==

Создайте новый пустой проект PhoneGap.В приведенном примере файла index.js замените переменную «app» внизу следующим:

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 голос
/ 27 сентября 2012

У меня та же проблема.

Я склоняюсь к добавлению # cordova = true к URL-адресу, загруженному клиентом cordova, и тестированию для location.hash.indexOf ("cordova = true")> -1 на моей веб-странице.

1 голос
/ 08 декабря 2011

Ааронс, попробуйте

if (PhoneGap.available){
    do PhoneGap stuff;
}
1 голос
/ 15 мая 2014

Ничего из этого не сработает, если только вы не удалите файл PhoneGap Javascript из настольной версии приложения, что противоречит моей цели иметь одну кодовую базу.

Другой вариант - использоватьПапка merges , см. Снимок экрана ниже.

Вы можете добавить файлы для конкретной платформы / переопределить файлы по умолчанию.

(в некоторых случаях это должно сработать)

enter image description here


Другими словами: вместо того, чтобы обнаруживать браузер, вы просто не включаете определенные файлы для сборки на рабочем столе / прикрепляете определенные файлы только для iOS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...