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

我正在开发一个使用PhoneGap:Build for一个移动版本的Web应用程序,并希望为“桌面”版本和移动版本提供一个代码库。 我希望能够检测到PhoneGap调用是否可以正常工作(例如,移动设备上的用户是否支持PhoneGap)。

我已经search,不能相信有没有这样做的简单方法。 许多人提出了build议;

  • http://www.sencha.com/forum/showthread.php?144127-Checking-if-running-in-PhoneGap-or-Mobile-Web-Browser
  • http://groups.google.com/group/phonegap/browse_thread/thread/322e80bd41bb1a54/a421300eb2a2029f?lnk=gst&q=detect+desktop#a421300eb2a2029f
  • http://groups.google.com/group/phonegap/browse_thread/thread/8a95dfeb0f313792/3ff10d8f35211739?lnk=gst&q=detect+desktop+browser#3ff10d8f35211739

除非您从应用程序的桌面版本中删除PhoneGap Javascript文件,否则这些工作都不起作用,这会挫伤我拥有一个代码库的目标。

到目前为止,我唯一提出的解决scheme是浏览器/用户代理嗅探,但至less可以说这是不稳健的。 更好的解决scheme欢迎!

编辑:一个稍微好一点的解决scheme是尝试调用PhoneGap函数一些小超时后 – 如果它不起作用,然后假设用户在桌面的Web浏览器。

我使用这个代码:

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

UPDATE

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

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

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

前几天我写了一篇关于它的文章 。 这是最好的解决scheme,你可以find(直到PhoneGap将发布的东西,也许或可能没有),它是简短的,简单和完美的(我已经检查过每一个可能的方式和平台)。

这个function可以处理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%的情况下,请按照下列步骤(它涉及本机代码稍作修改):

创build一个名为__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平台上的index.html起始页更改为__phonegap_index.html即可 。 比方说,我的项目名称是例子 ,您需要更改的文件(PhoneGap版本2.2.0):

  • iOSCordovaLibApp/AppDelegate.m
  • Androidsrc/org/apache/cordova/example/cordovaExample.java
  • Windows 8example/package.appxmanifest
  • 黑莓www/config.xml
  • WebOSframework/appinfo.json
  • Badasrc/WebForm.cpp (第56行)
  • 窗口电话7 – 不知道在哪里(有人仍然在该平台上开发?!)

最后,你可以在你的网站上的任何地方使用它,如果它在PhoneGap上运行的话:

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

希望能帮助到你。 🙂

我知道这是刚刚回答,但“PhoneGap.available”不存在了。 你应该使用:

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

或者从1.7开始,更喜欢:

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

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

编辑对于一些没有工作的人。 那么你可以尝试(没有testing过)

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

这适用于我(运行1.7.0)

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

在桌面版Chrome和Safari上进行testing。

像原来的海报一样,我正在使用phonegap构build服务。 经过两天和近50个testing版本,我想出了一个优雅的解决scheme,对我很好。

我无法使用UA嗅探,因为我想testing并在移动浏览器中运行。 我原本是在cobberboy的相当function的技术。 这对我不起作用,因为“howPatientAreWe:10000”延迟/超时对于浏览器内开发来说太麻烦了。 如果将其设置得较低,偶尔会在应用/设备模式下失败。 必须有另一种方式…

phonegap构build服务需要将phonegap.js文件从您的代码库中删除,然后再将您的应用程序的文件提交给服务。 因此,我可以testing它的存在,以确定是否在浏览器与应用程序运行。

另一个警告,我也使用jQueryMobile,所以jQM和phonegap必须初始化之前,我可以开始任何自定义脚本。 下面的代码放在我自定义的应用程序的index.js文件的开头(在jQuery之前,在jQM之前)。 此外phonegapbuild立文档说放置在HTML中的某处<script src="phonegap.js"></script> 。 我完全放弃它,并使用$ .getScript()来加载它来testing它的存在。

 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 // ie $.mobile.defaultPageTransition = 'slide'; }, ready: function () { // Both phonegap (if available) and jQM are fired up and ready // let the custom scripting begin! } } 

有趣的是,许多答案,但是他们不包括这三个选项:

1 – cordova.js将把cordova对象设置在全局范围内。 如果在那里,那么你很可能在cordova范围内运行。

 var isCordovaApp = !!window.cordova; 

2 – Cordova将运行您的应用程序,就像从桌面上打开HTML文档一样。 它将使用FILE而不是HTTP协议。 检测到这将使您有机会假定您的应用程序已在本地加载。

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

3 – 使用cordova脚本的load事件来检测上下文。 脚本include可以在构build过程中轻松删除,或者脚本加载只会在浏览器中失败。 所以这个全局variables不会被设置。

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

信贷来自Adobe的Damien Antipa

我们发现告诉我们是否在cordova / phonegap应用程序中最可信的方式是使用此configurationAppendUserAgent修改cordova应用程序的用户代理。

config.xml添加:

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

然后打电话:

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

为什么?

  1. window.cordovadocument.addEventListener('deviceready', function(){}); 受到比赛条件的限制
  2. navigator.standalone<content src="index.html" />是一个网站(如: <content src="https://www.example.com/index.html" />或者cordova-plugin – 远程注入 )
  3. 试图将用户代理列入白名单来猜测它是否是真正的浏览器是非常复杂的。 Android浏览器通常是自定义的网页浏览。

我用这个方法:

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

在浏览器环境中debug将是true的,在设备上是false的。

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

 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/

问题的实质是,只要cordova.device是未定义的,您的代码就不能确定是否因为cordova已经确定您的设备不被支持,或者是因为cordova仍在准备自己,并且deviceready将在以后触发(或第三个选项:cordova没有正确加载)。

唯一的解决办法是定义一个等待期,并决定在这段时间之后,你的代码必须假定该设备不被支持。 我希望cordova设置一个参数在某处说:“我们试图find一个支持的设备,放弃”,但似乎没有这样的参数。

一旦build立起来,您可能需要在没有支持设备的情况下做一些特定的事情。 就像隐藏设备的应用程序市场的链接,就我而言。

我把这个function拼凑在一起,几乎涵盖了所有的情况。 它可以让你定义一个deviceready处理程序,一个从未准备好的处理程序和一个等待时间。

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

我这样做的方式是使用一个全局variables,这个全局variables被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 

在为移动设备构build时,不会使用cordova.js(而是使用平台特定的cordova.js文件),因此无论协议,用户代理或库如何,此方法都具有100%的正确性variables(可能会改变)。 可能还有其他的东西,我应该包括在cordova.js中,但我不知道他们到底是什么。

另一种方式,基于SlavikMe的解决scheme:

只需使用从PhoneGap源传递给index.html的查询参数即可。 也就是说,在Android中,而不是

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

使用

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

SlavikMe在其他平台上有很好的名单。

那么你的index.html可以简单地做到这一点:

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

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

  • 0:电脑浏览器
  • 1:手机浏览器
  • 2:电话/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被加载 (body onload(…),$(document).ready(…)) 之后才能运行

  • document.documentElement中的“ontouchstart”将出现在具有触摸屏的笔记本电脑和台式机显示器中,因此即使它是桌面,也会报告移动浏览器。 有不同的方法来做更精确的检查,但我使用它,因为它仍然照顾我需要的案件的99%。 你总是可以用这条线代替更强大的东西。

亚伦,试试

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

GeorgeW的解决scheme是可以的,但即使在真实的设备上,PhoneGap.available只有在PhoneGap的东西被加载后才是真实的,例如document.addEventListener('deviceready',onDeviceReady,false)中的onDeviceReady被调用。

在此之前,如果你想知道,你可以这样做:

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

此解决scheme假定大多数开发人员使用Chrome或Firefox进行开发。

我有同样的问题。

我倾向于向cordova客户端加载的URL添加#cordova = true,并在我的网页中testinglocation.hash.indexOf(“cordova = true”)> -1。

以下对我来说最新的PhoneGap / Cordova(2.1.0)。

怎么运行的:

  • 概念非常简单
  • 我倒置了一些上述超时解决scheme的逻辑。
  • 注册device_ready事件( 由PhoneGap文档推荐 )
    • 如果事件在超时之后仍然未被触发,则回退到假设浏览器。
    • 相反,上面的其他解决scheme依赖于testing一些PhoneGapfunction或其他,并观看他们的testing中断。

优点:

  • 使用PhoneGap推荐的device_ready事件。
  • 移动应用程序没有延迟。 一旦device_ready事件触发,我们继续。
  • 没有用户代理嗅探(我喜欢testing我的应用程序作为一个移动网站,所以浏览器嗅探不是我的select)。
  • 不依赖无证(因此脆弱的)PhoneGapfunction/属性。
  • 即使在使用桌面或移动浏览器时,也要将cordova.js保存在您的代码库中。 因此,这回答了OP的问题。
  • Wytze在上面说:“我希望cordova会在某个地方设置一个参数来说:”我们试着find一个支持的设备,然后放弃“,但似乎没有这个参数。 所以我在这里提供一个。

缺点:

  • 超时是icky。 但我们的移动应用程序逻辑不依赖于延迟; 相反,当我们处于网页浏览器模式时,它被用作后备。

==

创build一个全新的空白PhoneGap项目。 在提供的示例index.js中,将底部的“app”variablesreplace为:

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

几个月前,当我们开始我们的应用程序时,我偶然发现了这个问题,因为我们希望应用程序也是“ browser-compatible ”(同时理解在这种情况下某些function将被阻止:录音,指南针等) 。

只有100% (而且我坚持100%的条件)解决scheme来确定应用程序的执行上下文是这样的:

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

  • 因此你可以使用诸如“ willIBeInPhoneGapSometimesInTheNearFuture() ”这样的调用(这是PRE-PG,当然你仍然需要一个POST-PG方法来检查你是否可以调用PG API,但是这个方法是微不足道的)。

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

  • 您可以编写一个构build脚本为您完成:一个代码库包含两个变体。

这个问题并不是一个真正的答案,但是当我在桌面浏览器中testing时,我只是设置一个本地存储值,以使浏览器加载应用程序暂停设备不会触发。

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

除非您从应用程序的桌面版本中删除PhoneGap Javascript文件,否则这些工作都不起作用,这会挫伤我拥有一个代码库的目标。

另一个select是使用merges文件夹,见下面的截图。

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

(它应该在一些情况下做的伎俩)

在这里输入图像说明


换句话说:而不是检测浏览器,你只是不包括某些文件的桌面生成/仅附加iOS的某些文件。

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

适用于Windows和Mac机器。 需要为linux查找解决scheme查看详情

 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 } 

实际上,我发现这里列出的两种技术组合工作效率最高,首先检查是否可以访问cordova / phonegap,并检查设备是否可用。 像这样:

 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 ie * $(document).ready(...). */ function invokeOnReady(callback){ $(document).ready(function(){ if (isOnDevice()) { document.addEventListener("deviceready", callback, false); } else { invoke(callback); } }); } 

我使用GeorgeW和mkprogrammingbuild议的组合:

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

我猜他们不是那么不同吗? 哈哈…不好笑。 谁不认为这不成问题? 这是您考虑最简单的解决scheme。 推送不同的文件到你的服务器,然后你做PhoneGap。 我也暂时与上面build议的http:check一起去。

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

我的兴趣在于将浏览器的导航栏向上推,所以我真的可以删除隔离的脚本的标签,并按[DW]中的重build(无论如何他们将进行部署清理,所以这可能是其中的一个任务)。这是一个很好的select(考虑到没有其他可用的东西),只要在推送到PG时手动注释掉isMobileBrowserAndNotPhoneGap的东西)。 在我的情况下,我会简单地删除(孤立的代码)文件的标签,当它是一个移动浏览器(这将是更快,更小)推动导航栏的标签。 [所以如果你可以隔离代码的优化,但手动的解决scheme。]

稍作修改,但对我完全没有任何问题。

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

把这个代码例如。 在文件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); } 

然后,而不是包括cordovaJavaScript本身包括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> 

放松你的工作! 🙂

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

仅供参考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

我正在尝试与窗口对象,但它没有工作,因为我打开InAppBrowser中的远程URL。 无法完成。 所以实现它的最好和最简单的方法是将一个string附加到您需要从phonegap应用程序打开的url。 然后检查文档位置是否附有string。

下面是它的简单代码

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

你会看到一个string被添加到url“#phonegap”。因此在域url中添加下面的脚本

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