Phát hiện nếu thiết bị là iOS


408

Tôi tự hỏi liệu có thể phát hiện xem trình duyệt có chạy trên iOS hay không, tương tự như cách bạn có thể phát hiện tính năng với Modernizr (mặc dù đây rõ ràng là phát hiện thiết bị thay vì phát hiện tính năng).

Thông thường tôi sẽ ưu tiên phát hiện tính năng thay vào đó, nhưng tôi cần tìm hiểu xem một thiết bị có phải là iOS hay không vì cách họ xử lý video theo câu hỏi này API YouTube không hoạt động với thiết bị iPad / iPhone / không phải Flash


Xem [Chuỗi tác nhân người dùng iOS 5 là gì?] [1] (trùng lặp?). [1]: stackoverflow.com/questions/7825873/ từ
dejuknow

1
Đây là phát hiện phía máy khách hoặc phía máy chủ?
Douglas Greenshields

Xin chào @DoumundG Greenshields, đó là phía khách hàng
SparrwHawk

1
Ngoài ra, không phải là một bản sao, tôi đang hỏi làm thế nào để làm điều đó. Tôi chưa bao giờ sử dụng tác nhân đánh hơi trước đây.
SparrwHawk

Câu trả lời:


821

Phát hiện iOS

Tôi không phải là người hâm mộ của Tác nhân người dùng đánh hơi, nhưng đây là cách bạn sẽ làm điều đó:

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

Một cách khác là dựa vào navigator.platform:

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

iOSsẽ là một trong hai truehoặcfalse

Tại sao không phải là MSStream

Microsoft đã chèn từ iPhone vào IE11 userAgentđể thử và đánh lừa Gmail bằng cách nào đó. Vì vậy, chúng ta cần loại trừ nó. Thông tin thêm về điều này ở đâyở đây .

Dưới đây là bản cập nhật của IE11 userAgent(Bản cập nhật Internet Explorer cho Windows Phone 8.1):

Mozilla / 5.0 (Di động; Windows Phone 8.1; Android 4.0; ARM; Trident / 7.0; Touch; rv: 11.0; IEMobile / 11.0; Nokia; Lumia 930) như iPhone OS 7_0_3 Mac OS X AppleWebKit / 537 (KHTML, như Gecko) Safari di động / 537


Dễ dàng thêm nhiều thiết bị hơn mà không cần sử dụng Biểu thức thông thường:

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()sẽ là một trong hai truehoặcfalse

Lưu ý: Cả hai navigator.userAgentnavigator.platformcó thể được làm giả bởi người dùng hoặc tiện ích mở rộng trình duyệt.


Phát hiện phiên bản iOS

Cách phổ biến nhất để phát hiện phiên bản iOS là phân tích cú pháp từ chuỗi Tác nhân người dùng . Nhưng cũng có suy luận phát hiện tính năng * ;

Chúng tôi biết một thực tế history APIđã được giới thiệu trong iOS4 - matchMedia APItrong iOS5 - webAudio APItrong iOS6 - WebSpeech APItrong iOS7 và v.v.

Lưu ý: Đoạn mã sau không đáng tin cậy và sẽ bị hỏng nếu bất kỳ tính năng HTML5 nào bị phản đối trong phiên bản iOS mới hơn. Bạn đã được cảnh báo!

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

2
Cảm ơn Pierre - mã này có vẻ đơn giản hơn, tôi chỉ tự hỏi liệu tôi có thể chỉ định 'iOS' thay vì phải gõ tất cả các iDevices riêng biệt .... if ((navigator.userAgent.match (/ iPhone / i)) | | (navigator.userAgent.match (/ iPod / i)) || (navigator.userAgent.match (/ iPad / i))) {// Làm gì đó}
SparrwHawk

9
Những gì bạn đang làm trong đoạn mã thứ hai là suy luận tính năng, không phải phát hiện tính năng. Phát hiện tính năng là kiểm tra các tính năng mà bạn thực sự sẽ sử dụng, trong khi những gì bạn đang làm là kiểm tra các tính năng mà bạn tình cờ biết được giới thiệu trong một phiên bản cụ thể của HĐH và suy ra phiên bản HĐH từ chúng. Điều này rất mong manh vì các phiên bản iOS trong tương lai có thể loại bỏ các tính năng này.
Tim Down

23
Đây là một cách tốt hơn để viết séc của bạn:var iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
LandonSchropp

5
Chỉ cần một lưu ý - mảng navigator.pl platform không hoạt động trên Trình mô phỏng iPad vì nó có toàn bộ cụm từ "Trình mô phỏng iPad" trong chuỗi nền tảng.
Kevin Newman

9
Từ iOS 13, tác nhân người dùng của iPad đã thay đổi thành "Mac OS", ví dụ: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15vì vậy câu trả lời này cần được cập nhật
zvi

38

Sau iOS 13, bạn nên phát hiện các thiết bị iOS như thế này, vì iPad sẽ không được phát hiện là thiết bị iOS theo cách cũ (do tùy chọn "máy tính để bàn" mới, được bật theo mặc định):

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

Điều kiện đầu tiên cho iOS <13 hoặc iPhone hoặc iPad với chế độ Máy tính để bàn bị vô hiệu hóa, điều kiện thứ hai cho iPadOS 13 trong cấu hình mặc định, vì nó có vị trí giống như Macintosh Intel, nhưng thực tế là Macintosh duy nhất có cảm ứng đa điểm.

Thay vì hack hơn là một giải pháp thực sự, nhưng công việc đáng tin cậy đối với tôi

PS Như đã nói trước đó, có lẽ bạn nên thêm kiểm tra IE

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

Tại sao không sử dụng navigator.userAgentcho kiểm tra này /iPad|iPhone|iPod/.test(navigator.platform)? Có vẻ như navigator.platformluôn trả về 'MacIntel' cho iPhone iOS <= 12
Charis Theo

@CharisTheo Vì iPad không có trong userAgent trong iOS> = 13
Kzrbill

nhưng bạn đã kiểm tra iPad iOS> = 13 trong lần kiểm tra thứ hai hay tôi thiếu thứ gì?
Charis Theo

navigator.maxTouchPointskhông được hỗ trợ trong iOS, do đó, kiểm tra sẽ không làm gì cho bạn.
PaulC

@PaulC, Bạn đúng ở chỗ maxTouchPoints không được xác định cho iOS 12 trở xuống, nhưng kikiwora đang đi đúng hướng vì maxTouchPoints được hỗ trợ trong iOS 13. Xem câu trả lời của tôi.
Bob Arlof

14

Điều này đặt biến _iOSDevicethành đúng hoặc sai

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

3
làm gì !! làm gì
patrick

4
Phủ định kép @astron think được sử dụng để chuyển sang boolean
Vitim.us

2
@astron think bang bang, bạn là người boolean: D
Qback

1
Sử dụng /iPhone|iPod|iPad/.test(navigator.platform)bạn có thể tránh!!
Lionello

10

Nếu bạn đang sử dụng Modernizr , bạn có thể thêm một bài kiểm tra tùy chỉnh cho nó.

Việc bạn quyết định sử dụng chế độ phát hiện nào (userAgent, navigator.vendor hoặc navigator.pl platform) không quan trọng, bạn luôn có thể gói nó để sử dụng dễ dàng hơn sau này.

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

2
Hãy cẩn thận, Modernizr tự động viết thường tên của bài kiểm tra đã thêm. (trong ví dụ của bạn, Modernizr.isiOS sẽ không bao giờ trở lại đúng). Hành vi xấu của lib theo quan điểm của tôi ...
Cétia

3
Thông báo chỉ nhỏ: bạn có thể đơn giản hóa return x ? true : falseđến return Boolean(x)hoặc chỉreturn !!x
tibalt


6

Một phiên bản đơn giản, dễ mở rộng.

var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;

1
Nếu bạn cũng muốn điều này hoạt động trên iOS Simulator, bạn có thể sử dụng : navigator.platform.replace(' Simulator', '').
Koraktor 7/2/2015

Nhưng nó không hoạt động, vì['str'].indexOf('string') == -1
tibalt

navigator.pl platform sẽ chính xác là 'iPad', 'iPhone' hoặc 'iPod' trừ khi trình giả lập đang chạy.
Kory Nunn

4

Có lẽ đáng để trả lời rằng iPad chạy iOS 13 sẽ được navigator.platformđặt thành MacIntel, điều đó có nghĩa là bạn sẽ cần tìm một cách khác để phát hiện các thiết bị iPadOS.


3

Tôi đã viết điều này một vài năm trước đây nhưng tôi tin rằng nó vẫn hoạt động:

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

    }

2

Các tác nhân người dùng trên thiết bị iOS cho biết iPhone hoặc iPad trong đó. Tôi chỉ lọc dựa trên những từ khóa đó.


4
Ngoài ra còn có iPod Touch để xem xét.
Douglas Greenshields

@DoumundG Greenshields Đúng. Quên về điều đó nhưng tôi tin rằng nó cũng truyền danh tính của nó trong tác nhân người dùng.
Bryan Naegele

Tác nhân người dùng của iPad safari sẽ không còn bao gồm "iPad" từ iPadOS 13.
Jonny

2

Bất cứ nơi nào có thể khi thêm các bài kiểm tra Modernizr, bạn nên thêm một bài kiểm tra cho một tính năng, thay vì một thiết bị hoặc hệ điều hành. Không có gì sai khi thêm mười thử nghiệm tất cả các thử nghiệm cho iPhone nếu đó là những gì nó cần. Một số thứ không thể được phát hiện.

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

Chẳng hạn, video trên iPhone (không phải iPad) không thể phát trực tuyến trên trang web, nó sẽ mở ra toàn màn hình. Vì vậy, tôi đã tạo một thử nghiệm 'không có trong video'

Sau đó, bạn có thể sử dụng điều này trong css (Modernizr thêm một lớp .no-inpagevideovào <html>thẻ nếu thử nghiệm thất bại)

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

Điều này sẽ ẩn video trên iPhone (những gì tôi thực sự đang làm trong trường hợp này đang hiển thị một hình ảnh thay thế với một onclick để phát video - Tôi chỉ không muốn trình phát video mặc định và nút phát để hiển thị).


iOS10 hiện cho phép playsinlineđể bạn có thể sử dụng 'playsInline' in document.createElement('video');thử nghiệm ngay bây giờ github.com/Modernizr/Modernizr/issues/2077
Simon_Weaver

2

Wow, rất nhiều mã khó khăn dài ở đây. Giữ cho nó đơn giản, xin vui lòng!

Đây là IMHO nhanh, tiết kiệm và hoạt động tốt:

 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);
  • Đó là nhanh vì kiểm tra regexp các ^ s tarting vị trí của chuỗi nền tảng đầu tiên và dừng lại nếu không có "iP" (nhanh hơn so với tìm kiếm trên chuỗi UA dài cho đến cuối cùng anyway)
  • Nó an toàn hơn kiểm tra UA (giả sử navigator.pl platform ít bị làm giả hơn)
  • Phát hiện Trình mô phỏng iPhone / iPad


CẬP NHẬT: Điều này không bao gồm iPad ở chế độ máy tính để bàn (và do đó mặc định iPadOS 13).
Điều đó tốt cho các giai đoạn của tôi, nếu nó không dành cho bạn, hãy xem câu trả lời của Justin và kikiwora.


iOS = /^(iPhone|iPad|iPod)/.test(navigator.platform);thay vì điều này tôi sẽ làm iOS = /^(iPhone|iPad|iPod)/.test(navigator.userAgent || navigator.vendor || navigator.platform); như một biện pháp dự phòng vì trường hợp của tôi là navigator.pl
platform

navigator.platformkhông làm việc Bạn có thực sự trên iOS không? Kiểm tra với jeka.info/test/navigator.html . userAgentcho kết quả dương tính giả vì một số nhà cung cấp giả mạo nó để bắt chước các thiết bị của Apple vì bất kỳ lý do gì. vendorchỉ trở lại một trong hai Google Inc., Apple Computer, Inc.hoặc không có gì (trong Firefox).
jj

1

Hơi cập nhật câu trả lời đầu tiên bằng cách sử dụng một cách tiếp cận chức năng hơn.

    const isIOS = [
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod',
    ].indexOf(navigator.platform) !== -1;

Không hoạt động trong trình giả lập công cụ di động Brave / Chrome. Tôi nhận đượcMacIntel
sdfsdf

1

Không có câu trả lời nào trước đây ở đây hoạt động cho tất cả các trình duyệt chính trên tất cả các phiên bản iOS, kể cả iOS 13. Đây là một giải pháp hoạt động cho Safari, Chrome và Firefox cho tất cả các phiên bản 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()));
})();

Lưu ý rằng đoạn mã này được viết với mức độ ưu tiên về khả năng đọc, không phải tính đồng nhất hoặc hiệu suất.

Giải trình:

  • Nếu tác nhân người dùng chứa bất kỳ "iPod | iPhone | iPad" thì rõ ràng thiết bị là iOS. Nếu không, tiếp tục ...

  • Bất kỳ tác nhân người dùng nào khác không chứa "Macintosh" không phải là thiết bị của Apple và do đó không thể là iOS. Mặt khác, nó là một thiết bị của Apple, vì vậy hãy tiếp tục ...

  • Nếu maxTouchPointscó giá trị bằng 1hoặc lớn hơn thì thiết bị Apple có màn hình cảm ứng và do đó phải là iOS vì không có máy Mac nào có màn hình cảm ứng (kudos to kikiwora để đề cập maxTouchPoints). Lưu ý rằng maxTouchPointsundefineddành cho iOS 12 và dưới, vì vậy chúng tôi cần một giải pháp khác nhau cho kịch bản ...

  • iOS 12 trở xuống có một cách giải quyết không tồn tại trong Mac OS. Điều khó hiểu là thuộc volumetính của một Audiophần tử không thể được đặt thành công thành bất kỳ giá trị nào khác ngoài 1. Điều này là do Apple không cho phép thay đổi âm lượng trên thành Audiophần cho thiết bị iOS, nhưng đối với Mac OS. Điều đó có thể được sử dụng làm phương pháp dự phòng cuối cùng để phân biệt thiết bị iOS với thiết bị Mac OS.


0

Bạn cũng có thể dùng includes

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

-1

Trong trường hợp của tôi, tác nhân người dùng không đủ tốt vì trong Ipad, tác nhân người dùng giống như trong Mac OS, do đó tôi phải thực hiện một mẹo khó chịu:

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
}

chỉ cần đọc câu hỏi mà nó phát hiện iOS, không phát hiện ra thiết bị di động
Cybersupernova

-2

Để phát hiện phiên bản iOS, người ta phải hủy cấu trúc tác nhân người dùng bằng mã Javascript như sau:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.