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

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


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要么为真,要么为假

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

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

在iPad iOS 13上,用户代理与MacOS 13计算机上的用户代理相同,但如果你忽略iPad,这可能仍然可以工作一段时间:

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

!窗口。MSStream是为了不错误地检测IE11,请看这里和这里。

注意:都是导航器。userAgent和navigator。平台可以被用户或浏览器扩展伪造。

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

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

检测iOS版本

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

我们知道,历史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");

    }

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


如果您正在使用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设置为true或false

_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字符串直到结束快)。 它比导航仪安全。userAgent检查为导航器。平台不太可能是伪造的 检测iPhone / iPad模拟器


ORIGINAL ANSWER:
Wow, a lot of longish tricky code here. Keep it simple, please!

以我之见,这一个速度快,省钱,而且运行良好:

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

  // or, if you prefer it verbose:
 iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);

可能值得回答的是,运行iOS 13的ipad将有导航器。平台设置为MacIntel,这意味着你需要找到另一种方法来检测iPadOS设备。


在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。

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

P.S.如前所述,你可能应该添加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
}

你也可以使用include

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

请注意,此代码片段的编写优先考虑的是可读性,而不是简洁性或性能。

解释:

If the user agent contains any of "iPod|iPhone|iPad" then clearly the device is iOS. Otherwise, continue... Any other user agent that does not contain "Macintosh" is not an Apple device and therefore cannot be iOS. Otherwise, it is an Apple device, so continue... If maxTouchPoints has a value of 1 or greater then the Apple device has a touch screen and therefore must be iOS since there are no Macs with touch screens (kudos to kikiwora for mentioning maxTouchPoints). Note that maxTouchPoints is undefined for iOS 12 and below, so we need a different solution for that scenario... iOS 12 and below has a quirk that does not exist in Mac OS. The quirk is that the volume property of an Audio element cannot be successfully set to any value other than 1. This is because Apple does not allow volume changes on the Audio element for iOS devices, but does for Mac OS. That quirk can be used as the final fallback method for distinguishing an iOS device from a Mac OS device.


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

没有必要测试导航器。userAgent或navigator.platform:

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

导航器。standalone只在iOS Safari上设置。参见MDN, Safari HTML参考。


如果你正在使用React,有一个很棒的库可以解决这类问题:React - agent。(使用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.vendor来过滤MacOS系统。 当结果是苹果电脑公司,你知道它是MacOS。


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

创建一个名为helper的文件夹 创建一个名为platform的文件。Ts或platform.js 导出函数isIOS:

export const isIOS = () => {
    let platform = navigator?.userAgent || navigator?.platform || 'unknown'

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

如果是iPhone或iPod或Ipad,结果为真,否则为假。

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

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

https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform: ~:文本3 =弃用% % 20这% % 20 20特性是% 20不,% 20保持% 20 % 20兼容性% 20目的。

记录userAgentData、userAgent和平台。

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

    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 ?。平台根本不起作用。

我也没有收到任何与我的typescript相关的错误,即使我使用React调用这个函数。

奖金、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;
}

我们检查导航器的原因。userAgent + navigator?平台支持新旧浏览器。