Detectar si el dispositivo es iOS

409

Me pregunto si es posible detectar si un navegador se está ejecutando en iOS, de forma similar a cómo se puede detectar con Modernizr (aunque esto obviamente es detección de dispositivos en lugar de detección de características).

Normalmente preferiría la detección de funciones, pero necesito averiguar si un dispositivo es iOS debido a la forma en que manejan los videos según esta pregunta La API de YouTube no funciona con iPad / iPhone / dispositivo sin Flash

SparrwHawk
fuente
Consulte [¿Qué es la cadena de agente de usuario de iOS 5?] [1] (¿duplicado?). [1]: stackoverflow.com/questions/7825873/…
dejuknow
1
¿Es esta detección del lado del cliente o del lado del servidor?
Douglas Greenshields
Hola @DouglasGreenshields, es del lado del cliente
SparrwHawk
1
Además, no es un duplicado, estoy preguntando cómo hacerlo. Nunca he usado el agente de usuario olfateando antes.
SparrwHawk

Respuestas:

822

Detectando iOS

No soy fanático de la detección de agentes de usuario, pero así es como lo haría:

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

Otra forma es confiar en navigator.platform:

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

iOSserá cualquiera trueofalse

¿Por qué no MSStream?

Microsoft inyectó la palabra iPhone en IE11 userAgentpara intentar engañar a Gmail de alguna manera. Por lo tanto, debemos excluirlo. Más información sobre esto aquí y aquí .

A continuación se muestra la actualización de IE11 userAgent( actualización de Internet Explorer para Windows Phone 8.1):

Mozilla / 5.0 (móvil; Windows Phone 8.1; Android 4.0; ARM; Trident / 7.0; Touch; rv: 11.0; IEMobile / 11.0; NOKIA; Lumia 930) como iPhone OS 7_0_3 Mac OS X AppleWebKit / 537 (KHTML, como Gecko) Safari móvil / 537


Agregue fácilmente más dispositivos, sin usar Expresiones regulares:

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()será cualquiera trueofalse

Nota: Tanto navigator.userAgenty navigator.platformpuede ser falsificada por el usuario o una extensión del navegador.


Detectando la versión de iOS

La forma más común de detectar la versión de iOS es analizarla desde la cadena del Agente de usuario . Pero también hay inferencia de detección de características * ;

Sabemos a ciencia cierta que history APIse introdujo en iOS4 , matchMedia APIen iOS5 , webAudio APIen iOS6 , WebSpeech APIen iOS7, etc.

Nota: El siguiente código no es confiable y se romperá si alguna de estas características HTML5 está en desuso en una versión más reciente de iOS. ¡Usted ha sido advertido!

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';
}
Pierre
fuente
2
Gracias Pierre: este código parece más simple, solo me pregunto si puedo especificar 'iOS' en lugar de tener que escribir todos los iDevices separados ... if ((navigator.userAgent.match (/ iPhone / i)) | | (navigator.userAgent.match (/ iPod / i)) || (navigator.userAgent.match (/ iPad / i))) {// Hacer algo}
SparrwHawk
99
Lo que está haciendo en el segundo fragmento es la inferencia de características, no la detección de características. La detección de características está probando características que realmente va a utilizar, mientras que lo que está haciendo es probar características que sabe que se introdujeron en una versión particular del sistema operativo e inferir la versión del sistema operativo a partir de ellas. Esto es frágil porque las versiones futuras de iOS podrían eliminar estas características.
Tim Down
23
Esta es una mejor manera de escribir su cheque:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp
55
Solo una nota: la matriz navigator.platform no funciona en el Simulador de iPad porque tiene la frase completa "Simulador de iPad" en la cadena de la plataforma.
Kevin Newman
99
Desde iOS 13, el agente de usuario del iPad ha cambiado a "Mac OS", por ejemplo: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15por lo que esta respuesta debe actualizarse
zvi
38

Después de iOS 13, debe detectar dispositivos iOS como este, ya que el iPad no se detectará como dispositivos iOS de la forma anterior (debido a las nuevas opciones de "escritorio", habilitadas de forma predeterminada):

let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)

La primera condición para iOS <13 o iPhone o iPad con el modo de escritorio deshabilitado, la segunda condición para iPadOS 13 en la configuración predeterminada, ya que se posiciona como Macintosh Intel, pero en realidad es el único Macintosh con multitáctil.

Más bien un truco que una solución real, pero funciona de manera confiable para mí

PD Como se dijo anteriormente, probablemente debería agregar el chequeo de IE

let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!window.MSStream
kikiwora
fuente
¿Por qué no usar el navigator.userAgentpara esta verificación /iPad|iPhone|iPod/.test(navigator.platform)? Parece que navigator.platformsiempre devuelve 'MacIntel' para iPhone iOS <= 12
Charis Theo
@CharisTheo Porque el iPad no está en el UserAgent en iOS> = 13
Kzrbill
pero ya está buscando iPad iOS> = 13 en la segunda verificación o ¿me falta algo?
Charis Theo
navigator.maxTouchPointsno es compatible con iOS, por lo que esa comprobación no hará nada por usted.
PaulC
@PaulC, tienes razón en que maxTouchPoints no está definido para iOS 12 y versiones inferiores, pero kikiwora está en el camino correcto ya que maxTouchPoints es compatible con iOS 13. Mira mi respuesta.
Bob Arlof
14

Esto establece la variable _iOSDeviceen verdadero o falso

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
Vitim.us
fuente
3
Que hace !! ¿hacer?
patrick
44
@astronought doble negación se utiliza para lanzar a un booleano
Vitim.us
2
@astronought bang bang, eres booleano: D
Qback
1
Usando /iPhone|iPod|iPad/.test(navigator.platform)puede evitar el!!
lionello
10

Si está utilizando Modernizr , puede agregarle una prueba personalizada.

No importa qué modo de detección decida usar (userAgent, navigator.vendor o navigator.platform), siempre puede envolverlo para un uso posterior más fácil.

//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
fuente
2
Tenga cuidado, Modernizr pone en minúscula automáticamente el nombre de la prueba agregada. (en su ejemplo, Modernizr.isiOS nunca volverá verdadero). El mal comportamiento de la lib en mi opinión ...
CETIA
3
Sólo pequeño aviso: se puede simplificar return x ? true : falsea return Boolean(x)o simplementereturn !!x
Tibalt
6

Una versión simplificada y fácil de ampliar.

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
Kory Nunn
fuente
1
Si también quieres que esto funcione en el simulador de iOS puede utilizar: navigator.platform.replace(' Simulator', '').
Koraktor
Pero no funciona, porque['str'].indexOf('string') == -1
tibalt
navigator.platform será exactamente 'iPad', 'iPhone' o 'iPod' a menos que el simulador se esté ejecutando.
Kory Nunn
4

Probablemente valga la pena responder que los iPads con iOS 13 se habrán navigator.platformconfigurado MacIntel, lo que significa que necesitará encontrar otra forma de detectar dispositivos iPadOS.

Justin Searls
fuente
3

Escribí esto hace un par de años, pero creo que todavía funciona:

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

    }
Michael Benin
fuente
2

Los agentes de usuario en dispositivos iOS dicen iPhone o iPad en ellos. Acabo de filtrar en función de esas palabras clave.

Bryan Naegele
fuente
44
También hay iPod Touch para tener en cuenta.
Douglas Greenshields
@DouglasGreenshields Correcto. Olvidé eso, pero creo que también transmite su identidad en el agente de usuario.
Bryan Naegele
El agente de usuario de iPad safari ya no incluirá "iPad" de iPadOS 13.
Jonny
2

Siempre que sea posible al agregar pruebas de Modernizr, debe agregar una prueba para una función, en lugar de un dispositivo o sistema operativo. No hay nada de malo en agregar diez pruebas todas las pruebas para iPhone si eso es lo que se necesita. Algunas cosas simplemente no se pueden detectar características.

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

Por ejemplo, en el iPhone (no en el iPad) el video no se puede reproducir en línea en una página web, se abre a pantalla completa. Así que creé una prueba 'no-inpage-video'

Luego puede usar esto en css (Modernizr agrega una clase .no-inpagevideoa la <html>etiqueta si la prueba falla)

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

Esto ocultará el video en iPhone (lo que en realidad estoy haciendo en este caso es mostrar una imagen alternativa con un clic para reproducir el video; simplemente no quiero que se muestre el reproductor de video predeterminado y el botón de reproducción).

Simon_Weaver
fuente
iOS10 ahora lo permite para playsinlineque pueda usarlo 'playsInline' in document.createElement('video');como prueba ahora github.com/Modernizr/Modernizr/issues/2077
Simon_Weaver
2

Wow, hay un montón de código largo y complicado aquí. ¡Mantenlo simple, por favor!

Este es IMHO rápido, ahorra y funciona bien:

 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);
  • Es rápido, porque los controles de expresiones regulares de la ^ S posición de la cadena plataforma de primera tarting y se detiene si no hay una "IP" (más rápido que buscar la cadena larga UA hasta el final de todos modos)
  • Es más seguro que la comprobación de UA (suponiendo que sea menos probable que falsifique navigator.platform)
  • Detecta el simulador de iPhone / iPad


ACTUALIZACIÓN: Esto no cubre iPad en modo de escritorio (y, por lo tanto, iPadOS 13 predeterminado).
Eso está bien para mis casos de uso, si no es para ti, mira las respuestas de Justin y Kikiwora.

jj
fuente
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);en lugar de esto yo haría iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); como medida de respaldo primo en mi caso navigator.platform no funcionaba, pero hacerlo así más tarde trabajó bien
Coderboi
navigator.platformno funcionó? ¿Estás realmente en iOS entonces? Consulte con jeka.info/test/navigator.html . userAgentda falsos positivos porque algunos proveedores lo falsifican para imitar los dispositivos de Apple por cualquier motivo. vendorsólo devuelve o Google Inc., Apple Computer, Inc., o nada (en Firefox).
jj
1

Actualice ligeramente la primera respuesta con un enfoque más funcional.

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;
Sten Muchow
fuente
No funciona en el simulador móvil Brave / Chrome dev tools. ObtengoMacIntel
sdfsdf
1

También puedes usar includes

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

Ninguna de las respuestas anteriores aquí funciona para todos los principales navegadores en todas las versiones de iOS, incluido iOS 13. Aquí hay una solución que funciona para Safari, Chrome y Firefox para todas las versiones de 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()));
})();

Tenga en cuenta que este fragmento de código se escribió con prioridad en la legibilidad, no en la concisión o el rendimiento.

Explicación:

  • Si el agente de usuario contiene alguno de "iPod | iPhone | iPad", entonces claramente el dispositivo es iOS. De lo contrario, continúe ...

  • Cualquier otro agente de usuario que no contenga "Macintosh" no es un dispositivo Apple y, por lo tanto, no puede ser iOS. De lo contrario, es un dispositivo Apple, así que continúe ...

  • Si maxTouchPointstiene un valor 1igual o mayor, entonces el dispositivo Apple tiene una pantalla táctil y, por lo tanto, debe ser iOS ya que no hay Mac con pantallas táctiles (felicitaciones a kikiwora por mencionar maxTouchPoints). Tenga en cuenta que maxTouchPointses undefinedpara iOS 12 y versiones inferiores, por lo que necesitamos una solución diferente para ese escenario ...

  • iOS 12 y versiones posteriores tienen una peculiaridad que no existe en Mac OS. La peculiaridad es que la volumepropiedad de un Audioelemento no se puede establecer con éxito en ningún valor que no sea 1. Esto se debe a que Apple no permite cambios de volumen en el Audioelemento para dispositivos iOS, pero sí para Mac OS. Esa peculiaridad se puede usar como el método de respaldo final para distinguir un dispositivo iOS de un dispositivo Mac OS.

Bob Arlof
fuente
-1

En mi caso, el agente de usuario no era lo suficientemente bueno, ya que en el Ipad el agente de usuario era el mismo que en Mac OS, por lo tanto, tuve que hacer un truco desagradable:

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
}
Ian Farré
fuente
solo lea la pregunta que dice detectar iOS, no detectar dispositivos móviles
Cybersupernova
-2

Para detectar la versión de iOS, uno tiene que desestructurar el agente de usuario con un código Javascript como este:

 var res = navigator.userAgent.match(/; CPU.*OS (\d_\d)/);
    if(res) {
        var strVer = res[res.length-1];
        strVer = strVer.replace("_", ".");
        version = strVer * 1;
    }
viebel
fuente
-2

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

Mithun Sreedharan
fuente