检测是否在桌面浏览器上运行

我正在开发一个网络应用程序,它使用 PhoneGap: Build 的移动版本,并希望有一个单一的代码基础的“桌面”和移动版本。我希望能够检测 PhoneGap 调用是否能够工作(即,移动设备上的用户是否支持 PhoneGap)。

我一直在寻找,不敢相信没有一种简单的方法可以做到这一点

除非你把 PhoneGap Javascript 文件从这个应用的桌面版本中删除,否则这些都不起作用,这就违背了我建立一个代码库的目标。

到目前为止,我想到的唯一解决方案是浏览器/用户代理嗅探,但至少可以说这并不健壮。欢迎任何更好的解决方案!

编辑: 一个稍微好一点的解决方案是尝试在一些小的超时后调用 PhoneGap 函数-如果它不工作,那么假设用户是在桌面 Web 浏览器上。

81513 次浏览

Aaron 试试

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

GeorgeW 的解决方案是可行的,但是即使在真正的设备上,PhoneGap.able 也只有在 PhoneGap 的内容被加载之后才是真实的,例如,document.addEventListener 中的 onDeviceReady (‘ deviceready’,onDeviceReady,false)已经被调用。

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

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

这个解决方案假设大多数开发人员使用 Chrome 或 Firefox 进行开发。

我知道刚才已经有人接了,但是“ PhoneGap 可用”已经不存在了。 你应使用:

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

或自1.7以来,更喜欢:

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

编辑2019: 正如在评论中所说,这只有当你不包括 cordova 库到您的桌面浏览器构建。当然,对于每个目标设备,只包含严格的最小 javascript/html/css 文件是一个很好的做法

我用这个代码:

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

更新

还有很多其他的方法来检测是否在浏览器上运行 phonegap,这里有另一个很好的选择:

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

如图所示: 在移动浏览器或 PhoneGap 应用程序之间进行检测

This works for me (running 1.7.0)

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

在桌面 Chrome 和 Safari 上测试。

问题的本质在于,只要 cordova 设备没有定义,你的代码就无法确定这是否是因为 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
}
}
}
}


}

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

试试这种方法:

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

我认为这是最简单的: var isPhoneGap = (location.protocol == "file:")

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

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

我结合了 乔治mkprogramming的建议:

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

我也有同样的问题。

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.

以下内容适合我使用最新的 PhoneGap/Cordova (2.1.0)。

工作原理:

  • 概念很简单
  • 我反转了上述一些超时解决方案的逻辑。
  • Register for the device_ready event (as recommended by the PhoneGap docs )
    • 如果超时后事件仍未触发,请退回到假设的浏览器。
    • 相比之下,上面的其他解决方案依赖于测试 PhoneGap 的某些特性或其他特性,并观察它们的测试中断情况。

优点:

  • 使用 PhoneGap 推荐的 device _ ready 事件。
  • 移动应用程序没有延迟。一旦 device _ ready 事件触发,我们就继续。
  • 没有用户代理嗅探(我喜欢把我的应用程序作为一个移动网站来测试,所以我不会选择浏览器嗅探)。
  • 不依赖于没有文档的(因此是脆弱的) PhoneGap 特性/属性。
  • 即使在使用桌面或移动浏览器时,也要将 cordova.js 保存在代码库中。因此,这回答了 OP 的问题。
  • 怀兹上面说: “我希望科尔多瓦能在某个地方设置一个参数,表示‘我们已经试图找到一个支持的设备,但放弃了’,但似乎没有这样的参数。”。所以我在这里提供了一个。

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.

==

创建一个全新的空白 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"));
}

就像原来的海报一样,我在使用电话隔离建设服务。经过两天近50次的测试构建,我想出了一个非常适合我的优雅的解决方案。

我不能使用 UA 嗅探,因为我想在移动浏览器中测试和运行。我最初选定的是鞋匠相当实用的技术。这对我来说不起作用,因为“ howPatientAreWe: 10000”延迟/超时对于浏览器内开发来说太麻烦了。如果设置得再低一些,在 app/device 模式下的测试偶尔也会失败。肯定还有别的办法。

Phonegap 构建服务要求在向服务提交应用程序文件之前,从代码存储库中省略 phonegap.js文件。因此,我能够测试它的存在,以确定是否运行在浏览器与应用程序。

另一个警告是,我还使用 jQueryMobile,因此在开始任何自定义脚本之前,jQM 和 phonegap 都必须进行初始化。下面的代码放在应用程序的自定义 index.js 文件的开头(jQuery 之后,jQM 之前)。同样,phonegap 构建文档说要将 <script src="phonegap.js"></script>放在 HTML 的某个地方。我不管了 完全删除并使用 $. getScript ()加载它,以便测试它的存在。

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

我想在某种程度上他们并没有那么不同,不是吗?哈哈... 不好笑。谁不觉得这会是个问题呢? 这里有一个最简单的解决方案。 将不同的文件推送到服务器,然后执行 PhoneGap 操作。 I'd also temporarily go with the http: check suggested above.

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

我的兴趣在于推动浏览器导航栏,所以实际上我可以删除孤立的脚本标记,然后按下[在 DW 中]重新构建(无论如何,它们将是部署的一些清理工作,因此这可以成为其中的一项任务) 无论如何,我觉得这是一个很好的选择(考虑到没有太多其他可用的) ,有效地只是手动注释出事情的 isMobileBrowserAndNotPhoneGap 推到 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.]

几天前我写了一篇关于它的 邮寄。这是你能找到的最好的解决方案(直到 PhoneGap 发布一些东西,也许或者也许不发布) ,它简短,简单,完美(我已经用各种可能的方式和平台检查过了)。

这个函数可以完成98% 的工作。

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

要完成其他2% 的情况,请遵循以下步骤(它涉及对本机代码的轻微更改) :

创建一个名为 _ _ phonegap _ index. html的文件,其源代码如下:

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

现在,在本机上,只需在所有 PhoneGap 平台上将起始页从 Html更改为 _ _ phonegap _ index. html。假设我的项目名称是 例子,您需要更改的文件是(对于 PhoneGap 2.2.0版本) :

  • IOS -CordovaLibApp/AppDelegate.m
  • Android -src/org/apache/cordova/example/cordovaExample.java
  • Windows8 -example/package.appxmanifest
  • 黑莓 -www/config.xml
  • WebOS -framework/appinfo.json
  • Bada - src/WebForm.cpp (line 56)
  • WindowPhone7 -不知道在哪里(有人还在那个平台上开发? !)

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

希望能有所帮助。 : -)

这似乎是可行的,我已经在生产中使用它:

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

资料来源: http://tqcblog.com/2012/05/09/detecting-phonegap-cordova-on-startup/

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

预先确定应用程序执行上下文的唯一 100%(我坚持100% 的条件)解决方案是:

  • 将一个 JS“标志”变量初始化为 true,并在全 Web 上下文中将其更改为 false;

  • 因此,您可以使用类似于“ willIBeInPhoneGapSometimesInTheNearFuture()”的调用(即 pre-PG,当然您仍然需要 POST-PG 方法来检查是否可以调用 PG API,但是这个方法很简单)。

  • 然后你说: “ but how do you determine the execution context?”; 答案是: “ you don’t”(因为我不认为你能可靠地做到,除非 PG 的那些聪明人会在他们的 API 代码中做到这一点) ;

  • 您编写了一个构建脚本来完成这项工作: 一个代码基带有两个变体。

为了保持一个代码库,我们感兴趣的是运行代码的“平台”。对我来说,这个“平台”可以是三种不同的东西:

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

注:

  • 这必须是 run only after cordova.js has been loaded(body onload (...) ,$(document) . ready (...))

  • Document.documentElement 中的“ ontouch start”将出现在具有触摸屏的笔记本电脑和桌面显示器中,因此即使是台式机,它也能报告移动浏览器。有不同的方法可以做出更精确的检查,但我使用它,因为它仍然照顾到99% 的情况下,我需要。您总是可以将该行替换为更健壮的代码。

稍微修改了一下,但对我来说没有任何问题。

意图是只在嵌入式设备上加载 Cordova,而不是在桌面上,所以我完全避免在桌面浏览器上加载 Cordova。测试和开发的 UI 和 MVVM 等是非常舒适的。

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

然后不再包含 cordova javascript 本身,而是包含 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>

放松你的工作! :)

我使用的方法是使用一个全局变量,该变量被仅在浏览器中使用的 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 -->

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.

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

另一种方法,基于 SlavikMe 的解决方案:

只需使用从 PhoneGap 源代码传递给 index.html的查询参数即可

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

使用

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

SlavikMe 有一个很棒的列表,告诉你在其他平台上可以做到这一点。

Then your index.html can simply do this:

if (window.location.href.match(/phonegap=1/)) {
alert("phonegap");
}
else {
alert("not phonegap");
}

这个问题的答案不是 真的,但是当我在桌面浏览器中测试时,我只是设置一个本地存储值来使浏览器加载应用程序,尽管设备已经不能启动。

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

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.

另一个选择是使用 合并文件夹,见下面的截图。

您可以添加特定于平台的文件/覆盖默认文件。

(在某些情况下,它应该会奏效)

enter image description here


换句话说: 与其检测浏览器,你只是不包括某些文件的桌面构建/附加某些文件只为 iOS。

有趣的是,许多答案并不包括以下三个选项:

Js 将在全局范围内设置 cordova 对象。如果它在那里,那么你最有可能在一个科尔多瓦范围内运行。

var isCordovaApp = !!window.cordova;

2-Cordova 将运行您的应用程序,就像您从桌面打开 HTML 文档一样。它将使用 FILE 代替 HTTP 协议。检测到这一点,您就有机会假设您的应用程序是本地加载的。

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>

这要归功于 Damien Antipa from Adobe

只是想知道怎么进去 PhoneGap 3.x 移动应用开发快照

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

在 YASMF 框架中

Https://github.com/photokandystudios/yasmf-next/blob/master/lib/yasmf/util/core.js#l152

我使用这种方法:

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

debugtrue放在浏览器环境中,false放在设备上。

即使模拟设备处于活动状态,也要检测桌面浏览器

适用于 Windows 和 Mac 机器。需要为 linux 查看详细信息找到一个解决方案

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
}

我尝试使用 windows 对象,但是在 InAppBrowser 中打开远程 URL 时无法工作。完成不了。 所以实现它的最好和最简单的方法是在你需要打开的手机应用程序的 URL 后面添加一个字符串。然后检查文档位置是否附加了字符串。

下面是它的简单代码

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

您将看到一个字符串被添加到 URL“ # phonegap”

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

我们发现判断是否在 cordova/phonegap 应用程序中的最可靠方法是使用这个配置 AppendUserAgent修改 cordova 应用程序的用户代理。

config.xml中添加:

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

然后打电话给:

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

为什么?

  1. window.cordovadocument.addEventListener('deviceready', function(){});受赛车条件的限制
  2. <content src="index.html" />是一个网站(例如: <content src="https://www.example.com/index.html" />或与 cordova-plugin-remote-injection)时,navigator.standalone不工作
  3. 尝试将用户代理列入白名单来猜测它是否是一个真正的浏览器是非常复杂的。Android 浏览器通常是定制的 webview。
if (document.URL.includes('http')) {
// running in browser
}

Handles both http and https.