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
maxTouchPointshar ett värde på1eller 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ämnamaxTouchPoints). Observera attmaxTouchPointsärundefinedfö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 ettAudio-element inte kan ställas in på något värde annat än1. 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)
^ 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)navigator.userAgent-kontroll eftersom navigator.platform är mycket mindre sannolikt att förfalskasSvar #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');
}
