我想知道是否可以检测浏览器是否在 iOS 上运行,类似于如何使用 Modernizr 进行功能检测(尽管这显然是设备检测而不是功能检测)。
通常我更喜欢功能检测,但我需要确定设备是否是 iOS,因为他们根据这个问题处理视频的方式YouTube API not working with iPad / iPhone / non-Flash device
检测 iOS
使用 iOS 13 iPad both User agent and platform strings are changed 和 differentiating between iPad and MacOS seems possible,因此下面的所有答案现在都需要考虑到这一点。
这可能是涵盖 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,请参阅 here 和 here。
注意: navigator.userAgent
和 navigator.platform
都可能被用户或浏览器扩展程序伪造。
存在用于更改 userAgent 或平台的浏览器扩展,因为网站使用过于严厉的检测并且经常禁用某些功能,即使用户的浏览器本来可以使用该功能。
为了降低与用户的冲突,建议针对每种情况专门检测您网站所需的确切功能。然后,当用户获得具有所需功能的浏览器时,它已经可以工作而无需额外的代码更改。
检测 iOS 版本
检测 iOS 版本的最常用方法是通过 parsing it from the User Agent string。但也有特征检测推理*;
我们知道 history API
是在 iOS4 中引入的 - iOS5 中的 matchMedia API
- iOS6 中的 webAudio API
- WebSpeech API
在 iOS7 等等。
注意:以下代码不可靠,如果这些 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
navigator.userAgent
进行此项检查 /iPad|iPhone|iPod/.test(navigator.platform)
?对于 iPhone iOS <= 12,navigator.platform
似乎总是返回“MacIntel”
navigator.maxTouchPoints
,因此该检查不会为您做任何事情。
这会将变量 _iOSDevice
设置为 true 或 false
_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
/iPhone|iPod|iPad/.test(navigator.platform)
您可以避免 !!
此处之前的答案均不适用于所有 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)。请注意,对于 iOS 12 及更低版本,maxTouchPoints 未定义,因此我们需要针对该场景使用不同的解决方案...
iOS 12 及更低版本有一个 Mac OS 中不存在的怪癖。怪癖是 Audio 元素的 volume 属性不能成功设置为 1 以外的任何值。这是因为 Apple 不允许 iOS 设备的 Audio 元素上的音量更改,但 Mac OS 允许。这个怪癖可以用作区分 iOS 设备和 Mac OS 设备的最终后备方法。
Audio
元素(如有必要)。在这种情况下,该元素实际上并未用于播放声音,并且它不会影响您可能在系统中使用的其他 Audio
元素的音量。
如果您使用 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');
}
return x ? true : false
简化为 return Boolean(x)
或只是 return !!x
一个简化的、易于扩展的版本。
var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
navigator.platform.replace(' Simulator', '')
。
['str'].indexOf('string') == -1
更新:我的原始答案不包括桌面模式下的 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;
只要桌面 Mac 根本不支持触摸事件或不超过 4 个触摸点(当前 iOS 设备支持 5 个触摸点),这应该是安全的
桌面 Mac 根本不支持触摸事件
或不超过 4 个触摸点(当前 iOS 设备支持 5 个触摸点)
它很快,因为正则表达式 ^ 首先检查平台字符串的起始位置,如果没有“iP”则停止(无论如何都比搜索长 UA 字符串直到结束要快)
它比 navigator.userAgent 检查更安全,因为 navigator.platform 被伪造的可能性要小得多
检测 iPhone / iPad 模拟器
恕我直言,这个速度很快,保存良好,并且运行良好:
iOS = /^iP/.test(navigator.platform);
// or, if you prefer it verbose:
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);
而不是这个,我会做 iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform);
作为后备措施,因为在我的情况下 navigator.platform 不起作用,但像以后那样做就可以了
navigator.platform
没用?那你真的在iOS上吗?检查 jeka.info/test/navigator.html 。 userAgent
给出误报是因为一些供应商出于任何原因伪造它以模仿 Apple 设备。 vendor
只返回 Google Inc.
、Apple Computer, Inc.
或什么都不返回(在 Firefox 中)。
可能值得回答的是,运行 iOS 13 的 iPad 会将 navigator.platform
设置为 MacIntel
,这意味着您需要找到另一种方法来检测 iPadOS 设备。
检测 iOS(<12 和 13+)
社区 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 会在 <html>
标记中添加一个类 .no-inpagevideo
)
.no-inpagevideo video.product-video
{
display: none;
}
这将隐藏 iPhone 上的视频(在这种情况下,我实际上正在做的是显示一个带有 onclick 播放视频的替代图像 - 我只是不希望显示默认的视频播放器和播放按钮)。
playsinline
,因此您现在可以使用 'playsInline' in document.createElement('video');
作为测试github.com/Modernizr/Modernizr/issues/2077
如果你使用 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
https://github.com/faisalman/ua-parser-js
iOS 设备上的用户代理在其中说 iPhone 或 iPad。我只是根据这些关键字进行过滤。
无需测试 navigator.userAgent
或 navigator.platform
:
const isIOS = typeof navigator.standalone === 'boolean';
navigator.standalone
仅在 iOS Safari 上设置。请参阅MDN、Safari HTML Reference。
const
对我来说非常适合这个条件检查:if (isIOS === true ) { //stuff for iOS } else {// stuff for all other }
因为 navigator.platform
已被弃用,最好不要再使用它,我想添加其他解决方案。
您可以通过选中 navigator.vendor
在 MacOS 系统上进行过滤。当结果为 Apple Computer, Inc.
时,您知道它是 MacOS。
navigator.vendor
也是 deprecated
使用更实用的方法稍微更新第一个答案。
const isIOS = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod',
].indexOf(navigator.platform) !== -1;
MacIntel
您也可以使用 includes
const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(navigator.platform)
在我的情况下,用户代理不够好,因为在 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;
test
返回一个布尔值并且可以替换 match
为了检测 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;
}
var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
navigator.platform
已弃用且不依赖它。Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15
,因此需要更新此答案