javascript - Upptäck om enheten är iOS


Jag undrar om det är möjligt att upptäcka om en webbläsare körs på iOS, på samma sätt som man kan upptäcka funktioner med Modernizr (även om detta uppenbarligen är enhetsskanning snarare än funktionsskanning).

Normalt skulle jag föredra funktionsdetektion istället, men jag behöver ta reda på om en enhet är iOS på grund av hur de hanterar videor enligt denna fråga YouTube API fungerar inte med iPad/iPhone/enheter utan Flash

Svar #1

Detektering av iOS

Med iOS 13 ändras både User agent- och plattformssträngarna på iPad och att skilja mellan iPad och MacOS verkar möjligt, så alla svar nedan måste nu ta hänsyn till det.

Detta kan vara det kortaste alternativet som också täcker iOS 13:

function iOS() {
  return [
    'iPad Simulator',
    'iPhone Simulator',
    'iPod Simulator',
    'iPad',
    'iPhone',
    'iPod'
  ].includes(navigator.platform)
  // iPad on iOS 13 detection
  || (navigator.userAgent.includes("Mac") && "ontouchend" in document)
}

iOS kommer att vara antingen true eller false

Sämre alternativ: Användaragentavkänning

User Agent-sniffning är farligare och problem uppstår ofta.

På iPad i iOS 13 är användaragenten identisk med den på en MacOS 13-dator, men om du ignorerar iPads kan detta fortfarande fungera ett tag:

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

!window.MSStream är för att inte felaktigt känna igen IE11, se här och här.

Observera: Både navigator.userAgent och navigator.platform kan manipuleras av användaren eller en webbläsartillägg.

Webbläsartillägg för att ändra userAgent eller plattform finns eftersom webbplatser använder alltför kraftfulla detektionsmetoder och ofta inaktiverar vissa funktioner även om användarens webbläsare annars skulle kunna använda den funktionen.

För att dämpa denna konflikt med användare rekommenderas det att specifikt för varje fall identifiera de exakta funktioner som din webbplats behöver. Då när användaren får en webbläsare med den nödvändiga funktionen kommer det redan att fungera utan ytterligare kodändringar.

Upptäcker iOS-version

Det vanligaste sättet att upptäcka iOS-versionen är genom att analysera den från User Agent-strängen. Men det finns också funktionsdetektering slutsats*;

Vi vet med säkerhet att history API introducerades i iOS4 - matchMedia API i iOS5 - webAudio API i iOS6 - WebSpeech API i iOS7 och så vidare.

Obs: Följande kod är inte tillförlitlig och kommer att sluta fungera om någon av dessa HTML5-funktioner tas bort i en nyare iOS-version. Du har blivit varnad!

function iOSversion() {

  if (iOS) { // <-- Use the one here above
    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';
}

Svar #2

Efter iOS 13 bör du upptäcka iOS-enheter på det här sättet, eftersom iPad inte kommer att upptäckas som iOS-enheter på det gamla sättet (på grund av nya "desktop"-alternativ, aktiverade som standard):

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

Det första villkoret för iOS < 13 eller iPhone eller iPad med inaktiverat skrivbordsläge, det andra villkoret för iPadOS 13 i standardkonfigurationen, eftersom den positionerar sig som Macintosh Intel, men egentligen är den den enda Macintosh med multi-touch.

Snarare en nödlösning än en riktig lösning, men fungerar pålitligt för mig

P.S. Som nämnts tidigare, borde du förmodligen lägga till en IE-kontroll

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

Svar #3

Ingen av de tidigare svaren här fungerar för alla större webbläsare på alla versioner av iOS, inklusive iOS 13. Här är en lösning som fungerar för Safari, Chrome och Firefox för alla iOS-versioner:

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()));
})();

Observera att denna kodsnutt skrevs med fokus på läsbarhet, inte korthet eller prestanda.

Förklaring:

  • Om användaragenter innehåller någon av "iPod|iPhone|iPad" är enheten tydligt iOS. Annars, fortsätt...

  • Alla andra användaragenter som inte innehåller "Macintosh" är inte en Apple-enhet och kan därför inte vara iOS. Annars är det en Apple-enhet, så fortsätt...

  • Om maxTouchPoints har ett värde på 1 eller högre så har Apple-enheten en pekskärm och måste därför vara iOS eftersom det inte finns några Mac-datorer med pekskärmar (beröm till kikiwora för att nämna maxTouchPoints). Observera att maxTouchPoints är undefined för iOS 12 och tidigare, så vi behöver en annan lösning för det scenariot...

  • iOS 12 och tidigare har en egenhet som inte finns i Mac OS. Egenheten är att volume-egenskapen hos ett Audio-element inte kan ställas in på något värde annat än 1. Detta beror på att Apple inte tillåter volymändringar på Audio-elementet för iOS-enheter, men gör det för Mac OS. Den egenheten kan användas som den sista reservmetoden för att skilja en iOS-enhet från en Mac OS-enhet.

Svar #4

Detta sätter variabeln _iOSDevice till true eller false

_iOSDevice = !!navigator.platform.match(/iPhone|iPod|iPad/);

Svar #5

ORIGINELLT SVAR 2018 (kan vara inaktuellt, beroende på användningsfall)
Wow, mycket lång och knepig kod här. Håll det enkelt, tack! Den här är enligt min åsikt snabb, säker och fungerar bra:

 iOS = /^iP/.test(navigator.platform);

  // or, if you prefer it verbose:
 iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);

UPPDATERING 2019-09: Mitt ursprungliga svar täcker inte iPad i skrivbordsläge (standard ändras till skrivbordsläge i kommande iPadOS 13 och högre).
Det är bra för mina användningsfall, om det inte är för dig, använd denna uppdatering:

// iPhone and iPad including iPadOS 13+ regardless of desktop mode settings

iOSiPadOS = /^iP/.test(navigator.platform) ||
           /^Mac/.test(navigator.platform) && navigator.maxTouchPoints > 4;

UPPDATERING 2024 alternativ

// in 2024 we don't care about IE 11 throwing an error and can do this:

iOSiPadOS = navigator.platform.startsWith("iP") ||
    navigator.platform.startsWith("Mac") && navigator.maxTouchPoints > 4;
  • Båda bör vara säkra så länge som

    • stationära Mac-datorer stödjer inte alls touchhändelser
    • eller högst 4 beröringspunkter (nuvarande iOS-enheter stödjer 5 beröringspunkter)
  • Det är snabbt eftersom regexp ^ först kontrollerar startpositionen för plattformssträngen och stoppar om det inte finns någon "iP" (snabbare än att söka igenom den långa UA-strängen tills slutet i alla fall)
  • Det är säkrare än navigator.userAgent-kontroll eftersom navigator.platform är mycket mindre sannolikt att förfalskas
  • Upptäcker iPhone/iPad-simulator

Svar #6

Om du använder Modernizr kan du lägga till ett eget test för det.

Det spelar ingen roll vilken detekteringsmetod du väljer att använda (userAgent, navigator.vendor eller navigator.platform), du kan alltid paketera den för enklare användning senare.

//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');
}

Relaterade artiklar