Detectar se o dispositivo é iOS

408

Gostaria de saber se é possível detectar se um navegador está sendo executado no iOS, semelhante a como você pode detectar com o Modernizr (embora isso seja obviamente uma detecção de dispositivo e não uma detecção de recurso).

Normalmente, eu preferiria a detecção de recursos, mas preciso descobrir se um dispositivo é iOS devido à maneira como eles lidam com vídeos, de acordo com esta pergunta. A API do YouTube não funciona com iPad / iPhone / dispositivo não Flash

SparrwHawk
fonte
Consulte [Qual é a sequência de agente do usuário do iOS 5?] [1] (duplicada?). [1]: stackoverflow.com/questions/7825873/…
dejuknow 27/01
1
Essa detecção é do lado do cliente ou do servidor?
Douglas Greenshields
Hey @DouglasGreenshields, é do lado do cliente
SparrwHawk
1
Além disso, não é uma duplicata, estou perguntando como fazê-lo. Eu nunca usei cheirar agente de usuário antes.
precisa saber é o seguinte

Respostas:

821

Detectando iOS

Eu não sou fã de cheirar o User Agent, mas eis como você faria isso:

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

Outra maneira é confiar navigator.platform:

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

iOSserá trueoufalse

Por que não o MSStream

A Microsoft injetou a palavra iPhone no IE11 userAgentpara tentar enganar o Gmail de alguma forma. Portanto, precisamos excluí-lo. Mais informações sobre isso aqui e aqui .

Abaixo está a atualização do IE11 userAgent( Atualização do Internet Explorer para 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) como iPhone OS 7_0_3 Mac OS X AppleWebKit / 537 (KHTML, como Gecko) Mobile Safari / 537


Adicione facilmente mais dispositivos, sem usar expressões 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á trueoufalse

Nota: Ambos navigator.userAgente navigator.platformpodem ser falsificados pelo usuário ou por uma extensão do navegador.


Detectando a versão do iOS

A maneira mais comum de detectar a versão do iOS é analisando-a na cadeia de caracteres do User Agent . Mas também há inferência de detecção de recursos * ;

Sabemos que um fato history APIfoi introduzido no iOS4 - matchMedia APIno iOS5 - webAudio APIno iOS6 - WebSpeech APIno iOS7 e assim por diante.

Nota: O código a seguir não é confiável e será interrompido se algum desses recursos do HTML5 for descontinuado em uma versão mais recente do iOS. Você foi avisado!

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
fonte
2
Obrigado Pierre - esse código parece mais simples, porém, eu me pergunto se posso especificar 'iOS' em vez de precisar digitar todos os iDevices separados ... if (((navigator.userAgent.match (/ iPhone / i)) | | (navigator.userAgent.match (/ iPod / i)) || (navigator.userAgent.match (/ iPad / i))) {// Do something}
SparrwHawk
9
O que você está fazendo no segundo snippet é inferência de recurso, não detecção de recurso. A detecção de recursos está testando recursos que você realmente usará, enquanto o que você está fazendo é testar recursos que você conhece que foram introduzidos em uma versão específica do sistema operacional e inferir a versão do sistema operacional a partir deles. Isso é frágil porque versões futuras do iOS podem remover esses recursos.
Tim Baixo
23
Esta é a melhor maneira de escrever seu cheque:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp
5
Apenas uma observação - o array navigator.platform não funciona no iPad Simulator porque possui a frase inteira "iPad Simulator" na string da plataforma.
Kevin Newman
9
No iOS 13, o agente do usuário do iPad mudou para "Mac OS", por exemplo: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15portanto, essa resposta precisa ser atualizada
zvi
38

Após o iOS 13, você deve detectar dispositivos iOS como este, pois o iPad não será detectado como dispositivos iOS de maneiras antigas (devido às novas opções de "área de trabalho", ativadas por padrão):

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

A primeira condição para iOS <13 ou iPhone ou iPad com o modo Desktop desativado, a segunda condição para o iPadOS 13 na configuração padrão, uma vez que se posiciona como o Macintosh Intel, mas na verdade é o único Macintosh com multitoque.

Em vez de um hack do que uma solução real, mas trabalhe de maneira confiável para mim

PS Como foi dito anteriormente, você provavelmente deve adicionar um check-up do IE

let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!window.MSStream
kikiwora
fonte
Por que não usar o navigator.userAgentpara esta verificação /iPad|iPhone|iPod/.test(navigator.platform)? Parece que navigator.platformsempre retorna 'MacIntel' para iPhone iOS <= 12
Charis Theo
@CharisTheo Como o iPad não está no userAgent no iOS> = 13
Kzrbill
mas você já está verificando o iPad iOS> = 13 na segunda verificação ou estou perdendo alguma coisa?
Charis Theo
navigator.maxTouchPointsnão é suportado no iOS, portanto, essa verificação não fará nada por você.
PaulC
@PaulC, você está certo, pois maxTouchPoints não está definido para o iOS 12 e inferior, mas o kikiwora está no caminho certo, pois o maxTouchPoints é suportado no iOS 13. Veja minha resposta.
Bob Arlof
14

Isso define a variável _iOSDevicecomo true ou false

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
Vitim.us
fonte
3
o que !! Faz?
patrick
4
@astronought dupla negação é usado para lançar a um boolean
Vitim.us
2
@astronought bang bang, você é booleano: D
Qback 18/06/19
1
Usando /iPhone|iPod|iPad/.test(navigator.platform)você pode evitar o!!
lionello 1/19
10

Se você estiver usando o Modernizr , poderá adicionar um teste personalizado.

Não importa qual modo de detecção você decida usar (userAgent, navigator.vendor ou navigator.platform), você sempre pode agrupá-lo para facilitar o uso posteriormente.

//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
fonte
2
Cuidado, o Modernizr coloca em minúsculas o nome do teste adicionado automaticamente. (no seu exemplo, Modernizr.isiOS nunca retornará verdadeiro). O mau comportamento da lib na minha opinião ...
Cétia
3
Apenas pequena observação: você pode simplificar return x ? true : falsea return Boolean(x)ou apenasreturn !!x
tibalt
6

Uma versão simplificada e fácil de estender.

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
Kory Nunn
fonte
1
Se você também quiser que isso funcione no iOS Simulator você pode usar: navigator.platform.replace(' Simulator', '').
Koraktor
Mas isso não funciona, porque['str'].indexOf('string') == -1
tibalt
navigator.platform será exatamente 'iPad', 'iPhone' ou 'iPod', a menos que o simulador esteja em execução.
Kry Nunn #
4

Provavelmente vale a pena responder que os iPads com iOS 13 terão navigator.platformdefinido MacIntel, o que significa que você precisará encontrar outra maneira de detectar dispositivos iPadOS.

Justin Searls
fonte
3

Eu escrevi isso há alguns anos, mas acredito que ainda 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
fonte
2

Os agentes do usuário nos dispositivos iOS dizem iPhone ou iPad. Eu apenas filtrei com base nessas palavras-chave.

Bryan Naegele
fonte
4
Há também iPod Touch a considerar.
Douglas Greenshields
@DouglasGreenshields Correct. Esqueci sobre isso, mas acredito que ele transmite sua identidade no agente do usuário também.
Bryan Naegele
Agente de usuário do iPad safari não incluirá "iPad" da iPadOS 13.
Jonny
2

Sempre que possível, ao adicionar testes Modernizr, você deve adicionar um teste para um recurso, em vez de um dispositivo ou sistema operacional. Não há nada errado em adicionar dez testes todos os testes para o iPhone, se é isso que é preciso. Algumas coisas simplesmente não podem ser detectadas.

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

Por exemplo, no vídeo do iPhone (não no iPad) não pode ser reproduzido em linha em uma página da Web, ele abre a tela inteira. Então eu criei um teste 'no-inpage-video'

Você pode usar isso em css (o Modernizr adiciona uma classe .no-inpagevideoà <html>tag se o teste falhar)

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

Isso ocultará o vídeo no iPhone (o que realmente estou fazendo neste caso é mostrar uma imagem alternativa com um clique para reproduzir o vídeo - só não quero que o player de vídeo padrão e o botão play sejam exibidos).

Simon_Weaver
fonte
O iOS10 agora permite playsinlineque você possa usar 'playsInline' in document.createElement('video');como teste agora github.com/Modernizr/Modernizr/issues/2077
Simon_Weaver
2

Uau, muitos códigos complicados e longos aqui. Mantenha simples, por favor!

Este é IMHO rápido, economize e funcione bem:

 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);
  • É rápido, porque as verificações de expressões regulares a ^ s posição da linha plataforma primeiro tarting e pára se não houver "IP" (mais rápido do que procurar a string UA longa até o final de qualquer maneira)
  • É mais seguro do que a verificação de UA (supondo que navigator.platform seja menos provável)
  • Detecta o simulador de iPhone / iPad


ATUALIZAÇÃO: Isso não cobre o iPad no modo de área de trabalho (e, portanto, o iPadOS 13 padrão).
Isso é bom para os meus casos, se não é para você, veja as respostas de Justin e kikiwora.

jj
fonte
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);ao invés disso eu faria iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); como uma medida fallback porque no meu caso navigator.platform não funcionou, mas fazê-lo como mais tarde funcionou bem
Coderboi
navigator.platformnão funcionou? Você está realmente no iOS, então? Verifique com jeka.info/test/navigator.html . userAgentfornece falsos positivos, porque alguns fornecedores fingem imitar dispositivos Apple por qualquer motivo. vendorapenas retorna quer Google Inc., Apple Computer, Inc.ou nada (no Firefox).
jj
1

Atualize levemente a primeira resposta usando uma abordagem mais funcional.

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;
Sten Muchow
fonte
Não funciona no simulador móvel Brave / Chrome dev tools. Eu receboMacIntel
sdfsdf
1

Você também pode usar includes

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

Nenhuma das respostas anteriores aqui funciona para todos os principais navegadores em todas as versões do iOS, incluindo o iOS 13. Aqui está uma solução que funciona para Safari, Chrome e Firefox para todas as versões do 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()));
})();

Observe que esse trecho de código foi escrito com prioridade na legibilidade, não na concisão ou no desempenho.

Explicação:

  • Se o agente do usuário contiver algum "iPod | iPhone | iPad", então claramente o dispositivo é iOS. Caso contrário, continue ...

  • Qualquer outro agente de usuário que não contenha "Macintosh" não é um dispositivo Apple e, portanto, não pode ser iOS. Caso contrário, é um dispositivo Apple, então continue ...

  • Se maxTouchPointstiver um valor igual 1ou superior, o dispositivo Apple possui uma tela sensível ao toque e, portanto, deve ser iOS, pois não há Macs com telas sensíveis ao toque (parabéns ao kikiwora por mencionar maxTouchPoints). Observe que maxTouchPointsé undefinedpara iOS 12 e abaixo, por isso precisamos de uma solução diferente para esse cenário ...

  • O iOS 12 e abaixo apresentam uma peculiaridade que não existe no Mac OS. A peculiaridade é que a volumepropriedade de um Audioelemento não pode ser definida com êxito para qualquer outro valor que não seja 1. Isso ocorre porque a Apple não permite alterações de volume no Audioelemento para dispositivos iOS, mas para Mac OS. Essa peculiaridade pode ser usada como o método final de fallback para distinguir um dispositivo iOS de um dispositivo Mac OS.

Bob Arlof
fonte
-1

No meu caso, o agente do usuário não era bom o suficiente, pois no Ipad o agente do usuário era o mesmo do Mac OS; portanto, tive que fazer um truque desagradável:

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é
fonte
basta ler a pergunta que diz detectar iOS, não detectar móvel
Cybersupernova
-2

Para detectar a versão do iOS, é necessário desestruturar o agente do usuário com um 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
fonte
-2

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

Mithun Sreedharan
fonte