我想知道是否可以检测浏览器是否在 iOS 上运行,类似于如何使用 Modernizr 进行功能检测(尽管这显然是设备检测而不是功能检测)。
通常我更喜欢功能检测,但我需要确定设备是否是 iOS,因为他们根据这个问题处理视频的方式YouTube API not working with iPad / iPhone / non-Flash device
我想知道是否可以检测浏览器是否在 iOS 上运行,类似于如何使用 Modernizr 进行功能检测(尽管这显然是设备检测而不是功能检测)。
通常我更喜欢功能检测,但我需要确定设备是否是 iOS,因为他们根据这个问题处理视频的方式YouTube API not working with iPad / iPhone / non-Flash device
在iOS 13 iPad 中,用户代理和平台字符串都发生了变化,iPad 和 MacOS 之间的区别似乎是可能的,所以下面的所有答案现在都需要考虑到这一点。
这可能是涵盖 iOS 13 的最短替代方案:
function iOS() {
return [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
].includes(navigator.platform)
// iPad on iOS 13 detection
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
}
iOS
将是true
或false
用户代理嗅探更危险,问题经常出现。
在 iPad iOS 13 上,用户代理与 MacOS 13 计算机的用户代理相同,但如果您忽略 iPad,这可能会持续一段时间:
var iOS = !window.MSStream && /iPad|iPhone|iPod/.test(navigator.userAgent); // fails on iPad iOS 13
这!window.MSStream
是为了不错误地检测到 IE11,请参见此处和此处。
注意:两者navigator.userAgent
和navigator.platform
都可以被用户或浏览器扩展伪造。
存在用于更改 userAgent 或平台的浏览器扩展,因为网站使用过于严厉的检测并且经常禁用某些功能,即使用户的浏览器本来可以使用该功能。
为了降低与用户的冲突,建议针对每种情况专门检测您网站所需的确切功能。然后,当用户获得具有所需功能的浏览器时,它已经可以工作而无需额外的代码更改。
检测 iOS 版本的最常见方法是从 User Agent 字符串中解析它。但也有特征检测推断*;
我们知道在iOS4 - iOS5 - iOS6 - iOS7等中history API
引入的事实。matchMedia API
webAudio API
WebSpeech API
注意:以下代码不可靠,如果这些 HTML5 功能中的任何一个在较新的 iOS 版本中被弃用,就会中断。你被警告了!
function iOSversion() {
if (iOS) { // <-- Use the one here above
if (window.indexedDB) { return 'iOS 8 and up'; }
if (window.SpeechSynthesisUtterance) { return 'iOS 7'; }
if (window.webkitAudioContext) { return 'iOS 6'; }
if (window.matchMedia) { return 'iOS 5'; }
if (window.history && 'pushState' in window.history) { return 'iOS 4'; }
return 'iOS 3 or earlier';
}
return 'Not an iOS device';
}
在 iOS 13 之后,您应该像这样检测 iOS 设备,因为 iPad 不会被旧方式检测为 iOS 设备(由于新的“桌面”选项,默认启用):
let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
iOS < 13 或禁用桌面模式的 iPhone 或 iPad 的第一个条件,默认配置中 iPadOS 13 的第二个条件,因为它的定位类似于 Macintosh Intel,但实际上是唯一具有多点触控的 Macintosh。
与其说是真正的解决方案,不如说是一种技巧,但对我来说可靠地工作
PS如前所述,您可能应该添加IE检查
let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!window.MSStream
这会将变量设置_iOSDevice
为true或false
_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
此处之前的答案均不适用于所有 iOS 版本(包括 iOS 13)上的所有主要浏览器。这是适用于所有 iOS 版本的 Safari、Chrome 和 Firefox 的解决方案:
var isIOS = (function () {
var iosQuirkPresent = function () {
var audio = new Audio();
audio.volume = 0.5;
return audio.volume === 1; // volume cannot be changed from "1" on iOS 12 and below
};
var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
var isAppleDevice = navigator.userAgent.includes('Macintosh');
var isTouchScreen = navigator.maxTouchPoints >= 1; // true for iOS 13 (and hopefully beyond)
return isIOS || (isAppleDevice && (isTouchScreen || iosQuirkPresent()));
})();
请注意,此代码片段的编写优先考虑可读性,而不是简洁性或性能。
解释:
如果用户代理包含任何“iPod|iPhone|iPad”,那么显然该设备是 iOS。否则,继续...
任何其他不包含“Macintosh”的用户代理都不是 Apple 设备,因此不能是 iOS。否则,它是 Apple 设备,所以继续...
如果maxTouchPoints
具有1
或更大的值,则 Apple 设备具有触摸屏,因此必须是 iOS,因为没有带触摸屏的 Mac(感谢 kikiwora 提及maxTouchPoints
)。请注意,这maxTouchPoints
适用undefined
于 iOS 12 及更低版本,因此我们需要针对该场景使用不同的解决方案...
iOS 12 及更低版本有一个 Mac OS 中不存在的怪癖。怪癖是元素的volume
属性Audio
不能成功设置为除 之外的任何值1
。这是因为 Apple 不允许在Audio
iOS 设备的元素上更改音量,但对于 Mac OS 则允许。这个怪癖可以用作区分 iOS 设备和 Mac OS 设备的最终后备方法。
如果您使用的是Modernizr,则可以为其添加自定义测试。
无论您决定使用哪种检测模式(userAgent、navigator.vendor 或 navigator.platform),您都可以随时将其包装起来以便以后使用。
//Add Modernizr test
Modernizr.addTest('isios', function() {
return navigator.userAgent.match(/(iPad|iPhone|iPod)/g);
});
//usage
if (Modernizr.isios) {
//this adds ios class to body
Modernizr.prefixed('ios');
} else {
//this adds notios class to body
Modernizr.prefixed('notios');
}
一个简化的、易于扩展的版本。
var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
更新:我的原始答案不包括桌面模式下的 iPad (默认更改为桌面模式即将到来iPadOS 13 及更高版本)。
这对我的用例来说很好,如果它不适合你,请使用此更新:
// iPhone and iPad including iPadOS 13+ regardless of desktop mode settings
iOSiPadOS = /^iP/.test(navigator.platform) ||
/^Mac/.test(navigator.platform) && navigator.maxTouchPoints > 4;
^
首先检查平台字符串的起始位置,如果没有“iP”则停止(无论如何都比搜索长 UA 字符串直到结束要快)navigator.userAgent
检查更安全,因为navigator.platform
伪造的可能性要小得多恕我直言,这个速度很快,保存良好,并且运行良好:
iOS = /^iP/.test(navigator.platform);
// or, if you prefer it verbose:
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);
可能值得回答的是,运行 iOS 13 的 iPad 将navigator.platform
设置为MacIntel
,这意味着您需要找到另一种方法来检测 iPadOS 设备。
社区 wiki,因为编辑队列说它已满,所有其他答案目前已过时或不完整。
const iOS_1to12 = /iPad|iPhone|iPod/.test(navigator.platform);
const iOS13_iPad = (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));
const iOS1to12quirk = function() {
var audio = new Audio(); // temporary Audio object
audio.volume = 0.5; // has no effect on iOS <= 12
return audio.volume === 1;
};
const isIOS = !window.MSStream && (iOS_1to12 || iOS13_iPad || iOS1to12quirk());
几年前我写了这个,但我相信它仍然有效:
if(navigator.vendor != null && navigator.vendor.match(/Apple Computer, Inc./) && navigator.userAgent.match(/iPhone/i) || (navigator.userAgent.match(/iPod/i)))
{
alert("Ipod or Iphone");
}
else if (navigator.vendor != null && navigator.vendor.match(/Apple Computer, Inc./) && navigator.userAgent.match(/iPad/i))
{
alert("Ipad");
}
else if (navigator.vendor != null && navigator.vendor.match(/Apple Computer, Inc./) && navigator.userAgent.indexOf('Safari') != -1)
{
alert("Safari");
}
else if (navigator.vendor == null || navigator.vendor != null)
{
alert("Not Apple Based Browser");
}
在添加 Modernizr 测试时,您应该尽可能添加功能测试,而不是设备或操作系统。如果需要的话,为 iPhone 添加十个测试并没有错。有些东西就是无法检测到特征。
Modernizr.addTest('inpagevideo', function ()
{
return navigator.userAgent.match(/(iPhone|iPod)/g) ? false : true;
});
例如,在 iPhone(不是 iPad)上,视频不能在网页上内联播放,它会打开全屏。所以我创建了一个测试'no-inpage-video'
然后您可以在 css 中使用它(如果测试失败,Modernizr 会.no-inpagevideo
在<html>
标签中添加一个类)
.no-inpagevideo video.product-video
{
display: none;
}
这将隐藏 iPhone 上的视频(在这种情况下,我实际上正在做的是显示一个带有 onclick 的替代图像来播放视频 - 我只是不希望显示默认的视频播放器和播放按钮)。
iOS 设备上的用户代理在其中说 iPhone 或 iPad。我只是根据这些关键字进行过滤。
如果你使用 React,有一个很好的库来解决这类问题:REACT-UGENT。(使用 ua-parser-js 构建。)
https://github.com/medipass/react-ugent
可用的浏览器有:
铬, 铬, 边缘, 火狐, 即, 猞猁, 野生动物园, 歌剧
可用的操作系统有:
安卓,黑莓,铬操作系统,debian,ios,linux,mac os,ubuntu,unix,windows
可用设备有:
控制台, 计算机, 移动, 平板电脑, smarttv, 可穿戴, 嵌入式
易于使用:
<Ugent browser="safari" os="ios">
<div>
This text only shows on Safari on iOS.
</div>
</Ugent>
如果你不使用 React,基本上,你可以使用 - ua-parser-js
使用更实用的方法稍微更新第一个答案。
const isIOS = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod',
].indexOf(navigator.platform) !== -1;
你也可以使用includes
const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(navigator.platform)
无需测试navigator.userAgent
or navigator.platform
:
const isIOS = typeof navigator.standalone === 'boolean';
navigator.standalone
仅在 iOS Safari 上设置。请参阅MDN,Safari HTML 参考。
因为navigator.platform
已弃用,最好不要再使用它,我想添加其他解决方案。
您可以通过选中navigator.vendor
. 当结果为Apple Computer, Inc.
时,您就知道它是 MacOS。
在我的情况下,用户代理不够好,因为在 Ipad 中,用户代理与 Mac OS 中的相同,因此我不得不做一个讨厌的把戏:
var mql = window.matchMedia("(orientation: landscape)");
/**
* If we are in landscape but the height is bigger than width
*/
if(mql.matches && window.screen.height > window.screen.width) {
// IOS
} else {
// Mac OS
}
var isiOSSafari = (navigator.userAgent.match(/like Mac OS X/i)) ? true: false;
为了检测 iOS 版本,必须使用这样的 Javascript 代码解构用户代理:
var res = navigator.userAgent.match(/; CPU.*OS (\d_\d)/);
if(res) {
var strVer = res[res.length-1];
strVer = strVer.replace("_", ".");
version = strVer * 1;
}