510

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

通常我更喜欢功能检测,但我需要确定设备是否是 iOS,因为他们根据这个问题处理视频的方式YouTube API not working with iPad / iPhone / non-Flash device

4

20 回答 20

994

检测 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 字符串中解析它。但也有特征检测推断*

我们知道在iOS4 - iOS5 - iOS6 - iOS7等中history API引入的事实。matchMedia APIwebAudio APIWebSpeech 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';
}
于 2012-01-27T20:51:26.633 回答
59

在 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
于 2019-09-23T15:03:27.300 回答
18

这会将变量设置_iOSDevicetruefalse

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
于 2013-08-08T19:03:46.743 回答
14

此处之前的答案均不适用于所有 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 不允许在AudioiOS 设备的元素上更改音量,但对于 Mac OS 则允许。这个怪癖可以用作区分 iOS 设备和 Mac OS 设备的最终后备方法。

于 2020-05-29T21:20:55.927 回答
10

如果您使用的是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');
}
于 2013-05-27T08:18:59.707 回答
8

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

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
于 2014-03-18T00:20:13.077 回答
7

更新:我的原始答案不包括桌面模式下的 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 个触摸点)
  • 它很快,因为正则表达式^首先检查平台字符串的起始位置,如果没有“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);
于 2018-09-21T17:55:43.283 回答
5

可能值得回答的是,运行 iOS 13 的 iPad 将navigator.platform设置为MacIntel,这意味着您需要找到另一种方法来检测 iPadOS 设备。

于 2019-07-21T14:53:11.057 回答
5

检测 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());
于 2020-10-05T11:11:30.917 回答
2

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

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

    }
于 2012-12-05T04:24:17.227 回答
2

在添加 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 的替代图像来播放视频 - 我只是不希望显示默认的视频播放器和播放按钮)。

于 2014-05-10T19:23:18.670 回答
1

iOS 设备上的用户代理在其中说 iPhone 或 iPad。我只是根据这些关键字进行过滤。

于 2012-01-27T19:06:29.660 回答
1

如果你使用 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

于 2021-09-14T12:30:50.563 回答
0

使用更实用的方法稍微更新第一个答案。

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;
于 2019-06-06T13:25:13.857 回答
0

你也可以使用includes

  const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(navigator.platform)
于 2020-05-27T05:17:23.730 回答
0

无需测试navigator.userAgentor navigator.platform

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

navigator.standalone仅在 iOS Safari 上设置。请参阅MDNSafari HTML 参考

于 2021-06-18T09:45:02.600 回答
0

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

您可以通过选中navigator.vendor. 当结果为Apple Computer, Inc.时,您就知道它是 MacOS。

于 2021-11-16T18:04:02.383 回答
-1

在我的情况下,用户代理不够好,因为在 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
}
于 2020-05-04T10:40:29.467 回答
-2

var isiOSSafari = (navigator.userAgent.match(/like Mac OS X/i)) ? true: false;

于 2013-02-12T17:45:43.270 回答
-3

为了检测 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;
    }
于 2012-02-19T16:05:06.140 回答