Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect iPad Mini in HTML5

Apple's iPad Mini is a smaller clone of the iPad 2 in more ways than we'd want. In JavaScript, the window.navigator object exposes the same values for the Mini and iPad 2. My tests so far to detect the difference have not lead to success.

Why is this important?

As the iPad Mini and iPad 2 screens are identical in pixels but vary in actual size (inches / centimeters), they vary in PPI (pixels per inch).

For web applications and games to offer a friendly user interface, certain elements are adjusted in size relative to a user's thumb or finger position, thus, we may want to scale certain images or buttons to provide for that better user experience.

Things I have tried so far (including some pretty obvious approaches):

  • window.devicepixelratio
  • CSS element width in cm unit
  • CSS media queries (such as resolution and -webkit-device-pixel-ratio)
  • SVG drawings in similar units
  • Doing all sorts of CSS webkit transforms for a set time and counting rendered frames with requestAnimFrame (I was hoping to detect a measurable difference)

I'm fresh out of ideas. How about you?

Update Thanks for the responses so far. I would like to comment on people voting against detecting iPad mini versus 2 as Apple has uhm, one guideline to rule them all. Okay, here's my reasoning why I feel it really makes all sense in the world to know if a person is using an iPad mini or a 2. And do with my reasoning what you like.

The iPad mini is not only a much smaller device (9.7 inch versus 7.9 inch), but its form factor allows for a different usage. The iPad 2 is usually held with two hands when gaming unless you're Chuck Norris. The mini is smaller, but it is also much lighter and allows for gameplay where you hold it in one hand and use another to swipe or tap or whatnot. As a game designer and developer myself, I'd just like to know if it's a mini so I can choose to provide the player with a different controlscheme if I want (for instance after A/B testing with a group of players).

Why? Well, it's a proven fact that the majority of users tend to go with the default settings, so leaving out a virtual thumbstick and putting some other tap-based control on the screen (just giving an arbitrary example here) when the player loads up the game for the first time is what I, and probably other game designers, would love to be able to do.

So IMHO this goes beyond the thick fingers / guidelines discussions and is just something Apple and all other vendors ought to do: allow us to uniquely identify your device and think different instead of following guidelines.

like image 310
Martin Kool Avatar asked Nov 06 '12 09:11

Martin Kool


23 Answers

Play a stereo audio file and compare the accelerometer response when volume is high on the right channel and on the left channel - iPad2 had mono speakers whereas iPad Mini has built-in stereo speakers.

Need your help to gather the data please visit this page and help me collect data for this crazy idea. I don't have an iPad mini so I really need your help

like image 153
Avi Marcus Avatar answered Oct 02 '22 14:10

Avi Marcus


Update: It looks like these values are reporting the viewport width and height at the time of tab creation, and they don't change upon rotation, so this method can't be used for device detection!

You can use the either screen.availWidth or screen.availHeight as they seem to be different for iPad Mini and iPad 2.

iPad Mini

screen.availWidth = 768
screen.availHeight = 1004

iPad 2

screen.availWidth = 748
screen.availHeight = 1024

Source: http://konstruktors.com/blog/web-design/4396-detect-ipad-mini-javascript/

like image 21
Kaspars Avatar answered Oct 02 '22 12:10

Kaspars


I understand this might be a bit low-tech solution, but since we can't seem to come up with anything else yet..

I am assuming you already check for most of the other devices, so I see the following scenarios possible.

You could check for ALL the possible most popular devices that require special CSS/sizing, and if it matches none of those either assume it's an iPad mini or simply ask the user?

// Device checks here
...
else {
  // it would probably be better to make this a nicer popup-thing
  var mini = prompt("Are you using a iPad mini? Press yes for a better user experience");
  // Store the result for future visits somehow.
}

I know that might seem like a stupid approach right now, but if we currently have no way of deciding if the device is a iPad mini or an iPad 2 at least the website will be usable with iPad mini devices doing something like this.

You could even go with something like this:

"To give you the best possible browsing experience we try to detect your device-type to customise the website to your device. Unfortunately due to limitations this is not always possible and we can't currently determine if you use an iPad 2 or an iPad mini by using these methods.

For the best possible browsing experience, please select what device you are using below.

This choice will be stored for future visits to the website on this device.

[] iPad 2 
[*] iPad mini
[] Ancient blackberry device

"

I am not entirely familiar with what you can and can't do client-side in Javascript. I know you can get a user's IP, but is it possible to get a user's mac address? Are those ranges different between iPad2's and iPad mini's?

like image 39
flexd Avatar answered Oct 02 '22 12:10

flexd


I know that is a horrible solution, but at the moment the only way to differentiate between an iPad Mini and an iPad 2 is to check its build number and map each build number with the related device.

Let me give you an example: iPad mini, version 6.0, is exposing "10A406" as build number, while iPad 2 is exposing "10A5376e".

This value can be easily obtained through a regex on the user agent (window.navigator.userAgent); that number is prefixed with "Mobile/".

Unfortunately this is the only unequivocal way to detect an iPad Mini; I would suggest to adopt a viewport related approach (where supported, using vh / vw units) to properly display contents on different screen sizes.

like image 23
Alessandro Piatti Avatar answered Oct 02 '22 13:10

Alessandro Piatti


tl;dr Don't compensate for the difference between iPad mini and iPad 2 unless you'll also compensate between fat and skinny fingers.

Apple appears to be deliberately trying not to let you tell the difference. Apple appears not to want us to write different code for the different size versions of iPads. Not being part of Apple myself, I don't know this for sure, I'm just saying that this is what it appears like. Maybe, if the developer community comes up with a fancy detector for iPad minis, Apple may deliberately break that detector in future versions of iOS. Apple wants you to set your minimum target size to 44 iOS points, and iOS will display that in two sizes, the larger iPad size and the smaller iPhone/iPad mini size. 44 points is plenty generous, and your users will certainly know if they are on the smaller iPad, so can compensate on their own.

I suggest stepping back to your stated reason for asking for the detector: adjusting target size for end user comfort. By deciding to design for one size on the large iPad and another size on the small iPad you are deciding that all people have the same size fingers. If your design is tight enough that the difference in size from an iPad 2 and an iPad mini makes a difference, than the size of fingers between me and my wife will make a bigger difference. So compensate for user finger size, not iPad model.

I have a suggestion on how to measure finger size. I'm a native iOS developer, so I don't know if this can be accomplished in HTML5, but here's how I would measure finger size in a native app. I'd have the user pinch two objects together, then measure how close they get together. Smaller fingers will get the objects closer together, and you can use this measurement to derive a scaling factor. This automatically adjusts for iPad size. The same person will have a larger measurement of on screen points on an iPad mini than on an iPad 2. For a game you can call this a calibration step, or not even call it out. Have it as a starting step. For example in a shooting game have the player put the ammo in the gun with a pinching motion.

like image 20
Mr. Berna Avatar answered Oct 02 '22 14:10

Mr. Berna


Ask the user to drop their iPad from several thousand feet above the ground. Then use the internal accelerometer to measure the time it takes for the iPad to reach terminal velocity. The larger iPad has a greater drag coefficient and should reach terminal velocity in less time than an iPad Mini.

Here is some sample code to get you started.

function isIPadMini( var timeToReachTerminalVelocity )
{
    return (timeToReachTerminalVelocity > IPAD_MINI_THRESHOLD);
}

You almost certainly need to revisit this code when Apple inevitably releases the next iPad in a different form factor. But I am sure you will stay on top of things and maintain the this hack for each new version of the iPad.

like image 42
Jason Avatar answered Oct 02 '22 13:10

Jason


Unfortunately, at the moment it seems like this isn't possible: http://www.mobilexweb.com/blog/ipad-mini-detection-for-html5-user-agent

Two days ago, I’ve tweeted about the first detected problem: “It is confirmed that the iPad Mini User Agent is the same as the iPad 2“. I’ve received literally hundreds of answers saying that user agent sniffing is a bad practice, that we should detect features not devices, etc, etc.

Well yes guys, you are right, but it has no direct relationship with the problem. And I need to add the second bad news: there is no client-side technique to make ”feature detection” neither.

like image 21
BenM Avatar answered Oct 02 '22 14:10

BenM


This is a wild shot, but one of the difference between iPad 2 and iPad mini is that the former does not have a 3-axis gyroscope. Maybe it'll be possible to use the WebKit device orientation API to see what sort of information you can get from it.

For example, this page seems to suggest that you can only get the rotationRate value if the device has a gyroscope.

Sorry I can't give a working POC - I don't have access to an iPad mini. Maybe someone who knows a bit more about these orientation APIs can chime in here.

like image 38
Assaf Lavie Avatar answered Oct 02 '22 14:10

Assaf Lavie


Well, the iPad 2 and the iPad Mini have different sized batteries.

If iOS 6 supports it, you can get the current battery level from 0.0..1.0 using window.navigator.webkitBattery.level. At some level either in hardware or software, that is likely calculated as CurrentLevel / TotalLevel, where both are ints. If so, that will result in a float which is a multiple of 1 / TotalLevel. If you take lots of battery level readings from both devices, and calculate battery.level * n you might be able to find a value of n where all the results start to be close to integers, which will give you iPad2TotalLevel and iPadMiniTotalLevel.

If those two numbers are different, and mutually prime, then in production you can calculate battery.level * iPad2TotalLevel and battery.level * iPadMiniTotalLevel. Whichever is closer to an integer will indicate which device is being used.

Sorry about the number of ifs in this answer! Hopefully something better will come along.

like image 23
Douglas Avatar answered Oct 02 '22 14:10

Douglas


EDIT 1: My original answer, below, was "don't do it". In the interest of being positive:

The real question, I think, has nothing to do with the iPad X vs. iPad mini. I think it is about optimizing UI element dimensions and placement to the user's ergonomics. You need to determine the size of the user's finger/s in order to drive your UI element sizing and, perhaps, positioning. This, again, is and should probably be arrived at without needing to actually know what device you are running on. Let's exaggerate: Your app is running on a 40 inch diagonal screen. Don't know the make and model or the DPI. How do you size the controls?

You need to display a button that is the gating element into the site/game. I'll leave it up to you to decide where or how it makes sense to do this.

While the user will see this as a single button, in reality it will be composed of a matrix of small tightly packed buttons that is visually covered to appear as a single button image. Imagine a 100 x 100 pixel button made up of 400 buttons, each 5 x 5 pixels. You need to experiment to see what makes sense here and how small your sampling needs to be.

Possible CSS for button array:

.sense_row {
  width:100px;
  height:5px;
  margin:0;
  padding:0;
}

.sense_button {
  float:left;
  width:3px;
  height:3px;
  padding:0px;
  margin:0px;
  background-color:#FF0;
  border:1px solid #000;
} 

And the resulting array:

button array

When the user touches the button array you will, effectively, get an image of the user's finger's contact area. You can then use whatever criteria you want (probably empirically derived) in order to arrive at a set of numbers that you can use to scale and position the various UI elements per your requirements.

The beauty of this approach is that you no-longer care about what device name or model you might be dealing with. All you care about is the size of the user's finger in relation to the device.

I would imagine that this sense_array button could be hidden as part of the entry process into the application. For example, if it is a game, maybe there's a "Play" button or various buttons with the user's names or a means to select what level they'll play, etc. You get the idea. The sense_array button could live anywhere the user has to touch in order to get into the game.

EDIT 2: Just noting that you probably don't need that many sense buttons. A set of concentric circles or buttons arranged like a huge asterisk * might do just fine. You have to experiment.

With my old answer, below, I am giving you both sides of the coin.

OLD ANSWER:

The right answer is: Don't do this. It's a bad idea.

If your buttons are so small that they become unusable on a mini you need to make your buttons larger.

If I have learned anything at all in doing native iOS apps it's that trying to outsmart Apple is a formula for undue pain and aggravation. If they chose to not allow you to identify the device it's because, well, in their sandbox, you shouldn't.

I wonder, are you adjusting the size/location in portrait vs. landscape?

like image 24
martin's Avatar answered Oct 02 '22 14:10

martin's


What about a micro benchmark, calculate something that takes roughly X microseconds on iPad 2 and Y sec on iPad mini.

It's probably not accurate enough, but there might be some instruction the iPad mini's chip is more efficient at.

like image 44
Les Avatar answered Oct 02 '22 14:10

Les


Yes, it's a good point to check gyroscope. You can easily do it with

https://developer.apple.com/documentation/webkitjs/devicemotionevent

or something like

window.ondevicemotion = function(event) {
    if (navigator.platform.indexOf("iPad") != -1 && window.devicePixelRatio == 1) {
        var version = "";
        if (event.acceleration) version = "iPad2";
        else version="iPad Mini";

        alert(version);
    }
    window.ondevicemotion = null;
}​

Don't have any iPads to test it out.

like image 41
lc0 Avatar answered Oct 02 '22 12:10

lc0


Require all users with the iPad2 user agent to supply a photo using the built in camera and detect the resolution using the HTML File API. iPad Mini photos will be higher resolution due to the improvements in the camera.

You could also play around with creating an invisible canvas element, and convert it to a PNG/JPG using the Canvas API. I don't have any way to test it, but the resulting bits might be different due to the underlying compression algorithm and the device's pixel density.

like image 20
Vlad Magdalin Avatar answered Oct 02 '22 14:10

Vlad Magdalin


You could always ask the user?!

If the User can't see the buttons or content, then give them a way to manage the scaling themselves. You could always build in some scaling buttons to the site to make the content (text/buttons) larger / smaller. This would be (almost) guaranteed to work for any current iPad resolution and probably any future resolution apple decide they want to make.

like image 42
TK. Avatar answered Oct 02 '22 13:10

TK.


This isn't an answer to your question as posed, but I hope it will be more useful than saying "don't do that":

Instead of detecting the iPad Mini, why not detect that a user is having a hard time hitting the control (or: is consistently hitting in a subregion of the control), and grow / shrink the size of the control to accommodate them?

Users who need bigger controls get them regardless of hardware; users who don't need bigger controls and want to see more content get that too. It's not a simple as just detecting the hardware, and there will be some subtle things to get right, but if it were done carefully it could be really nice.

like image 25
Stephen Canon Avatar answered Oct 02 '22 14:10

Stephen Canon


This reminds me of a quote from the movie Equilibrium:

"What, would you say, is the easiest way to get a weapon away from a Grammaton Cleric?"

"You ask him for it."

We're so used to fighting for solutions, when sometimes, it may be better to ask. (There are good reasons that we usually don't do this, but it's always an option.) All of the suggestions here are brilliant, but a simple solution might be to have your program ask which iPad they're using when they start it.

I know that this is kind of a cheeky answer, but I hope it's a reminder that we don't have to fight for everything. (I've braced myself for the downvotes. :P)

Some examples:

  • Keyboard detection during OS installations sometimes can't detect a specific keyboard, so the installer has to ask.
  • Windows asks whether a network you connect to is a home network or a public network.
  • Computers can't detect the person who is about to use it, so they require a username and password.

Best of luck - I hope you find an awesome solution! If you don't, though, don't forget this one.

like image 5
jedd.ahyoung Avatar answered Oct 02 '22 13:10

jedd.ahyoung


Not answering the question, but the question behind the question:

Your goal is to improve the user experience on a smaller screen. The appearance of the UI controls is one part of it. Another part of UX is the way the application responds.

What if you make the area that responds to taps big enough to be user friendly on the iPad Mini while keeping the visual representation of the UI controls small enough to be visually pleasing on the iPad?

If you have gathered enough taps that were not in the visual area, you can decide to visually scale the UI Controls.

As a bonus, this works for big hands on iPad as well.

like image 4
Laurens Avatar answered Oct 02 '22 13:10

Laurens


All solutions here are not future-proof (what prevents Apple from releasing an iPad with the same screen size as the iPad 2 but same resolution as the iPad Mini). So I came up with an idea:

Create a div with 1 inch width and append it to the body. Then I create another div with 100% width and append it to the body:

var div1= $("<div/>").appendTo(document.body).width("1in");
var div2= $("<div/>").appendTo(document.body).width("100%");

jQuery width() function always returns values in pixels so you can just:

var screenSize= div2.width() / div1.width();

screenSize now holds the size available to the application in inches (beware rounding erros though). You can use that to place your GUI the way you like it. Also don't forget to remove the useless divs afterwards.

Also note that the algorithm proposed by Kaspars not only will not work if the user runs the application as full screen, but it will also break if Apple patches the browser UI.

This won't differentiate the devices, but as you explained in your edit what you actually wants to know is the device screen size. My idea will also not tell you exactly the screen size, but it will give you an even more useful information, the actual size (in inches) that you have available to draw your GUI.

EDIT: Use this code to check if it actually works on your device. I don't own any iPads to test it on.

var div1= $("<div/>").appendTo(document.body).width("1in").height("1in").css("position", "absolute");
var div2= $("<div/>").appendTo(document.body).width("100%").height("100%").css("position", "absolute");
var width= div2.width() / div1.width()
var height= div2.height() / div1.height()
alert(Math.sqrt(width*width + height*height));

It should popup a window with your screensize in inches. It seems to work on my laptop, returning 15.49 while my laptop screen is marketed as 15.4''. Can anyone test this on iPads and post comments please? Don't forget to run it full screen.

EDIT2: It turns out that the page I tested it in had some conflicting CSS. I fixed the test code to work properly now. You need position: absolute on the divs so you can use height in %.

EDIT3: I did some research, and it seems there is no way to actually get the size of the screen on any device. It's not something the OS can know. When you use a real world unit in CSS it is actually just an estimation based on some properties of your screen. Needless to say that this is not accurate at all.

like image 4
Hoffmann Avatar answered Oct 02 '22 13:10

Hoffmann


Not tested, but instead of playing an audio file and check the balance, it could work to listen to the microphone, extract the background noise, and compute its "color" (frequency graph). If IPad Mini has a different microphone model than IPad 2, then their background color should be measurably different and some audio fingerprinting techniques might help you tell which device is in use.

I don't seriously think it could be feasible and worth the hassle in this specific case, but I think fingerprinting the background noise could be used in some apps, for example to tell you where you are when you are inside a building.

like image 1
gb. Avatar answered Oct 02 '22 12:10

gb.


Based on Douglas question about new webkitAudioContext().destination.numberOfChannels on iPad 2 I decided to run some tests.

Checking numberOfChannels returned 2 on iPad mini but nothing on iPad 2 with iOS 5 and 2 as well with iOS 6.

Then I tried to check if webkitAudioContext is available

var hasWebkitAudio = typeof(webkitAudioContext) === "object";
alert(hasWebkitAudio);​

Same here iPad Mini and iPad 2 with iOS 6 returns true while iPad 2 with iOS 5 returns false.

(This test don't work on desktop, for desktop check if webkitAudioContext is a function).

Here's the code for you to try out: http://jsfiddle.net/sqFbc/

like image 1
Alfred Avatar answered Oct 02 '22 13:10

Alfred


What if you created a bunch of 1"x1" wide divs and appended them one by one to a parent div until the bounding box jumped from 1 inch to 2 inches? An inch on the mini is the same size as an inch on the iPad, right?

like image 1
Scovetta Avatar answered Oct 02 '22 14:10

Scovetta


In iOS7 there is a system-wide setting user can tweak: when things become too small to read, Text Size setting can be changed.

That text size can be used to form UI of plausible dimensions, e.g. for a button (tested on iPad Mini Retina to react to Text Size setting changes):

padding: 0.5em 1em 0.5em 1em;
font: -apple-system-body;    

(sample button CSS, thanks to jsfiddle and cssbuttongenerator)

like image 1
Srg Avatar answered Oct 02 '22 14:10

Srg


I am detecting the iPad mini by creating a canvas that is larger an iPad mini can render, filling a pixel then reading the color back out. The iPad mini reads the color as '000000'. everything else is rendering it as the fill color.

Partial code:

function rgbToHex(r, g, b) {
    if (r > 255 || g > 255 || b > 255)
        throw "Invalid color component";
    return ((r << 16) | (g << 8) | b).toString(16);
}
var test_colour = '8ed6ff';
working_context.fillStyle = '#' + test_colour;
working_context.fillRect(0,0,1,1);
var colour_data = working_context.getImageData(0, 0, 1, 1).data;
var colour_hex = ("000000" + rgbToHex(colour_data[0], colour_data[1], colour_data[2])).slice(-6);

I need this for canvas sizing so it's feature detection in my use case.

like image 1
SystemicPlural Avatar answered Oct 02 '22 13:10

SystemicPlural