ChatGPT解决这个技术问题 Extra ChatGPT

检测设备是否为 iOS

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

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

请参阅 [什么是 iOS 5 用户代理字符串?][1](重复?)。 [1]:stackoverflow.com/questions/7825873/…
这是客户端还是服务器端检测?
嘿@DouglasGreenshields,它是客户端
另外,不是重复的,我在问怎么做。我以前从未使用过用户代理嗅探。

P
Paul Rumkin

检测 iOS

使用 iOS 13 iPad both User agent and platform strings are changeddifferentiating 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 将是 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,请参阅 herehere

注意: navigator.userAgentnavigator.platform 都可能被用户或浏览器扩展程序伪造。

存在用于更改 userAgent 或平台的浏览器扩展,因为网站使用过于严厉的检测并且经常禁用某些功能,即使用户的浏览器本来可以使用该功能。

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

检测 iOS 版本

检测 iOS 版本的最常用方法是通过 parsing it from the User Agent string。但也有特征检测推理*

我们知道 history API 是在 iOS4 中引入的 - iOS5 中的 matchMedia API - iOS6 中的 webAudio API - WebSpeech APIiOS7 等等。

注意:以下代码不可靠,如果这些 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 可能会删除这些功能。
这是写支票的更好方法:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
请注意 - navigator.platform 数组在 iPad 模拟器上不起作用,因为它在平台字符串中包含整个短语“iPad Simulator”。
MDN 表示 navigator.platform 已弃用且不依赖它。
从 iOS 13 开始,iPad 的用户代理已更改为“Mac OS”,例如:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15,因此需要更新此答案
k
kikiwora

在 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”
@CharisTheo 因为 iPad 不在 iOS 中的 userAgent >= 13
但是您已经在第二次检查中检查 iPad iOS >= 13 还是我遗漏了什么?
iOS 不支持 navigator.maxTouchPoints,因此该检查不会为您做任何事情。
@PaulC,您是正确的,对于 iOS 12 及更低版本未定义 maxTouchPoints,但由于 iOS 13 支持 maxTouchPoints,因此 kikiwora 走在正确的轨道上。请参阅我的答案。
V
Vitim.us

这会将变量 _iOSDevice 设置为 truefalse

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

什么!!做?
@astronought 双重否定用于转换为布尔值
@astronought 砰砰,你是布尔值:D
使用 /iPhone|iPod|iPad/.test(navigator.platform) 您可以避免 !!
B
Bob Arlof

此处之前的答案均不适用于所有 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 设备的最终后备方法。


似乎这会产生实际更改非 iOS 设备上的音量的副作用(以防这对任何人都很重要)
@Tspoon,提供的代码片段创建一个一次性的 Audio 元素(如有必要)。在这种情况下,该元素实际上并未用于播放声音,并且它不会影响您可能在系统中使用的其他 Audio 元素的音量。
C
Craig Conover

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

请注意,Modernizr 会自动将添加的测试名称小写。 (在您的示例中, Modernizr.isiOS 永远不会返回 true)。在我看来,lib 的不良行为......
只是很小的通知:您可以将 return x ? true : false 简化为 return Boolean(x) 或只是 return !!x
K
Kory Nunn

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

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

如果您还希望它在 iOS 模拟器上运行,您可以使用:navigator.platform.replace(' Simulator', '')
但它不起作用,因为 ['str'].indexOf('string') == -1
navigator.platform 将完全是“iPad”、“iPhone”或“iPod”,除非模拟器正在运行。
j
j.j.

更新:我的原始答案不包括桌面模式下的 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.htmluserAgent 给出误报是因为一些供应商出于任何原因伪造它以模仿 Apple 设备。 vendor 只返回 Google Inc.Apple Computer, Inc. 或什么都不返回(在 Firefox 中)。
navigator.platform 被劝阻:“[它] 应该几乎总是被避免以支持特征检测。”
J
Justin Searls

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


S
Simon B.

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

“平台”现在已弃用
M
Michael Benin

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

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

    }

S
Simon_Weaver

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


iOS10 现在允许 playsinline,因此您现在可以使用 'playsInline' in document.createElement('video'); 作为测试github.com/Modernizr/Modernizr/issues/2077
T
Tural Mehdiyev

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


B
Bryan Naegele

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


还需要考虑 iPod Touch。
@DouglasGreenshields 正确。忘了那个,但我相信它也会在用户代理中传输其身份。
iPad Safari 的用户代理将不再包含 iPadOS 13 中的“iPad”。
J
Jeffery To

无需测试 navigator.userAgentnavigator.platform

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

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


如果浏览器是chrome怎么办?
@IBG 刚刚尝试过,它在 iOs chrome 上返回“未定义”。所以这个答案不正确
@IBG我刚刚在iPhone(iOS 14.3)上的Firefox 38.1和iPad(iPadOS 15.0.2)上的Chrome 95.0.4638.50上试过这个,它在两者上都有效
@strix25 你确定你输入的代码正确吗?
在上面的 @JefferyTo 示例中使用 const 对我来说非常适合这个条件检查:if (isIOS === true ) { //stuff for iOS } else {// stuff for all other }
R
Royal

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

您可以通过选中 navigator.vendor 在 MacOS 系统上进行过滤。当结果为 Apple Computer, Inc. 时,您知道它是 MacOS。


navigator.vendor 也是 deprecated
S
Simon B.

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

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;

在 Brave/Chrome 开发工具移动模拟器中不起作用。我得到MacIntel
A
Alan

您也可以使用 includes

  const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(navigator.platform)

这错过了“......模拟器”品种。这么多的答案,很少有经过充分研究的:(
N
Neku80

在我的情况下,用户代理不够好,因为在 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
}

M
Mithun Sreedharan

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


这个三元运算符没用; test 返回一个布尔值并且可以替换 match
v
viebel

为了检测 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;
    }