如何在iOS 13及以上版本中检测iPad和iPad操作系统版本?

31

我可以在iPhone上检测到iOS 13,但在iPad OS 13上navigator.platform显示为MacIntel。因此,无法使用以下代码识别iPad,但在iPhone上完美运行。

    if (/iP(hone|od|ad)/.test(navigator.platform)) {
            var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
            var version = [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
            return version;
    }

当我们使用iPad上的浏览器请求移动网站时,navigator.platform 返回的是iPad并可以正常工作。

有人可以建议一种使用Javascript识别运行iOS 13及以上版本的iPad的方法吗?


1
可能是告诉Web上的iPadOS与macOS的重复问题。 - Eugene Berdnikov
6个回答

36

我通过检查navigator.maxTouchPointsnavigator.platform,成功地实现了iPad的检测。虽然它并不完美(如下面的评论中所讨论的),但这是目前我找到的最佳解决方案,所以我想分享一下。

const iPad = (userAgent.match(/(iPad)/) /* iOS pre 13 */ || 
  (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) /* iPad OS 13 */);

如果用户有触摸屏显示器,这会返回true吗? - Kris
2
@Kris 我已经更新了代码,使用 navigator.platform,我认为至少对于我的应用程序来说这将是有效的。目前还没有触摸屏 Mac(但是)任何触摸屏 MacIntel 平台都应该是 iPadOS 13+?我猜他们可能会有第三方触摸屏显示器,但我不确定 MacOS 会如何响应??如果有其他方法,我会很高兴尝试,但这是目前我看到的唯一有效的方法。 - Stenerson
添加window.devicePixelRatio检测可以帮助区分iPad和iPhone。在新款iPhone上,window.devicePixelRatio == 3,而所有的iPad都是window.devicePixelRatio == 2。 https://51degrees.com/blog/device-detection-for-apple-iphone-and-ipad - Justin Putney
@JustinPutney 这不是一个好的解决方案,因为iPhone 2-7也会返回2 - Mick
2
Phaser解决方案 https://github.com/azerion/phaser/commit/554eeca5935f6311227c9be1c1331ffcd94abdc2#diff-de672b8173a52c4541cf4d3841682351R1228 - Florent
显示剩余3条评论

12

简而言之:

const iPad = !!(navigator.userAgent.match(/(iPad)/)
  || (navigator.platform === "MacIntel" && typeof navigator.standalone !== "undefined"))

我们可以使用navigator.standalone参数。它目前仅在iOS Safari上非标准且仅用于此:

Navigator.standalone

返回一个布尔值,指示浏览器是否以独立模式运行。仅适用于苹果的iOS Safari。

当与navigator.platform === "MacIntel"结合使用时,iPad是唯一定义此属性的设备,因此typeof navigator.standalone !== "undefined"可过滤运行Safari的Mac设备(触摸屏或非触摸屏)。

我设置了一个CodeSandbox,并在Browserstack上进行了手动测试,看起来像预期的那样工作:https://bc89h.csb.app/

版本检测(仅限iOS)

我没有对此进行过多的测试,但应该为其他人提供一个良好的起点:

const version = navigator.userAgent.match(/Version\/(\d+)\.(\d+)\.?(\d+)?/);
const major = version && version[1] ? version[1] : "";
const minor = version && version[2] ? version[2] : "";
const patch = version && version[3] ? version[3] : "";

上述内容将版本拆分为主要、次要和修补程序元素。这似乎适用于我对iOS 12和13进行的快速测试。上面的沙箱链接显示了输出结果。


在 TL;DR 中,您可以只使用 /iPad/ 而不需要括号。 - damd

3
您可以使用WURFL.js,如果您只想知道正在使用的设备是什么,它是免费的:https://web.wurfl.io/#wurfl-js 完全透明,我是WURFL和ImageEngine背后公司的COO,但我也是一个开源开发者:an open-source developer :)
WURFL.js可以告诉您正在使用哪个操作系统以及是否为iPhone或iPad。
要使用它,只需将以下内容添加到页面头部即可:
<script type="text/javascript" src="//wurfl.io/wurfl.js"></script>

然后你可以在JavaScript中使用设备信息:
console.log(WURFL.complete_device_name);

注:使用付费版本,您可以获得更准确的结果(例如:Apple iPhone XS MaxApple iPad Pro 11),以及许多其他设备特性。
如果您不需要初始绘制所需的设备信息,则还可以异步运行它,以便不会阻塞呈现。将其放在 body 的末尾,并使用 asyncdefer:
<script type="text/javascript">
window.addEventListener('WurflJSDetectionComplete', () => {
   console.log(`Device: ${WURFL.complete_device_name}`);
});
</script>
<script type="text/javascript" src="//wurfl.io/wurfl.js" async></script>

顺便说一下,您可以利用这个改进的设备信息来增强Google Analytics: https://www.scientiamobile.com/wurfljs-google-analytics-iphone/

请注意,与其他答案不同,这个答案不需要开发人员进行持续的维护。


在iPad上,只有在Safari设置中取消请求桌面站点时,它才会显示平板电脑,而所有用户可能都不会这样做。默认情况下,它会显示桌面站点。 - Rudy
确实是这样,感谢澄清。苹果在去年推出了这个功能,不幸的是目前还没有已知的绕过方法,尤其是在防止指纹识别方面下了很多功夫。 - SteveK

3
简单来说,你不能直接做到。你只能使用类似这样的黑科技手段。
let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)

第一个条件是“移动设备”,第二个条件是 iPad 模拟 Macintosh Safari。对我而言,它运作稳定,但未来可能发生变化。如果未来有带有触摸屏的 Mac 电脑,这将不仅检测桌面模式下的 iPad,也会检测普通的 Mac 电脑。
另一种方法是特性检测——你可以依赖浏览器特性支持,但不应完全依赖它。例如,Mac 上的 Safari 不支持日期选择器,但移动版却支持。
总之,我建议你不要依赖平台检测(未来它将失效),而是像 Modernizr 这样使用特性检测(但不是用于区分平台)——如果你想使用日期选择器,你可以检查其是否可用,如果不行,可以使用 HTML 替代方案。不要因为用户使用某些其他浏览器就锁定他们。你可以通知他们但给予隐藏通知并继续使用网站的选项。
作为用户,当有人告诉我去使用另一个浏览器时,我很讨厌。
请记住——平台检测表明存在糟糕的代码气味,因为所有这些都是 hack。

1

我稍微扩展了实现,利用了一些iPad OS相对于Mac OS Catalina更多的默认浏览器功能。根据我在各种iPad和所有晚期iOS设备上的测试,这个实现效果很好。

var isIPadOs = window.AuthenticatorAssertionResponse === undefined
        && window.AuthenticatorAttestationResponse === undefined
        && window.AuthenticatorResponse === undefined
        && window.Credential === undefined
        && window.CredentialsContainer === undefined
        && window.DeviceMotionEvent !== undefined
        && window.DeviceOrientationEvent !== undefined
        && navigator.maxTouchPoints === 5
        && navigator.plugins.length === 0
        && navigator.platform !== "iPhone";

概要:https://gist.github.com/braandl/f7965f62a5fecc379476d2c055838e36

谢谢你的努力!但是这个改变不会随着下一个iPadOS或iPad设备而改变吗? - Mick
是的,绝对没错。所有这些“指纹识别”方法最终都需要更新... 不过由于我的经验与苹果浏览器更新政策相符,这应该还可以再用一段时间... - braandl
@braandl 谢谢你!不过 window.CredentialsContainer 里有个错别字! - Patrick Hübl-Neschkudla

0

这个方法有点hackish,肯定不是很安全,但目前我们正在使用以下方法,似乎可以解决问题。

第一个块只是为了检测旧版iPad的用户代理,而在“OR”之后的第二个块则是检查平台是否为Macintosh并具有触摸点。在撰写本文时,Mac尚未推出官方触摸屏,因此应该相当安全一段时间。

if ((/\b(iPad)\b/.test(navigator.userAgent)
    && /WebKit/.test(navigator.userAgent)
    && !window.MSStream)
    || (navigator.platform === 'MacIntel'
    && navigator.maxTouchPoints
    && navigator.maxTouchPoints === 5)
  ) {
        return true;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接