I am using ui-screen-shooter, which makes use of the UI Automation JavaScript API to take screenshots of apps. My app has a slightly different structure on iPad and iPhone, so I need to detect the device type in my shoot_the_screen.js script and run different code. I would like something equivalent to [[UIDevice currentDevice] userInterfaceIdiom] that I can use in JavaScript. Here is the best I have come up with. It works, but do you know of a cleaner, less device-dependent way to get the same information?
var target = UIATarget.localTarget();
var width = target.rect().size.width;
if (width == 1024 || width == 768)
{
// iPad
}
else
{
// iPhone
}
You can call model() on the target to get the information you need. That's exactly what I'm doing in the ui-screen-shooter itself.
var modelName = UIATarget.localTarget().model();
// This prints "iPhone" or "iPad" for device. "iPhone Simulator" and "iPad Simulator" for sim.
UIALogger.logMessage(modelName);
Related
Before voting for duplicate:
Please read the full question below. I explained there why any of "how to detect mobile device?" is not a case here.
Question (and why it's not a simple negation of mobile dev. detection):
There are plenty of questions about "How to detect an mobile device with JavaScript?" (one of the best, if you are looking for it: What is the best way to detect a mobile device in jQuery?), but I want to ask for something a bit different: "How to detect non-mobile device with JavaScript?".
You might think that when I can make an mobile detection like this:
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile
|Opera Mini/i.test(navigator.userAgent)){
alert('mobile');
}
I can just put negation before the statement inside if and that would be check for non-mobile device. Not really.
The code above detects several versions of mobile devices. For all not recognized devices, we cannot be 100% sure that they are not mobile. If userAgent contains one of the typed literals (webOS, iPone etc.) it's surely a mobile device. If not, it can goes two ways:
It's not a mobile device
It's a mobile device that we did not listed (mistake, exotic device, device released after we wrote the code etc.)
So instead of negating the test for mobile device, I want to write a test for non-mobile (Linux/Windows PC, Mac etc.). That way, if the result will be true, I will be 100% sure that I deal with non-mobile device. In the other case - it's rather mobile, but it's only an strong assumption.
So basically, I want to react only when I'm 100% sure it's non-mobile device, and when I do not know it for sure, I don't want to take any steps (or I will assume it's a mobile device).
How would that formula look? It's safe to test against Windows (Windows Phone or something like that could also use that literal?)? What about Mac, Linux PC and others?
This is taken from here:
var BrowserDetect = function() {
var nav = window.navigator,
ua = window.navigator.userAgent.toLowerCase();
// detect browsers (only the ones that have some kind of quirk we need to work around)
if (ua.match(/ipad/i) !== null)
return "iPod";
if (ua.match(/iphone/i) !== null)
return "iPhone";
if (ua.match(/android/i) !== null)
return "Android";
if ((nav.appName.toLowerCase().indexOf("microsoft") != -1 || nav.appName.toLowerCase().match(/trident/gi) !== null))
return "IE";
if (ua.match(/chrome/gi) !== null)
return "Chrome";
if (ua.match(/firefox/gi) !== null)
return "Firefox";
if (ua.match(/webkit/gi) !== null)
return "Webkit";
if (ua.match(/gecko/gi) !== null)
return "Gecko";
if (ua.match(/opera/gi) !== null)
return "Opera";
//If any case miss we will return null
return null;
};
It's not very elegant but you can add/remove it to your preference.
A second answer, while I understand you are specifically looking for a NON mobile detection, you could also use http://detectmobilebrowsers.com/ which has almost complete mobile device detection (Even the less popular).
I am using a "shake" function from github - and it has a detection that is browser-based javascript.
//feature detect
this.hasDeviceMotion = 'ondevicemotion' in window;
This though yields true even on Chrome on OS X.
It feels strange, since I am not willing to shake my monitor on my desktop.
Safari on OS X gives me "false" in return when testing.
I have searched but not been able to find out why Chrome decided to take this path. It bugs me.
Is there a better way to make this detection? Not all "mobile devices" has shake as well.. or does not let the browser have that capability, as it does not seem to work in windows phones.
not really sure about your question and as well, I am just digging into its functionality, however you could use something like
X : <span id="varx"></span>
Y : <span id="vary"></span>
Z : <span id="varz"></span>
<script>
window.ondevicemotion = function(event){
var accelerationX = event.accelerationIncludingGravity.x;
var accelerationY = event.accelerationIncludingGravity.y;
var accelerationZ = event.accelerationIncludingGravity.z;
document.getElementById("varx").innerHTML = accelerationX;
document.getElementById("vary").innerHTML = accelerationY;
document.getElementById("varz").innerHTML = accelerationZ;
};
</script>
it will show this value only if the event have the accelerationIncludingGravity property, this is only available in mobile, not 100% this is what you want, you could also trigger an event asking for if(accelerationX){//execute action}else{//execute planB} hope this help, if it doesn't I'll be happy to learn and get some feedback.
Requirement - Detect tablets using JavaScript
I'm not allowed to use any plugin or lib (jQuery is an exception) and want to keep code to minimum.
I have read many posts on this topic and came up with this solution (Checking screen resolution and touch):
var _w = Math.max($(window).width(), $(window).height());
var _h = Math.min($(window).width(), $(window).height());
var tabletView = (_w >= 1000 && _h >= 600);
var is_touch_device = 'ontouchstart' in document.documentElement;
if (tabletView && is_touch_device) {
alert('tablet');
}
else {
alert('Not a Tablet');
}
Question: Is this code reliable enough? If not what's the better approach?
This will also see phones with larger screen resolutions as tablets.
Other than that, this code is reliable, and there isn't really anything you could do to detect the difference between a phone and tablet, without libraries, or manually parsing user-agents.
A client recently asked me to implement a slideshow on our website. I'm concerned that constantly animating picture transitions on the homepage will peg the processor of most mobile devices, so I want to disable the automatic advancing to preserve battery life. Is there any way to do this without trying to detect the user agent?
I've seen that there is a battery status API drafted here, but I don't know how complete it is, or which browsers have implemented it.
Actually determining battery would be quite difficult and probably involve various permissions problems.
Try just executing a small piece of code and checking the time it took. Pick a cutoff and if the code executes too slowly, turn off the transitions/animation/autoadvance. This will catch more than just battery devices; anything too slow will get the un-animated version. Degrade gracefully.
Now you can, with this API: http://davidwalsh.name/javascript-battery-api
navigator.getBattery().then(function(result) {});
Another old topic, but still relevant - I now check if the device has motion sensors, not many laptops do, but all modern smart phones and tablets do - so laptop users can live with slightly more battery use -
jQuery:
if (window.DeviceOrientationEvent) {
$(window).one("devicemotion", function(event) {
if (event.originalEvent.acceleration
&& event.originalEvent.acceleration.x !== null) { // Chrome fakes it on desktop
isMobile = true;
}
});
}
Plain Javascript:
if (window.DeviceOrientationEvent) {
window.ondevicemotion = function(event) {
if (event.acceleration
&& event.acceleration.x !== null) { // Chrome fakes it on desktop
window.ondevicemotion = null;
isMobile = true;
}
};
}
I have a fairly large HTML/JS/CSS application that works great when running as a web application with Safari on the iPhone.
When running this same application in an UIWebView within a native iPhone application calls within jQuery to create HTML fragments fail silently (ie: $("<div>HELLO WORLD</div>"); will not create the element.
I've tracked this down to the following equivalent code snippet in clean jQuery method:
var div = document.createElement(“div”);
div.innerHTML = “<div>HELLO WORLD</div>”;
When I look at div.outerHTML I see
<div>/<div>
div.innerHTML returns an empty string.
This does not appear to be a jQuery problem, nor does this happen 100% of the time. I haven’t been able to find a pattern, but in some cases it works 2-3 times in a row, sometimes if fails 5-6 times consecutively. This seems to only shows up when running the application inside a UIWebView in an Objective-C application. Also I’ve only seen this on an actual device running iOS 4.2, not the emulator.
Has anyone run into anything similar? Does anyone have a fix?
I had this problems too. It happens when the CPU of the phone is very busy (say 100%). Then the rendering engine sometimes forget about innerHTML settings.
The solution included in my unify project is to test if there is an element in childNodes, otherwise apply it again.
var target = document.createElement("div");
var text = "<div>Hello World</div>";
target.innerHTML = text;
var self = this;
self.__intervalHandle = window.setInterval(function() {
target.innerHTML = text:
if (target.firstChild) {
window.clearInterval(self.__intervalHandle);
self.__intervalHandle = null;
}
}, 100);
This forces the rendering engine to apply the innerHTML to the DOM and gives the rendering engine some time (100 ms in this example, a good value in our tests) to handle it.
Well, the solution [NOT a production quality solution] posted by Sebastian worked, but I couldn’t confirm if CPU load would cause this issue. I generated a lot of background load on the iOS host and couldn’t reproduce this issue.
Upon further investigation, the rendering issue seems to be a side effect of iOS shell canceling the navigation. Once the navigation is canceled by the iOS shell, the rendering engine probably take that as not needing to render more UI [basically doesn’t render anything for a small period].
One way to fix this would be to send commands to iOS shell as hash (#) parameters instead of a URL. This way iOS shell will get the commands and doesn’t need to cancel the navigation. This approach seems to work in the test code below. So, if window.location is set to location1, it alerts “At: 1” and element e2 has no value. And if the window.location is set to location2, it alerts “At: 0” and element e2 has the value.
#Kevin, could you confirm that you were canceling the navigation on iOS host when this behavior happened.
Test Code:
Javascript:
var location1 = "myApp://Test";
var location2 = "#myApp://Test";
$("#change").live("click", function (e) {
var element = document.getElementById("e1");
window.location = location1; var i = 0;
element.innerHTML = "At: " + i;
window.__intervalHandle = window.setInterval(function () {
var html = element.innerHTML;
if (html) {
alert(html);
window.clearInterval(window.__intervalHandle);
window.__intervalHandle = null;
} else {
element.innerHTML = "At: " + ++i;
}
}, 1);
document.getElementById("e2").innerHTML = "Test";
});
iOS pseudo code:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL* u = [ request URL];
if( [[u scheme] compare:#"myapp" ] == NSOrderedSame) {
{
return NO; // don’t navigate
}
return YES; // navigate
}
You should take a look at http://blog.techno-barje.fr/post/2010/10/06/UIWebView-secrets-part3-How-to-properly-call-ObjectiveC-from-Javascript.
It turns out that cancelling navigation as part of the -webView:shouldStartLoadWithRequest: delegate method may cause issues with innerHTML. I updated our JS code to use the method recommended in that article and I haven't seen the innerHTML issue crop up in a while.