Определить, является ли устройство iOS

409

Мне интересно, можно ли определить, работает ли браузер на iOS, подобно тому, как вы можете определять функцию с помощью Modernizr (хотя это, очевидно, обнаружение устройства, а не обнаружение функции).

Обычно я предпочел бы вместо этого обнаружение функций, но мне нужно выяснить, является ли устройство iOS из-за того, как они обрабатывают видео, в соответствии с этим вопросом YouTube API не работает с iPad / iPhone / не-Flash устройством

SparrwHawk
источник
Смотрите [Что такое строка агента пользователя iOS 5?] [1] (дубликат?). [1]: stackoverflow.com/questions/7825873/…
dejuknow
1
Это обнаружение на стороне клиента или на стороне сервера?
Дуглас Гриншилдс
Привет @DouglasGreenshields, это на стороне клиента
SparrwHawk
1
Кроме того, не дубликат, я спрашиваю, как это сделать. Я никогда не использовал пользовательский агент сниффинг раньше.
SparrwHawk
stackoverflow.com/questions/19877924/…
Кристоф Русси

Ответы:

822

Обнаружение 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 Update):

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';
}
пьер
источник
2
Спасибо, Пьер, хотя этот код кажется более простым, мне просто интересно, могу ли я просто указать «iOS» вместо необходимости набирать все отдельные iDevices .... if ((navigator.userAgent.match (/ iPhone / i)) | | (navigator.userAgent.match (/ iPod / i)) || (navigator.userAgent.match (/ iPad / i)))) // // Сделать что-то}
SparrwHawk
9
То, что вы делаете во втором фрагменте, это вывод функций, а не обнаружение функций. Обнаружение функций - это тестирование функций, которые вы на самом деле собираетесь использовать, тогда как то, что вы делаете, это тестирование функций, которые, как вы знаете, были введены в определенной версии ОС и выводят версию ОС из них. Это хрупко, потому что будущие версии iOS могут удалить эти функции.
Тим Даун
23
Это лучший способ выписать свой чек:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp
5
Напоминаем, что массив navigator.platform не работает на симуляторе iPad, поскольку в строке платформы содержится вся фраза «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
kikiwora
источник
Почему бы не использовать navigator.userAgentдля этой проверки /iPad|iPhone|iPod/.test(navigator.platform)? Кажется, что navigator.platformвсегда возвращает «MacIntel» для iPhone iOS <= 12
Харис Тео
@CharisTheo, потому что iPad не в пользовательском агенте в iOS> = 13
Kzrbill
но вы уже проверяете для iPad iOS> = 13 во второй проверке или я что-то упустил?
Харис Тео
navigator.maxTouchPointsне поддерживается в iOS, так что проверка ничего не сделает для вас.
PaulC
@PaulC, Вы правы в том, что maxTouchPoints не определено для iOS 12 и ниже, но kikiwora находится на правильном пути, так как maxTouchPoints поддерживается в iOS 13. Смотрите мой ответ.
Боб Арлоф
14

Это устанавливает переменную _iOSDeviceв true или false

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
Vitim.us
источник
3
что значит !! делать?
Патрик
4
Двойное отрицание @astronought используется для приведения к логическому
значению
2
@astronought bang bang, ты
логичен
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');
}
ThiagoPXP
источник
2
Будьте осторожны, Modernizr автоматически вводит нижний регистр имени добавленного теста. (в вашем примере Modernizr.isiOS никогда не вернет true). Плохое поведение lib на мой взгляд ...
Cétia
3
Просто крошечное замечание: вы можете упростить return x ? true : falseдо return Boolean(x)или простоreturn !!x
tibalt
6

Упрощенная, легко расширяемая версия.

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
Кори Нанн
источник
1
Если вы хотите , чтобы это работало на IOS Simulator вы можете использовать: navigator.platform.replace(' Simulator', '').
Koraktor
Но это не работает, потому что['str'].indexOf('string') == -1
tibalt
navigator.platform будет точно «IPad», «iPhone» или «IPOD» , если тренажер не работает.
Кори Нанн
4

Вероятно, стоит ответить, что iPad под управлением iOS 13 будет 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

Пользовательские агенты на устройствах iOS говорят iPhone или iPad в них. Я просто фильтрую по этим ключевым словам.

Брайан Нагеле
источник
4
Также есть iPod Touch.
Дуглас Гриншилдс
@DouglasGreenshields Правильно. Забыл об этом, но я верю, что он передает свою личность и в пользовательском агенте.
Брайан Наегеле
Пользовательский агент iPad Safari больше не будет включать «iPad» из iPadOS 13.
Джонни
2

Везде, где возможно, при добавлении тестов 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 (в данном случае я на самом деле показываю альтернативное изображение с кликом для воспроизведения видео - я просто не хочу показывать видеоплеер и кнопку воспроизведения по умолчанию).

Simon_Weaver
источник
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);
  • Это быстро, потому что регулярное выражение сначала проверяет начальную позицию строки платформы в ^ s и останавливается, если нет «iP» (быстрее, чем поиск длинной строки UA до конца)
  • Это безопаснее, чем проверка UA (если предположить, что navigator.platform менее поддельный)
  • Обнаруживает iPhone / iPad Simulator


ОБНОВЛЕНИЕ: Это не распространяется на iPad в режиме рабочего стола (и, следовательно, по умолчанию iPadOS 13).
Это хорошо для моих случаев использования, если это не для вас, посмотрите ответы Джастина и Кикиворы.

JJ
источник
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);вместо этого я хотел бы использовать iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); в качестве запасного варианта, потому что в моем случае navigator.platform не работал, но делал это, как позже, работал нормально
Coderboi
navigator.platformне работал? Вы действительно на iOS тогда? Проверьте с jeka.info/test/navigator.html . userAgentдает ложные срабатывания, потому что некоторые производители подделывают его, чтобы имитировать устройства 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 dev tools. Я получаюMacIntel
sdfsdf
1

Вы также можете использовать includes

  const isApple = ['iPhone', 'iPad', 'iPod'].includes(navigator.platform)
Алан
источник
1

Ни один из предыдущих ответов здесь не работает для всех основных браузеров на всех версиях 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.

Боб Арлоф
источник
-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, а не обнаружение мобильного»
Cybersupernova
-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;
    }
viebel
источник
-2

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

Митхун Шридхаран
источник