检测设备是否为iOS

我想知道是否有可能检测浏览器是否运行在iOS上,类似于你如何使用Modernizr进行功能检测(尽管这显然是设备检测而不是功能检测)。

通常情况下,我会倾向于功能检测,但我需要找出一个设备是否是iOS,因为他们处理视频的方式根据这个问题YouTube API不适用于iPad / iPhone /非flash设备

520001 次浏览

iOS设备上的用户代理会显示iPhone或iPad。我只是根据这些关键词进行筛选。

iOS检测

使用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将是truefalse

更糟糕的选择:用户代理嗅探

用户代理嗅探更加危险,经常出现问题。

在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.userAgentnavigator.platform都可以被用户或浏览器扩展伪造。

改变userAgent或平台的浏览器扩展存在,因为网站使用了过于繁重的检测,并且经常禁用一些功能,即使用户的浏览器本来可以使用这些功能。

为了减少与用户的冲突,建议针对每种情况专门检测您的网站需要的确切功能。然后,当用户得到一个具有所需功能的浏览器时,它就已经可以工作了,而无需额外的代码更改。

检测iOS版本

最常见的检测iOS版本的方法是从User Agent字符串解析它。但也有特征检测推断;

我们知道history API是在iOS4中引入的,matchMedia API是在iOS5中引入的,webAudio API是在iOS6中引入的,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版本,我们必须像这样用Javascript代码解构用户代理:

 var res = navigator.userAgent.match(/; CPU.*OS (\d_\d)/);
if(res) {
var strVer = res[res.length-1];
strVer = strVer.replace("_", ".");
version = strVer * 1;
}

我在几年前写过这个,但我相信它仍然有效:

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


}

# EYZ0

如果您正在使用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');
}

这将变量_iOSDevice设置为真正的

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);

一个简化的、易于扩展的版本。

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;

在添加Modernizr测试时,只要有可能,您应该添加针对某个特性的测试,而不是针对某个设备或操作系统。如果需要的话,为iPhone添加10个测试并没有什么错。有些东西就是不能被特征检测到。

    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上的视频(我在这种情况下实际做的是显示一个可供选择的图像,点击播放视频-我只是不想显示默认的视频播放器和播放按钮)。

更新:我最初的答案不包括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个触摸点)
  • 因为regexp ^首先检查平台字符串的起始位置,如果没有"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 13的ipad将navigator.platform设置为MacIntel,这意味着你需要找到另一种方法来检测iPadOS设备。

在iOS 13之后,你应该像这样检测iOS设备,因为iPad将不会被旧的方式检测为iOS设备(由于新的“桌面”选项,默认启用):

let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)

iOS <禁用桌面模式,这是iPadOS 13默认配置的第二个条件,因为它把自己定位为Macintosh Intel,但实际上是唯一一款带有多点触摸的Macintosh。

与其说是一种破解,不如说是一种真正的解决方案,但对我来说很可靠

正如之前所说,你可能应该添加IE检查

let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!window.MSStream

在我的案例中,用户代理不够好,因为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
}

您也可以使用includes

  const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(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。否则,它就是苹果设备,所以继续…

  • 如果maxTouchPoints的值为1或更大,那么苹果设备就有触摸屏,因此肯定是iOS设备,因为没有带触摸屏的mac (kikiwora提到maxTouchPoints很赞)。注意,maxTouchPoints在iOS 12及以下版本中是undefined,所以我们需要一个不同的解决方案……

  • iOS 12及以下系统有一个Mac OS中不存在的怪癖。奇怪的是,Audio元素的volume属性不能成功地设置为1以外的任何值。这是因为苹果不允许在iOS设备上更改Audio元素的音量,但在Mac OS上允许。这一特点可以作为区分iOS设备和Mac OS设备的最终备用方法。

检测iOS(包括<12和13+)

社区维基,因为编辑队列说它是满的,所有其他答案目前是过时或不完整的。

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

没有必要测试navigator.userAgentnavigator.platform:

const isIOS = typeof navigator.standalone === 'boolean';

navigator.standalone只在iOS Safari上设置。见中数Safari HTML参考

如果你正在使用React,有一个很棒的库可以解决这类问题:REACT-UGENT。(使用ua-parser-js构建。)

https://github.com/medipass/react-ugent

可用的浏览器有:

Chrome, chromium, edge, firefox,即,lynx, safari, opera

可用的操作系统包括:

安卓,黑莓,铬操作系统,debian, ios, linux, MAC操作系统,ubuntu, unix, Windows

可选设备包括:

游戏机、电脑、手机、平板电脑、智能电视、可穿戴、嵌入式

易于使用:

<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

因为navigator.platform已弃用,最好不要再使用它,所以我想添加一个其他解决方案。

你可以在MacOS系统上通过检查navigator.vendor. #来过滤。 当结果是Apple Computer, Inc.时,你知道它是MacOS

如果你还在尝试检查是否是iOS,我建议你使用以下方法:

  1. 创建一个名为helper的文件夹
  2. 创建名为platform.tsplatform.js的文件
  3. 导出函数isIOS:
export const isIOS = () => {
let platform = navigator?.userAgent || navigator?.platform || 'unknown'


return /iPhone|iPod|iPad/.test(platform)
}

如果是iPhoneiPodIpad,则结果将是true,否则将是false

你可能会问,为什么我需要检查navigator.userAgent || navigator.platform,原因很简单,第二个选项曾经是默认的,但现在它已被弃用,一些浏览器将在未来停止支持这个,第一个更可靠。

你可以在这里查看我上面提到的反对意见:

# EYZ0。

记录userAgentDatauserAgentplatform

使用下面的函数,我收到了这些日志:

    console.log({
userAgentData: navigator?.userAgentData?.platform,
userAgent: navigator?.userAgent,
platform: navigator?.platform,
})


{
"userAgentData": "",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
"platform": "MacIntel"
}


我在自己的Macbook电脑上测试了它,它在不同的浏览器和操作系统上都能运行。因此,正如你所看到的,navigator?.userAgentData?.platform将根本不起作用。

# EYZ0。

奖金,isAndroid

如果你想知道如何检查是否是Android平台,我建议你不要遵循与isIOS相反的想法:

const isAndroid = !isIOS();
原因很简单,因为桌面将被识别为Android平台,所以它将不起作用。 要解决这个问题,你只需要做这个检查:

export const isAndroid = () => {
const ua = navigator.userAgent.toLowerCase() + navigator?.platform.toLowerCase();
const isAndroid = ua.indexOf("android") > -1;


return isAndroid;
}

我们检查navigator.userAgent + navigator?.platform的原因是为了支持旧浏览器和新浏览器。