Определить, является ли устройство iOS
Мне интересно, возможно ли определить, работает ли браузер на iOS, подобно тому, как вы можете определять функцию с помощью Modernizr (хотя это, очевидно, обнаружение устройства, а не обнаружение функции).
Обычно я предпочел бы вместо этого обнаружение функций, но мне нужно выяснить, является ли устройство iOS из-за того, как они обрабатывают видео, в соответствии с этим вопросом YouTube API не работает с iPad / iPhone / не-Flash устройством
25 ответов
Обнаружение 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
будет либо true
или же false
Почему не MSStream
Microsoft ввела слово iPhone в IE11 userAgent
чтобы попытаться обмануть Gmail как-то. Поэтому мы должны исключить это. Больше информации об этом здесь и здесь.
Ниже обновлен IE11 userAgent
(Обновление Internet Explorer для Windows Phone 8.1):
Mozilla / 5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident / 7.0; Touch; rv: 11.0; IEMobile / 11.0; NOKIA; Lumia 930), например iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, например Gecko) Мобильное Сафари / 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()
будет либо true
или же false
Примечание: оба navigator.userAgent
а также navigator.platform
может быть подделан пользователем или расширением браузера.
Определение версии iOS
Наиболее распространенный способ определения версии iOS - это анализ ее по строке User Agent. Но есть также вывод обнаружения функции *;
Мы точно знаем, что history API
был представлен в iOS4 - matchMedia API
в iOS5 - webAudio API
в iOS6 - WebSpeech API
в iOS7 и так далее..
Примечание. Следующий код не является надежным и будет поврежден, если какая-либо из этих функций HTML5 устарела в более новой версии iOS. Вы были предупреждены!
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';
}
После iOS13 вы должны обнаруживать такие устройства 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
Ни один из предыдущих ответов здесь не работает для всех основных браузеров во всех версиях iOS, включая iOS 13. Вот решение, которое работает для Safari, Chrome и Firefox для всех версий iOS:
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 не разрешает изменять громкость наAudio
для устройств iOS, но есть для Mac OS. Эту причуду можно использовать в качестве последнего запасного метода для отличия устройства iOS от устройства Mac OS.
Это устанавливает переменную _iOSDevice
правда или ложь
_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
Если вы используете 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');
}
Вау, здесь много длинного хитрого кода. Будьте проще, пожалуйста!
Это ИМХО быстро, сохранить и работать хорошо:
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);
- Это быстро, потому что регулярное выражение сначала проверяет стартовую позицию ^ строки строки платформы и останавливается, если нет "iP" (быстрее, чем поиск длинной строки UA до конца)
- Это безопаснее, чем проверка UA (если предположить, что navigator.platform менее поддельный)
- Обнаруживает iPhone / iPad Simulator
Упрощенная, легко расширяемая версия.
var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
Есть этот кастомный тест Модернизра: https://gist.github.com/855078
Обнаружение 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());
Наверное, стоит ответить, что iPad под управлением iOS 13 будет иметь navigator.platform
установлен в MacIntel
, а это значит, что вам нужно будет найти другой способ обнаружения устройств iPadOS.
Пользовательские агенты на устройствах iOS говорят iPhone или iPad в них. Я просто фильтрую по этим ключевым словам.
Я написал это пару лет назад, но я верю, что это все еще работает:
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");
}
Нет необходимости тестировать
navigator.userAgent
или же
navigator.platform
:
const isIOS = typeof navigator.standalone === 'boolean';
navigator.standalone
устанавливается только в iOS Safari. См. MDN, Справочник по Safari HTML .
Если вы используете React, для такого рода проблем есть отличная библиотека: REACT-UGENT. (Создан с использованием ua-parser-js.)
https://github.com/medipass/react-ugent
Доступные браузеры:
хром, хром, край, firefox, т.е. рысь, сафари, опера
Доступные ОС:
Android, Blackberry, Chrome OS, 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
Везде, где возможно, при добавлении тестов 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 (в данном случае я на самом деле показываю альтернативное изображение с кликом для воспроизведения видео - я просто не хочу показывать видеоплеер и кнопку воспроизведения по умолчанию).
Если вы все еще пытаетесь проверить, iOS это или нет, я рекомендую вам использовать этот подход:
- Создайте папку под названием
helper
- Создайте файл с именем
platform.ts
илиplatform.js
- Экспорт функции:
export const isIOS = () => {
let platform = navigator?.userAgent || navigator?.platform || 'unknown'
return /iPhone|iPod|iPad/.test(platform)
}
Результат будет
true
если это
iPhone
или
iPod
или
Ipad
или это будет
false
в противном случае.
Вы спросите, а зачем мне проверятьnavigator.userAgent || navigator.platform
, причина проста: второй вариант использовался по умолчанию, но теперь он устарел, и некоторые браузеры перестанут поддерживать его в будущем, первый вариант более надежен.
Вы можете проверить здесь об устаревании, о котором я упоминал выше:
РегистрацияuserAgentData
,userAgent
иplatform
.
Используя функцию ниже, я получил эти журналы:
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?.platform
не будет работать вообще.
Я также не получил никаких ошибок, связанных с моим машинописным текстом, хотя я использую React для вызова этой функции .
Бонус, это Android
Если вам интересно, как проверить, является ли платформа 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;
}
Причина, по которой мы проверяемnavigator.userAgent
плюсnavigator?.platform
заключается в поддержке старых браузеров и новых.
Слегка обновите первый ответ, используя более функциональный подход.
const isIOS = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod',
].indexOf(navigator.platform) !== -1;
Вы также можете использовать includes
const isApple = ['iPhone', 'iPad', 'iPod', 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator',].includes(navigator.platform)
Для всех, кто хочет соответствовать рекомендациям PageSpeed Insights и Lighthouse, которые помечают «проблемы», обнаруженные в консоли, для использованияnavigator.userAgent
(и т. д.), это может вам помочь (я почерпнул это из Boostrap 5):
function getUAString() {
let uaData = navigator.userAgentData;
if (null !== uaData && uaData.brands) {
return uaData.brands.map(item => item.brand + '/' + item.version).join(' ');
}
return navigator.userAgent;
}
const isIOS = /iP(hone|od|ad)/.test(getUAString());
это было мое решение после многих страданий, оно не идеально, но надеюсь помочь кому-нибудь.
function detectSafariOnIpadOS() {
var userAgent = navigator.userAgent;
var isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);
var isIpad = /iPad/i.test(userAgent);
var isMacintosh = /Macintosh/i.test(userAgent);
var isTouchDevice = "ontouchend" in document;
console.log("User Agent:", userAgent);
console.log("detectSafariOnIpadOS result:", isSafari && (isIpad || (isMacintosh && isTouchDevice)));
return isSafari && (isIpad || (isMacintosh && isTouchDevice));
}
Используйте проверки Apple Pay JS API
`if (window.dw && window.dw.applepay && window.ApplePaySession && window.ApplePaySession.canMakePayments()) {
// сделать все необходимое
}`
Потому что
navigator.platform
устарел, и лучше его больше не использовать, я хочу добавить другое решение.
Вы можете фильтровать в системах MacOS, проверив
navigator.vendor
. Когда результат
Apple Computer, Inc.
, вы знаете, что это MacOS.
В моем случае пользовательский агент был недостаточно хорош, так как в 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
}
var isiOSSafari = (navigator.userAgent.match(/like Mac OS X/i)) ? true: false;
Чтобы определить версию 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;
}