检测设备是否为iOS


408

我想知道是否有可能检测浏览器是否在iOS上运行,这与使用Modernizr进行功能检测的方式类似(尽管这显然是设备检测而非功能检测)。

通常,我宁愿使用功能检测,但我需要根据该问题确定设备是否为iOS,因为它们处理视频的方式YouTube API无法在iPad / iPhone /非Flash设备上使用


请参阅[什么是iOS 5用户代理字符串?] [1](重复?)。[1]:stackoverflow.com/questions/7825873/...
dejuknow

1
这是客户端还是服务器端检测?
Douglas Greenshields 2012年

嘿@DouglasGreenshields,它是客户端
SparrwHawk,2012年

1
另外,不是重复,我在问怎么做。我以前从未使用过用户代理嗅探。
SparrwHawk 2012年

Answers:


821

检测iOS

我不喜欢User Agent嗅探,但是您可以按照以下方式进行:

var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

另一种方法是依靠navigator.platform

var iOS = navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);

iOS将是truefalse

为什么不使用MSStream

微软在IE11中注入了iPhone一词,userAgent以试图以某种方式欺骗Gmail。因此,我们需要排除它。关于这方面更多的信息在这里这里

以下是IE11的更新userAgent(适用于Windows Phone 8.1的Internet Explorer更新):

Mozilla / 5.0(移动; Windows Phone 8.1; Android 4.0; ARM; Trident / 7.0;触摸; rv:11.0; IEMobile / 11.0;诺基亚; Lumia 930),例如iPhone OS 7_0_3 Mac OS X AppleWebKit / 537(KHTML,例如Gecko)移动版Safari / 537


无需使用正则表达式即可轻松添加更多设备:

function iOS() {

  var iDevices = [
    'iPad Simulator',
    'iPhone Simulator',
    'iPod Simulator',
    'iPad',
    'iPhone',
    'iPod'
  ];

  if (navigator.platform) {
    while (iDevices.length) {
      if (navigator.platform === iDevices.pop()){ return true; }
    }
  }

  return false;
}

iOS()将是truefalse

注意:无论navigator.userAgent并且navigator.platform可以由用户或浏览器扩展伪造。


检测iOS版本

检测iOS版本的最常见方法是通过User Agent字符串进行解析。但是也有特征检测推论* ;

我们知道,一个事实,history API在引进的iOS4 - matchMedia APIiOS5中 - webAudio APIiOS6的 - WebSpeech APIiOS7等..

注意:以下代码不可靠,如果在更新的iOS版本中不推荐使用这些HTML5功能,则这些代码将中断。你被警告了!

function iOSversion() {

  if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
    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';
}

2
谢谢Pierre-尽管此代码似乎更简单,但我只是想知道是否可以仅指定'iOS'而不是必须键入所有单独的iDevices...。 |((navigator.userAgent.match(/ iPod / i))||(navigator.userAgent.match(/ iPad / i))){//做某事}
SparrwHawk 2012年

9
您在第二个片段中所做的是功能推断,而不是功能检测。功能检测是测试您实际要使用的功能,而您正在做的是测试您碰巧知道的功能是在特定版本的OS中引入的,并从中推断出OS版本。这很脆弱,因为将来的iOS版本可能会删除这些功能。
蒂姆·唐

23
这是写支票的更好方法:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp 2013年

5
请注意-navigator.platform数组在iPad Simulator上不起作用,因为它在平台字符串中包含整个短语“ iPad Simulator”。
凯文·纽曼

9
从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因此此答案需要更新
zvi

38

在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)?似乎navigator.platform总是为iPhone iOS <= 12返回'MacIntel'
Charis Theo

@CharisTheo因为iPad不在iOS中的userAgent中> = 13
Kzrbill 19/12/20

但您已经在第二次检查中检查的是iPad iOS> = 13还是我遗漏了什么?
Charis Theo

navigator.maxTouchPoints在iOS中不受支持,因此支票不会为您做任何事情。
PaulC

@PaulC,您的说法是正确的,对于iOS 12及以下版本,maxTouchPoints尚未定义,但由于iOS 13支持maxTouchPoints,因此kikiwora处于正确的轨道。
鲍勃·阿洛夫

14

这会将变量设置_iOSDevicetruefalse

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

3
什么!做?
帕特里克

4
@astronought双重否定用于转换为布尔值
Vitim.us

2
@astronought bang bang,你是布尔值:D
Qback

1
使用/iPhone|iPod|iPad/.test(navigator.platform)您可以避免!!
lionello,

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');
}

2
请注意,Modernizr会自动小写所添加测试的名称。(在您的示例中,Modernizr.isiOS将永远不会返回true)。在我看来,LIB不良行为...
Cétia

3
只是微小的通知:您可以简化return x ? true : falsereturn Boolean(x)或只是return !!x
tibalt


6

简化,易于扩展的版本。

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

1
如果您还希望它在iOS Simulator上运行,则可以使用:navigator.platform.replace(' Simulator', '')
Koraktor 2015年

但这是行不通的,原因['str'].indexOf('string') == -1
tibalt 2015年

除非模拟器正在运行,否则navigator.platform将完全是 “ iPad”,“ iPhone”或“ iPod”。
Kory Nunn

4

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


3

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

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

    }


2

添加Modernizr测试时,应尽可能添加针对功能而不是设备或操作系统的测试。如果需要的话,添加十项针对iPhone的测试完全没有错。有些东西只是无法检测到。

    Modernizr.addTest('inpagevideo', function ()
    {
        return navigator.userAgent.match(/(iPhone|iPod)/g) ? false : true;
    });

例如,在iPhone(不是iPad)上的视频无法在网页上内联播放,它会全屏显示。所以我创建了一个测试“无页内视频”

然后,您可以在CSS中使用它(如果测试失败,Modernizr会.no-inpagevideo<html>标签中添加一个类)

.no-inpagevideo video.product-video 
{
     display: none;
}

这将在iPhone上隐藏视频(在这种情况下,我实际上正在做的是显示带有单击单击的替代图像来播放视频-我只是不希望显示默认的视频播放器和播放按钮)。


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

2

哇,这里有很多冗长的棘手代码。请保持简单!

这是恕我直言,快速,保存,并且工作良好:

 iOS = /^iP/.test(navigator.platform);

 // or, more future-proof (in theory, probably not in practice):

 iOS = /^iP(hone|[ao]d)/.test(navigator.platform);

 // or, if you prefer readability:

 iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);
  • 之所以快,是因为regexp首先检查平台字符串的^ s放置位置,如果没有“ iP”,则停止(比搜索长UA字符串直到结束都要快)
  • 它比UA检查更安全(假设navigator.platform不太可能被伪造)
  • 检测iPhone / iPad模拟器


更新:这不包括台式机模式下的 iPad (因此不包括默认的iPadOS 13)。
这对我的用例很好,如果不适合您,请参阅Justin和kikiwora的答案。


iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);而不是这样做iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); ,我会 在我的情况下作为后备措施cuz在navigator.platform中不起作用,但是像以后那样工作时效果很好
Coderboi

navigator.platform没有工作吗?那您真的在iOS上吗?检查jeka.info/test/navigator.htmluserAgent之所以提供误报,是因为无论出于何种原因,一些供应商都会伪造它来模仿Apple设备。vendor刚刚传回Google Inc.Apple Computer, Inc.或没有(在Firefox)。
jj

1

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

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

在Brave / Chrome开发人员工具移动模拟器中无法使用。我得到MacIntel
sdfsdf

1

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


0

您也可以使用 includes

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

-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
}

刚刚读了一个问题,它说检测iOS,而不检测移动
Cyber​​supernova

-2

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.