Wykryj, czy urządzeniem jest iOS

408

Zastanawiam się, czy można wykryć, czy przeglądarka działa w systemie iOS, podobnie jak w przypadku funkcji wykrywania za pomocą Modernizr (chociaż jest to oczywiście wykrywanie urządzeń, a nie wykrywanie funkcji).

Zwykle wolałbym zamiast tego wykrywać funkcje, ale muszę dowiedzieć się, czy urządzenie ma system iOS ze względu na sposób, w jaki obsługują filmy zgodnie z tym pytaniem. Interfejs API YouTube nie działa z urządzeniem iPad / iPhone / innym niż Flash

SparrwHawk
źródło
Zobacz [Co to jest ciąg klienta użytkownika iOS 5?] [1] (duplikat?). [1]: stackoverflow.com/questions/7825873/…
dejuknow
1
Czy to wykrywanie po stronie klienta czy po stronie serwera?
Douglas Greenshields
Hej @DouglasGreenshields, to jest po stronie klienta
SparrwHawk
1
Również nie duplikat, pytam, jak to zrobić. Nigdy wcześniej nie używałem wąchania klienta użytkownika.
SparrwHawk

Odpowiedzi:

821

Wykrywanie iOS

Nie jestem fanem wąchania User User Agent, ale oto jak to zrobić:

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

Innym sposobem jest poleganie na navigator.platform:

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

iOSbędzie albo truealbofalse

Dlaczego nie MSStream

Microsoft wstrzyknął słowo iPhone do IE11 userAgent, aby jakoś oszukać Gmaila. Dlatego musimy to wykluczyć. Więcej informacji na ten temat tutaj i tutaj .

Poniżej znajduje się aktualizacja IE11 (aktualizacja userAgentInternet Explorer dla 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) jak iPhone OS 7_0_3 Mac OS X AppleWebKit / 537 (KHTML, jak Gecko) Mobile Safari / 537


Z łatwością dodawaj więcej urządzeń bez użycia wyrażeń regularnych:

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()będzie albo truealbofalse

Uwaga: Zarówno navigator.userAgenti navigator.platformmogą być sfałszowane przez użytkownika lub rozszerzeniem przeglądarki.


Wykrywanie wersji iOS

Najczęstszym sposobem wykrywania wersji iOS jest parsowanie jej z ciągu Agenta użytkownika . Ale istnieje również wnioskowanie o wykrywaniu funkcji * ;

Wiemy o tym, że history APIzostał wprowadzony w iOS4 - matchMedia APIw iOS5 - webAudio APIw iOS6 - WebSpeech APIw iOS7 itd.

Uwaga: poniższy kod nie jest niezawodny i ulegnie awarii, jeśli którakolwiek z tych funkcji HTML5 będzie przestarzała w nowszej wersji iOS. Zostałeś ostrzeżony!

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
źródło
2
Dzięki Pierre - ten kod wydaje się jednak prostszy, po prostu zastanawiam się, czy mogę po prostu określić „iOS” zamiast wpisywać wszystkie oddzielne iDevices .... if ((navigator.userAgent.match (/ iPhone / i)) | | (navigator.userAgent.match (/ iPod / i)) || (navigator.userAgent.match (/ iPad / i))) {// Zrób coś}
SparrwHawk
9
Drugim fragmentem zajmuje się wnioskowanie o funkcjach, a nie ich wykrywanie. Wykrywanie funkcji to testowanie funkcji, których faktycznie będziesz używać, podczas gdy to, co robisz, to testowanie funkcji, o których wiesz, że zostały wprowadzone w konkretnej wersji systemu operacyjnego i wnioskowanie na ich podstawie. Jest to kruche, ponieważ przyszłe wersje iOS mogłyby usunąć te funkcje.
Tim Down
23
Jest to lepszy sposób na napisanie czeku:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp
5
Tylko uwaga - tablica navigator.platform nie działa na iPadzie Simulator, ponieważ ma całą frazę „iPad Simulator” w łańcuchu platformy.
Kevin Newman,
9
Z iOS 13 agent użytkownika iPada zmienił się na „Mac OS”, na przykład: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15więc odpowiedź musi zostać zaktualizowana
zvi
38

Po iOS 13 powinieneś wykryć takie urządzenia iOS, ponieważ iPad nie będzie wykrywany jako urządzenie iOS na stare sposoby (ze względu na nowe opcje „pulpitu”, domyślnie włączone):

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

Pierwszy warunek dla iOS <13 lub iPhone'a lub iPada z wyłączonym trybem Pulpit, drugi warunek dla iPadOS 13 w domyślnej konfiguracji, ponieważ ustawia się jak Macintosh Intel, ale tak naprawdę jest to jedyny Macintosh z funkcją Multi-Touch.

Raczej hack niż prawdziwe rozwiązanie, ale działaj niezawodnie dla mnie

PS Jak powiedziano wcześniej, prawdopodobnie należy dodać kontrolę IE

let isIOS = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!window.MSStream
kikiwora
źródło
Dlaczego nie skorzystać z navigator.userAgenttej kontroli /iPad|iPhone|iPod/.test(navigator.platform)? Wygląda na to, że navigator.platformzawsze zwraca „MacIntel” na iPhone'a iOS <= 12
Charis Theo
@CharisTheo Ponieważ iPad nie jest w userAgent w iOS> = 13
Kzrbill
ale sprawdzasz już iPada iOS> = 13 w drugim teście, czy coś mi brakuje?
Charis Theo,
navigator.maxTouchPointsnie jest obsługiwany w iOS, więc czek nie zrobi nic dla ciebie.
PaulC
@PaulC, masz rację, że maxTouchPoints jest niezdefiniowany dla iOS 12 i niższych, ale kikiwora jest na dobrej drodze, ponieważ maxTouchPoints jest obsługiwany w iOS 13. Zobacz moją odpowiedź.
Bob Arlof
14

Ustawia zmienną _iOSDevicena true lub false

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);
Vitim.us
źródło
3
co robi !! zrobić?
Patrick
4
Podwójna negacja @astronought służy do rzucenia na wartość logiczną
Vitim.us
2
@astronought bang bang, boolean: D
Qback
1
Za pomocą /iPhone|iPod|iPad/.test(navigator.platform)można uniknąć!!
lionello
10

Jeśli korzystasz z Modernizr , możesz dodać niestandardowy test.

Nie ma znaczenia, z którego trybu wykrywania zdecydujesz się skorzystać (userAgent, navigator.vendor lub navigator.platform), zawsze możesz go zawinąć, aby ułatwić później.

//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
źródło
2
Bądź ostrożny, Modernizr automatycznie dodaje małe litery do nazwy dodanego testu. (w twoim przykładzie Modernizr.isiOS nigdy nie zwróci wartości true). Złe zachowanie lib w mojej opinii ...
Cétia,
3
Wystarczy mały uwaga: można uprościć return x ? true : falsedo return Boolean(x)lub po prostureturn !!x
tibalt
6

Uproszczona, łatwa do rozszerzenia wersja.

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
Kory Nunn
źródło
1
Jeśli chcesz to do pracy na symulatorze iOS można użyć: navigator.platform.replace(' Simulator', '').
Koraktor,
Ale to nie działa, ponieważ['str'].indexOf('string') == -1
Tibalt
navigator.platformą będzie dokładnie „iPad”, „iPhone” lub „iPod”, chyba że uruchomiony jest symulator.
Kory Nunn,
4

Prawdopodobnie warto odpowiedzieć, że iPady z systemem iOS 13 będą navigator.platformustawione na MacIntel, co oznacza, że ​​będziesz musiał znaleźć inny sposób wykrywania urządzeń iPadOS.

Justin Searls
źródło
3

Napisałem to kilka lat temu, ale wierzę, że nadal działa:

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
źródło
2

Programy klienckie na urządzeniach z iOS mówią w nich iPhone lub iPad. Po prostu filtruję według tych słów kluczowych.

Bryan Naegele
źródło
4
Do rozważenia są także iPod Touches.
Douglas Greenshields
@DouglasGreenshields poprawnie. Zapomniałem o tym, ale wierzę, że przekazuje on również swoją tożsamość w kliencie użytkownika.
Bryan Naegele
Agent użytkownika iPada Safari nie będzie już zawierał „iPad” z iPada 13.
Jonny
2

O ile to możliwe, dodając testy Modernizr, należy dodać test funkcji, a nie urządzenia lub systemu operacyjnego. Nie ma nic złego w dodawaniu dziesięciu testów do testowania iPhone'a, jeśli tego właśnie potrzeba. Niektórych rzeczy po prostu nie można wykryć.

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

Na przykład wideo na iPhonie (nie na iPadzie) nie może być odtwarzane bezpośrednio na stronie internetowej, otwiera się pełny ekran. Więc stworzyłem test „wideo bez strony”

Możesz następnie użyć tego w css (Modernizr dodaje klasę .no-inpagevideodo <html>tagu, jeśli test się nie powiedzie)

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

To ukryje wideo na iPhonie (tak naprawdę robię w tym przypadku pokazując alternatywny obraz z kliknięciem, aby odtworzyć wideo - po prostu nie chcę, aby wyświetlał się domyślny odtwarzacz wideo i przycisk odtwarzania).

Simon_Weaver
źródło
iOS10 pozwala teraz, playsinlinewięc możesz użyć 'playsInline' in document.createElement('video');jako testu teraz github.com/Modernizr/Modernizr/issues/2077
Simon_Weaver 30.09.16
2

Wow, dużo długiego, trudnego kodu tutaj. Proszę, zachowaj prostotę!

Ten jest szybki, zapisuj i działa dobrze IMHO:

 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);
  • Jest szybki, ponieważ kontrole regexp ^ s pozycję pierwszego napisu platformy tarting i zatrzymuje się, gdy nie ma „IP” (szybciej niż przeszukując długi ciąg UA do końca tak)
  • Jest bezpieczniejszy niż czek UA (przy założeniu, że platforma navigator.pl prawdopodobnie nie zostanie sfałszowana)
  • Wykrywa iPhone / iPad Simulator


AKTUALIZACJA: Nie dotyczy iPada w trybie pulpitu (a zatem domyślnego iPada 13).
To dobrze dla moich przypadków użycia, jeśli nie jest dla ciebie, zobacz odpowiedzi Justina i kikiwory.

jj
źródło
iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);zamiast tego zrobiłbym to iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); jako rozwiązanie awaryjne, ponieważ w moim przypadku navigator.pl
Platforma
navigator.platformnie działało? Czy naprawdę jesteś na iOS? Sprawdź na stronie jeka.info/test/navigator.html . userAgentdaje fałszywie pozytywne wyniki, ponieważ niektórzy sprzedawcy podrobili to, aby naśladować urządzenia Apple z jakichkolwiek powodów. vendorpo prostu zwraca albo Google Inc., Apple Computer, Inc.albo nic (Firefox).
jj
1

Nieznacznie zaktualizuj pierwszą odpowiedź, stosując bardziej funkcjonalne podejście.

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;
Sten Muchow
źródło
Nie działa w mobilnym symulatorze narzędzi programistycznych Brave / Chrome. DostajęMacIntel
sdfsdf
1

Żadna z poprzednich odpowiedzi tutaj nie działa dla wszystkich głównych przeglądarek we wszystkich wersjach iOS, w tym iOS 13. Oto rozwiązanie, które działa w Safari, Chrome i Firefox dla wszystkich wersji 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()));
})();

Pamiętaj, że ten fragment kodu został napisany z myślą o czytelności, a nie zwięzłości lub wydajności.

Wyjaśnienie:

  • Jeśli klient użytkownika zawiera którykolwiek z „iPod | iPhone | iPad”, to oczywiście urządzenie to iOS. W przeciwnym razie kontynuuj ...

  • Każdy inny klient użytkownika, który nie zawiera „Macintosh”, nie jest urządzeniem Apple i dlatego nie może być iOS. W przeciwnym razie jest to urządzenie Apple, więc kontynuuj ...

  • Jeśli maxTouchPointsma wartość równą 1lub większą, to urządzenie Apple ma ekran dotykowy i dlatego musi być systemem iOS, ponieważ nie ma komputerów Mac z ekranami dotykowymi (podziękowania dla kikiwory za wzmiankę maxTouchPoints). Pamiętaj, że dotyczy maxTouchPointsto undefinediOS 12 i niższych, dlatego potrzebujemy innego rozwiązania dla tego scenariusza ...

  • iOS 12 i poniżej mają dziwactwo, które nie istnieje w Mac OS. Dziwactwo polega na tym, że volumewłaściwości Audioelementu nie można pomyślnie ustawić na żadną inną wartość niż 1. Wynika to z faktu, że Apple nie zezwala na zmiany głośności w Audioelemencie dla urządzeń z systemem iOS, ale zezwala na system Mac OS. To dziwactwo może być wykorzystane jako ostateczna metoda zastępcza dla odróżnienia urządzenia iOS od urządzenia Mac OS.

Bob Arlof
źródło
0

Możesz także użyć includes

  const isApple = ['iPhone', 'iPad', 'iPod'].includes(navigator.platform)
Alan
źródło
-1

W moim przypadku agent użytkownika nie był wystarczająco dobry, ponieważ na iPadzie agent użytkownika był taki sam jak w Mac OS, dlatego musiałem zrobić paskudną sztuczkę:

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é
źródło
po prostu przeczytaj pytanie: wykryj iOS, a nie wykryj telefon komórkowy
Cybersupernova
-2

Aby wykryć wersję iOS, należy zniszczyć agenta użytkownika za pomocą kodu JavaScript takiego:

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

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

Mithun Sreedharan
źródło