我正在开发一个使用PhoneGap的Web应用程序:针对移动版本构建,并希望为“桌面”和移动版本提供单一代码库。我希望能够检测PhoneGap呼叫是否有效(即移动设备上的用户是否支持PhoneGap)。
我已经搜索过,无法相信没有简单的方法可以做到这一点。很多人都提出了建议;
除非您从应用程序的桌面版本中删除PhoneGap Javascript文件,否则这些都无法正常工作,这会破坏我拥有一个代码库的目标。
到目前为止,我提出的唯一解决方案是浏览器/用户代理嗅探,但至少可以说这并不健全。欢迎任何更好的解决方案!
编辑:一个稍微好一点的解决方案是尝试在一些小的超时后调用PhoneGap函数 - 如果它不起作用,则假设用户在桌面Web浏览器上。
答案 0 :(得分:112)
我使用此代码:
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
}
如此处所示:Detect between a mobile browser or a PhoneGap application
答案 1 :(得分:50)
几天前我写了一篇关于它的post。这是你能找到的最好的解决方案(直到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平台上的起始页面从 index.html 更改为 __ phonegap_index.html 。假设我的项目名称是示例,您需要更改的文件(如PhoneGap 2.2.0版):
CordovaLibApp/AppDelegate.m
src/org/apache/cordova/example/cordovaExample.java
example/package.appxmanifest
www/config.xml
framework/appinfo.json
src/WebForm.cpp
(第56行)最后,您可以在网站的任何位置使用它,如果它在PhoneGap上运行:
if ( localStorage.getItem("isPhoneGap") ) {
alert("Running on PhoneGap!");
} else {
alert("Not running on PhoneGap!");
}
希望它有所帮助。 : - )
答案 2 :(得分:28)
我知道它已经回答了一段时间,但“PhoneGap.available”不再存在了。 你应该使用:
if (window.PhoneGap) {
//do stuff
}
或从1.7开始,更喜欢:
if (window.cordova) {
//do stuff
}
答案 3 :(得分:15)
我们发现告诉我们是否在cordova / phonegap应用程序中最值得信赖的方法是使用此配置AppendUserAgent修改cordova应用程序的用户代理。
在config.xml
添加:
<preference name="AppendUserAgent" value="Cordova" />
然后致电:
var isCordova = navigator.userAgent.match(/Cordova/i))
为什么?
window.cordova
和document.addEventListener('deviceready', function(){});
受竞赛条件影响navigator.standalone
是网站时,<content src="index.html" />
不起作用(例如:<content src="https://www.example.com/index.html" />
或cordova-plugin-remote-injection)答案 4 :(得分:14)
我认为这是最简单的:
var isPhoneGap = (location.protocol == "file:")
修改强> 对于一些没有工作的人。然后你可能会尝试(没有测试过)
var isPhoneGap = ! /^http/.test(location.protocol);
答案 5 :(得分:8)
这对我有用(运行1.7.0)
if (window.device) {
// Running on PhoneGap
}
在桌面Chrome和Safari上测试。
答案 6 :(得分:7)
与原始海报一样,我正在使用phonegap构建服务。经过两天和近50次测试,我提出了一个优雅的解决方案,对我来说非常有用。
我无法使用UA嗅探,因为我想在移动浏览器中测试和运行。我最初选择了cobberboy非常实用的技术。这对我不起作用,因为“howPatientAreWe:10000”延迟/超时对于浏览器内开发来说太麻烦了。将其设置得更低有时会在app / device模式下无法通过测试。必须有另一种方式......
在将应用程序的文件提交给服务之前,phonegap构建服务需要从代码存储库中省略phonegap.js
文件。因此,我能够测试它的存在,以确定是否在浏览器和app中运行。
另一个警告,我也在使用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!
}
}
答案 7 :(得分:6)
有趣的是,许多答案,但它们不包括这三个选项:
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事件来检测上下文。脚本包含可以在构建过程中轻松删除,或者脚本加载只会在浏览器中失败。这样就不会设置这个全局变量。
<script src="../cordova.js" onload="javascript:window.isCordovaApp = true;"></script>
答案 8 :(得分:5)
我使用这种方法:
debug = (window.cordova === undefined);
debug
将在设备上的true
浏览器环境中为false
。
答案 9 :(得分:4)
这似乎是可行的,我已经在生产中使用它了:
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/
答案 10 :(得分:3)
另一种方式,基于SlavikMe的解决方案:
只需使用从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");
}
答案 11 :(得分:3)
问题的实质是,只要cordova.device未定义,你的代码就不能确定是否因为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
}
}
}
}
}
答案 12 :(得分:3)
我正在使用的方法是使用一个全局变量,该变量被仅限浏览器版本的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%正确的优势,userAgents或库变量(可能会改变)。我应该在cordova.js中包含其他内容,但我不知道它们到底是什么。
答案 13 :(得分:2)
为了保留一个代码库,感兴趣的是代码运行的“平台”。对我来说,这个“平台”可以是三个不同的东西:
检查平台的方法:
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(...))
'ontouchstart'将出现在具有触控屏幕的笔记本电脑和台式机显示器中,因此即使它是桌面设备也会报告移动浏览器。有不同的方法来进行更精确的检查,但我使用它,因为它仍然照顾我需要的99%的情况。你总是可以用那条线代替更健壮的东西。
答案 14 :(得分:1)
GeorgeW的解决方案没问题,但即使在真实设备上,PhoneGap.available只有在PhoneGap的内容被加载后才会生效,例如已调用document.addEventListener中的onDeviceReady('deviceready',onDeviceReady,false)。
在此之前,如果你想知道,你可以这样做:
runningInPcBrowser =
navigator.userAgent.indexOf('Chrome') >= 0 ||
navigator.userAgent.indexOf('Firefox') >= 0
此解决方案假设大多数开发人员使用Chrome或Firefox进行开发。
答案 15 :(得分:1)
除非您从应用程序的桌面版本中删除PhoneGap Javascript文件,否则这些都无法正常工作,这会破坏我拥有一个代码库的目标。
另一种选择是使用合并文件夹,请参见下面的截图。
您可以添加特定于平台的文件/覆盖默认文件。
(它应该在某些情况下起作用)
换句话说:您只是不包含用于桌面构建/附加某些文件的某些文件,而不是检测浏览器。
答案 16 :(得分:1)
不是真的这个问题的答案,但是当我在桌面浏览器中进行测试时,我只是设置了localstorage值,以使浏览器加载应用程序争议设备已经没有激活。
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();
}
});
答案 17 :(得分:1)
适用于Windows和Mac计算机。需要找到linux View details
的解决方案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
}
答案 18 :(得分:1)
browser-compatible
”(理解在这种情况下会阻止某些功能:音频录制,指南针等)。
预先确定应用程序执行上下文的唯一100%
(我坚持百分之百的条件)解决方案是这样的:
将JS“flag”变量初始化为true,并在all-web上下文中将其更改为false;
因此你可以使用像“willIBeInPhoneGapSometimesInTheNearFuture()
”这样的调用(那是PRE-PG,你当然还需要一个POST-PG方法来检查你是否可以调用PG API,但这个是微不足道的)。
然后你说:“but how do you determine the execution context
?”;答案是:“你不要”(因为我认为你不能可靠,除非PG的那些优秀人士会在他们的API代码中这样做);
你编写了一个为你完成它的构建脚本:一个包含两个变体的代码库。
答案 19 :(得分:1)
以下适用于最新的PhoneGap / Cordova(2.1.0)。
工作原理:
优点:
缺点:
==
创建一个全新的空白PhoneGap项目。在提供的示例index.js中,替换&#34; app&#34;底部的变量:
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"));
}
答案 20 :(得分:1)
我有同样的问题。
我倾向于将#cordova = true添加到cordova客户端加载的URL并测试location.hash.indexOf(“cordova = true”)&gt; -1在我的网页上。
答案 21 :(得分:1)
亚伦,试试
if (PhoneGap.available){
do PhoneGap stuff;
}
答案 22 :(得分:0)
略有修改,但对我来说没有任何问题。
意图是仅在嵌入式设备上加载Cordova,而不是在桌面上加载Cordova,因此我完全避免在桌面浏览器上使用cordova。因此,UI和MVVM的测试和开发非常舒适。
输入此代码,例如。在文件 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>
轻松你的工作! :)
答案 23 :(得分:0)
if ( "device" in window ) {
// phonegap
} else {
// browser
}
答案 24 :(得分:0)
我想在某种程度上他们并没有那么不同吗?哈哈......不好笑。谁不认为这不会有问题? 这是您考虑的最简单的解决方案。 将不同的文件推送到服务器,然后执行PhoneGap。 我也暂时使用上面建议的http:检查。
var isMobileBrowserAndNotPhoneGap = (document.location.protocol == "http:");
我的兴趣在于推动浏览器导航栏,所以我真的可以删除隔离脚本的标签并按下[DW]中的rebuild(无论如何它们都会进行部署清理,因此这可能是其中一项任务。) 无论如何,我觉得这是一个很好的选择(考虑到其他方面没有其他选择),只需在推送到PG时用isMobileBrowserAndNotPhoneGap手动注释掉东西。 对我而言,在我的情况下,我将简单地删除(隔离代码)文件的标签,该文件在移动浏览器时推动导航栏(它会更快更小)。 [所以,如果您可以隔离优化但手动解决方案的代码。]
答案 25 :(得分:0)
我使用了GeorgeW和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.')
}
答案 26 :(得分:0)
仅供参考 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
答案 27 :(得分:0)
尝试这种方法:
/**
* 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);
}
});
}
答案 28 :(得分:0)
我实际上发现这里列出的两种技术的组合效果最好,首先检查可以访问cordova / phonegap还检查设备是否可用。像这样:
function _initialize() {
//do stuff
}
if (window.cordova && window.device) {
document.addEventListener('deviceready', function () {
_initialize();
}, false);
} else {
_initialize();
}
答案 29 :(得分:0)
我正在尝试使用窗口对象,但它没有起作用,因为我在InAppBrowser中打开了远程URL。无法完成它。 因此,实现它的最佳和最简单的方法是将一个字符串附加到您需要从phonegap应用程序打开的URL。然后检查文档位置是否附加了字符串。
下面是它的简单代码
var ref = window.open('http://yourdomain.org#phonegap', '_blank', 'location=yes');
你会看到一个字符串被添加到网址“#phonegap”。所以在域名网址中添加以下脚本
if(window.location.indexOf("#phonegap") > -1){
alert("Url Loaded in the phonegap App");
}
答案 30 :(得分:0)
if (document.URL.includes('http')) {
// running in browser
}
同时处理http和https。