Detect if page is loaded inside WKWebView in JavaScript - javascript

How can I reliably detect using javascript that a page is loaded inside a WKWebView? I'd like to be able to detect these scenarios:
iOS & WKWebView
iOS & Safari
not iOS
There is a similar question about UIWebView here. But it's quite old and I'm not sure if same still applies to WKWebView.

The accepted answer doesn't work as tested using the WKWebView vs UIWebView app
As the article mentions, the only HTML5 feature difference is IndexedDB support. So I'd go for a more reliable pattern with:
if (navigator.platform.substr(0,2) === 'iP'){
//iOS (iPhone, iPod or iPad)
var lte9 = /constructor/i.test(window.HTMLElement);
var nav = window.navigator, ua = nav.userAgent, idb = !!window.indexedDB;
if (ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !nav.standalone){
//Safari (WKWebView/Nitro since 6+)
} else if ((!idb && lte9) || !window.statusbar.visible) {
//UIWebView
} else if ((window.webkit && window.webkit.messageHandlers) || !lte9 || idb){
//WKWebView
}
}
You may ask: Why not using the UserAgent? That's because Android browsers use it as settings! So, we should never trust any UAs. Only browser features and property checks as such.
Also I noticed that the QuickTime plugin was always loaded as part of Older Safari and other Browsers in UIWebView. But the plugin is no longer present in WKWebView. So you can use the QuickTime plugin presence as an extra check.
9/23/16 Edit: I adjusted the code for Safari 10 which no longer allowed the sole idb check to be reliable, as mentioned by #xmnboy. To discard Safari 10, it checks for the old webkit engine bug, which only applied until Safari 9.2; and i use a window.statusbar.visible fallback which appears to be a reliable indicator signal after a few comparison tests between iOS 9 and 10. (please check though)

Given the change in behavior to the UIWebView that was introduced by Apple in iOS 10, here's a new answer that combines the original response by #Justin-Michael and the follow-up favorite by #hexalys.
var isWKWebView = false ;
if( navigator.platform.substr(0,2) === 'iP' ) { // iOS detected
if( window.webkit && window.webkit.messageHandlers ) {
isWKWebView = true ;
}
}
It turns out that Justin's answer was really the better feature detection mechanism, because it works for both iOS 9 and iOS 10.
No telling what happens when we get to iOS 11. :-)
Qualification: this test will work if you are using the official Cordova WKWebView plugin to build your webview app, because that plugin does initialize the addScriptMessageHandler method, as noted by #hexalys in the comments to this post. That mechanism is being used by Cordova to define a new JS to native bridge when the WKWebView plugin is present.
Search for addScriptMessageHandler in that plugin repo and see the very end of the ios-wkwebview-exec.js file in that repo for some implementation details (or search for the string window.webkit.messageHandlers in that file).

In iOS, you could add this code to establish communication between javascript and objective-c:
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *controller = [[WKUserContentController alloc] init];
[controller addScriptMessageHandler:self name:#"javascript_observer"];
configuration.userContentController = controller;
...
webview = [[WKWebView alloc] initWithFrame:... configuration: configuration];
In javascript, you could test the connection like this:
if ( window.webkit != undefined ){
//javascript is running in webview
}

It seems that because the latest iOS Chrome uses WKWebView as a rendering engine, Chrome is detected as WKWebView.
ua.indexOf('CriOS') !== -1
will helps to distinguish Chrome from WKWebView in App.

You can check for the existence of window.webkit.messageHandlers which WKWebKit uses to receive messages from JavaScript. If it exists, you're inside a WKWebView.
That combined with a simple user agent check should do the trick:
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);
var isWKWebView = false;
if (window.webkit && window.webkit.messageHandlers) {
isWKWebView = true;
}

Related

Detect if the user is navigating through the safari mobile browser on iphone

I am trying to detect if the user is navigating my website from safari browser on the iphone using jquery / javascript.
I am able to detect the IOS Environment using the user agent string
/iphone/i.test(navigator.userAgent.toLowerCase())
But this detects the Apple Webkit Environment i.e. it is same for all the browsers on the device. Can anyone suggest any different approach.
UPDATED:
Try this, for detecting Safari browser in an iPhone:
var isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
It identifies Safari 3.0+ and distinguishes it from Chrome.
JsFiddle
Since the other answer doesn't include detection of an iPhone, including that part.
var isIphone = /(iPhone)/i.test(navigator.userAgent);
var isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
if(isIphone && isSafari){
//do something
}
If you want to detect a particular iOS version and above, say iOS 7.0 and above then you can use the below code. It detects iOS version 7-19(for upcoming versions).
var isIphone= /(iPhone)*(OS ([7-9]|1[0-9])_)/i.test(navigator.userAgent);
var isFirefox = navigator.userAgent.indexOf("FxiOS") != -1;
var isChrome = navigator.userAgent.indexOf("CriOS") != -1;
var isEdge = navigator.userAgent.indexOf("EdgiOS") != -1;
var isOpera = navigator.userAgent.indexOf("OPT") != -1;
if (!isFirefox && !isChrome && !isEdge && !isOpera){
console.log("Only display in Safari")
} else {
console.log("Only display in Firefox/Chrome/Edge/Opera")
}
Hi, this way worked for me to detect only safari in ios mobile. The value FxiOs, CriOs, etc, I get from the userAgent value.

Is it possible to evaluate whether the clients browser is in incognito mode? [duplicate]

I'm building an extranet for a company paranoid about security. They want to make sure that (among other things) their users are browsing the site with the Private Browsing mode switched on in their web browser so that no cookies or history is kept.
I found only this
http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html
and
https://serverfault.com/questions/18966/force-safari-to-operate-in-private-mode-and-detect-that-state-from-a-webserver
The ideal solution would use no or minimal javascript. Would attempting to set a unique cookie work for all browsers and platforms? Anyone done this before?
thanks!
update
http://crypto.stanford.edu/~collinj/research/incognito/ uses the CSS visited technique of the browser fingerprinters mentioned by other posters- thanks for the hints.
I like it because it is small and elegant, but still want to be able to do it without javascript if possible.
Update June 2019
Google is removing the ability to detect Private Browsing Mode permanently in Chrome 76 onwards. So, if you're wanting to detect private browsing it's now impossible (unless you find a way to do it that Google hasn't found). The ability to detect private browsing mode has been acknowledged as a bug and was never intended.
To anyone else coming across this question, please note as of 2014, there is no reliable or accurate way to detect if someone is browsing in an incognito/private/safe browsing mode through Javascript or CSS. Previous solutions that once worked like the CSS history hack have since been rendered unusable by all browser vendors.
There should never be a situation where needing to detect private browsing mode on a normal day-to-day website is ever needed. People are choosing to browse anonymously and or not anonymously for their own reasons.
Browsers like Chrome and Firefox do not disable functionality like localStorage any more. They simply namespace it in a temporary location to prevent websites that use it from erroring out. Once you're finished browsing, the namespace is erased and nothing is saved. If you are testing for localStorage support regardless of mode, it will always return true for browsers that support it.
Other means of detecting private mode in Chrome specifically have been completely patched and will no longer work.
If it is required internally by a company, you should develop a browser plugin. Chrome and Firefox, in particular, expose internal API's which allow plugins to check if the user is in private browsing/incognito mode and action accordingly. It cannot be done outside of a plugin.
Here's an easier way to do detect privacy mode. This works in Safari only. I created it because a web app I am developing uses localStorage. LocalStorage is not available in Safari when in privacy mode, thus my app will not work.
On page load, run the script below. It shows an alert box if we cannot use localStorage.
try {
// try to use localStorage
localStorage.test = 2;
} catch (e) {
// there was an error so...
alert('You are in Privacy Mode\nPlease deactivate Privacy Mode and then reload the page.');
}
Current state
Google Chrome has developed further and leaves no more space for detection when using incognito mode. Same might apply for other browsers.
Old solutions (might partially work)
It is possible to detect enabled private browsing modes for the majority of used browsers. This includes Safari, Firefox, IE10, Edge and Google Chrome.
Firefox
When the private browsing mode of Firefox is enabled, the IndexedDB throws an InvalidStateError because it is not available in private browsing mode.
To very if that:
var db = indexedDB.open("test");
db.onerror = function(){/*Firefox PB enabled*/};
db.onsuccess =function(){/*Not enabled*/};
Safari
For Safari, the key is the local storage service. It is disabled in privacy mode. So try to access it and use a try-catch clause.
The following method works on both, OSX and iOS devices. Credits for this method are going to this question and answer
var storage = window.sessionStorage;
try {
storage.setItem("someKeyHere", "test");
storage.removeItem("someKeyHere");
} catch (e) {
if (e.code === DOMException.QUOTA_EXCEEDED_ERR && storage.length === 0) {
//Private here
}
}
IE10/Edge
Internet Explore is even going to disable the IndexedDB when in privacy mode. So check for existence. But that's not sufficient enough, because older browsers maybe don't even have an IDB. So do another check, e.g. for events that only IE10 and subsequent browser have/trigger. A related question on CodeReview can be found here
if(!window.indexedDB && (window.PointerEvent || window.MSPointerEvent)){
//Privacy Mode
}
Chrome
Update: This doesn't work since Chrome 76 (thanks to #jLynx)
Chromes Incognito mode can be verified by the file system. A great explanation can be found here on SO
var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
if (!fs) {
console.log("FS check failed..");
return;
}
fs(window.TEMPORARY, 100, function (fs) {}, function (err) {
//Incognito mode
});
update on safari
Safari (release v29) patched localstorage so that you can no longer use it for detection.
I saw one other solution that tries to save blob/files in indexedDB and that will reject with an error saying that it can't store fils when surfing in private mode.
but there is a new / easier method with the new whatwg/fs
navigator.storage.getDirectory().then(root => {
console.log('not private')
}, err => {
console.log('private')
})
Chrome 83 arrives with redesigned security settings, third-party cookies blocked in Incognito by default!
So this one is easy, create a iframe to a third party site, have it send a postMessage back notifying you if navigator.cookieEnabled is true or false. Ofc users have the option to disable third party cookie as well. So i tested and disabled 3th party cookies in the settings. But it still said cookie was enabled on third-party iframes using navigator.cookieEnabled. it only became disabled once i used Incognito - perhaps a bug?
new Promise((rs, rj, m = new MessageChannel(), d = document, i = d.createElement('iframe')) => {
i.src = 'https://httpbin.org/base64/PHNjcmlwdD5vbm1lc3NhZ2UgPSBlID0+IGUuZGF0YS5wb3N0TWVzc2FnZShuYXZpZ2F0b3IuY29va2llRW5hYmxlZCk8L3NjcmlwdD4='
i.onload = _ => i.contentWindow.postMessage(m.port1, '*', [m.port1], m.port2.onmessage = e => i.remove(rs(e.data)))
i.hidden = 1
d.body.append(i)
}).then(thirdPartyCookieEabled =>
console.log('Third party cookie enabled:', thirdPartyCookieEabled)
)
You could also probably do it using only js + ajax but didn't want to set up a 2 servers to test it myself. but for this SameSite=none have to be set as well.
res = await fetch('https://httpbin.org/cookies/set?enabled=1', {
credentials: 'include'
})
json = await res.json()
console.log(!!json.cookies.enabled)
Here is my take on detecting private mode
function detectPrivateMode(cb) {
var db,
on = cb.bind(null, true),
off = cb.bind(null, false)
function tryls() {
try {
localStorage.length ? off() : (localStorage.x = 1, localStorage.removeItem("x"), off());
} catch (e) {
// Safari only enables cookie in private mode
// if cookie is disabled then all client side storage is disabled
// if all client side storage is disabled, then there is no point
// in using private mode
navigator.cookieEnabled ? on() : off();
}
}
// Blink (chrome & opera)
window.webkitRequestFileSystem ? webkitRequestFileSystem(0, 0, off, on)
// FF
: "MozAppearance" in document.documentElement.style ? (db = indexedDB.open("test"), db.onerror = on, db.onsuccess = off)
// Safari
: /constructor/i.test(window.HTMLElement) || window.safari ? tryls()
// IE10+ & edge
: !window.indexedDB && (window.PointerEvent || window.MSPointerEvent) ? on()
// Rest
: off()
}
detectPrivateMode(function (isPrivateMode) {
console.log('is private mode: ' + isPrivateMode)
})
edit found a modern, faster, synkronas way to try it in firefox (they don't have service workers in privat mode) similar to ie don't include indexedDB but the test only works in secure sites
: "MozAppearance" in document.documentElement.style ? navigator.serviceWorker ? off() : on()
There's no way for your web page to know, absolutely for sure, that the user is in private browsing mode. Any attempts to check for various browser features will need to change often as security implementations are updated. It may work for some time in some browsers, but not all.
If the company is that concerned about security, I'd suggest rolling your own Firefox or Chromium distribution with locked down privacy settings, and only allowing that custom client to connect to the extranet.
I have built a little library that will work on all major platforms and browsers that I have tested: https://github.com/jLynx/PrivateWindowCheck
You can simply call
isPrivateWindow(function(is_private) {
if(is_private)
alert('Private');
else
alert('Not Private');
});
Many seem to believe that detecting incognito/private mode is no longer possible, and I can assure you that's definitely not true. I have been unable to find any publicly available code that works on 100% of browsers, so I made my own.
As of October 2021 my code is able to detect private browsing modes on Safari 15 (macOS & iOS), Chrome 93, Edge 93, Firefox 93, Internet Explorer 10+, as well as Brave.
I should also note that detecting incognito has legitimate, non-paywall related uses, of which I am using as part of a larger private project. For example, fraudsters often use incognito when conducting credit card fraud. While alone someone filling in a checkout form in incognito doesn't immediately scream fraud, paired with other data points (such as the user using a VPN as well), I would be wary of accepting such an order.
Sites that block access based on whether one is in incognito suck, but I pin that down more to bad site design.
Shameless plug: https://github.com/Joe12387/detectIncognito
I also have a demo available: https://detectincognito.com/
I hope this is helpful.
The localStorage trick is a bug which has been fixed, and it doesn't work anymore in Safari 11.0.
There is an interesting alternative that works in Safari, Opera and Internet Explorer (not Chrome): those browser send a DNT: 1 header (Do Not Track).
It's not 100% reliable because this header can be enabled for normal browsing (it's disabled by default), but it can help to identify privacy-conscious users.
Web browsers behave differently when privacy mode is activated.
On many browsers the caching of resources is limited. It is possible to detect where a browser has been based on their CSS cache. Its possible to conduct this this attack without JavaScript.
The EFF is working on a project to fingerprint browsers. Parts of the browsers fingerprint will be different when privacy mode is activated. Go ahead, try it.
You're not going to block them if they don't have private browsing enabled.
Why have a smart message box at all?
Would attempting to set a unique cookie work for all browsers and platforms? Anyone done this before?
I think the most elegant solution would be to:
Perform a security leak test
If security leak test reveals issue
Tell user to check settings
Suggest privacy mode
Because as you said, not everyone can or needs to enable privacy mode.
I agree with DigitalSeas's sentiment that we should generally not try to detect if the user is in a "private browsing" mode. However, I recently discovered that FireFox now subscribes to a service called "disconnect.me", which provides the url blacklist they use in their "tracking protection" feature. Since disconnect.me blacklists certain social networks (e.g. Facebook's facebook.net), we found that their SDKs would not load in FireFox. Therefore, it seems reasonable that we could try and detect private browsing mode in order to provide a more useful and precise error message to our users.
With that justification out of the way, this gist claims to provide detection for private browsing in major browsers using tricks specific to those browsers. At the time of this writing (the gist may have been updated by the time you read this) the detection logic is as follows:
function retry(isDone, next) {
var current_trial = 0, max_retry = 50, interval = 10, is_timeout = false;
var id = window.setInterval(
function() {
if (isDone()) {
window.clearInterval(id);
next(is_timeout);
}
if (current_trial++ > max_retry) {
window.clearInterval(id);
is_timeout = true;
next(is_timeout);
}
},
10
);
}
function isIE10OrLater(user_agent) {
var ua = user_agent.toLowerCase();
if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) {
return false;
}
var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua);
if (match && parseInt(match[1], 10) >= 10) {
return true;
}
return false;
}
function detectPrivateMode(callback) {
var is_private;
if (window.webkitRequestFileSystem) {
window.webkitRequestFileSystem(
window.TEMPORARY, 1,
function() {
is_private = false;
},
function(e) {
console.log(e);
is_private = true;
}
);
} else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) {
var db;
try {
db = window.indexedDB.open('test');
} catch(e) {
is_private = true;
}
if (typeof is_private === 'undefined') {
retry(
function isDone() {
return db.readyState === 'done' ? true : false;
},
function next(is_timeout) {
if (!is_timeout) {
is_private = db.result ? false : true;
}
}
);
}
} else if (isIE10OrLater(window.navigator.userAgent)) {
is_private = false;
try {
if (!window.indexedDB) {
is_private = true;
}
} catch (e) {
is_private = true;
}
} else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {
try {
window.localStorage.setItem('test', 1);
} catch(e) {
is_private = true;
}
if (typeof is_private === 'undefined') {
is_private = false;
window.localStorage.removeItem('test');
}
}
retry(
function isDone() {
return typeof is_private !== 'undefined' ? true : false;
},
function next(is_timeout) {
callback(is_private);
}
);
}
Browser makers are actively patching browser bugs that let sites identify private mode. Some bugs remain, but code to detect them is unlikely to be worth writing as the plan is it won't work for long.
The reason why browser makers are fixing these bugs is that sites like news publishers are using the bugs to identify private-mode users and refuse to serve them. The news publishers who want to do this tend to be using "metered paywalls", which let each browser view a certain number of free articles per day (or per week or whatever) and then start charging: since private-mode effectively resets the meter, the publishers don't want you to use private mode. But restricting private mode also restricts people who want to use it for other reasons, e.g. a domestic-abuse victim not wanting to keep history on a browser shared with their abuser, or someone not wanting their current activity to affect what advertisements they see in future, or some other reason. Although news sites that restrict private mode do tend to permit it if you log in, it's rather obvious that logging in lets them track you, so if you're trying to avoid being tracked then logging-in doesn't seem like an acceptable solution, hence browser makers want publishers not to be able to detect private mode.
There is another way of not keeping history: use a browser that lets you selectively clear it afterwards. Chrome for example can clear cookies, cache and history associated with specific domains, or for a specified period of time such as "for the last hour". That way you don't need private or incognito mode: you can get the same effect by browsing in normal mode and then erasing the traces. But you have to know how to do it, plus you must remember to do it, so it's a more troublesome approach than is using private mode. Still, I expect some people are using this as a workaround if their browser still has a bug that lets sites detect when they're in private mode and deny them service.
If you as a website author have a reason for not wanting your website to be stored in cache or history, for example if the site is meant to help domestic-abuse victims, then "how to detect private mode" might be the wrong question, as what you really want is "don't store this stuff in history, whether private mode is in use or not". Chris Coyier on css-tricks.com noted that window.location.replace() does not create a history item and techniques like this could be used to construct a site that at least doesn't leave its individual pages in history (at least not when browsed with Javascript switched on), but the referring page—possibly a dangerous-to-have search-result page—would still be in history, as would the final page they were on if they don't properly "sign out" of the site. (Intermediate pages might also be discernible via cache forensics, but anyone who can do that can probably also record the traffic as it happens, so we just have to hope the abuser is not that clever.) Another possible approach might be to create an innocent-looking cookie that stores the timestamp of the page's first load, and replace its content with something else if the current time exceeds that timestamp by too long, although its URL may still be loadable on another device or by clearing cookies (unless it was also session-dependent). But getting rid of the referring page is still going to be an issue, and as it's not always possible to confirm the user is in private mode, the best policy is probably to take steps to educate them about private mode anyway.
If you check their User-Agent, you can show them what both private mode and non private mode look like on their browser and OS, ask them to confirm which of the two matches their current window right now, and caution them if they choose the non private mode appearance. This won't work for browser and OS combinations you didn't test (but then neither will bug-based detection), and it assumes the user cares about their security enough to take the question seriously—but if they don't, the battle is probably already lost anyway.
Well, you wouldn't really distinguish private mode from "block all cookies" in that way, but apart from that rare situation I guess it should work.
The big problem IMO, is that this is a very very bad site design, not better than the good ol' "you need browser xxx to see this website" that was common in the '90s. Not all browser have a Private Browsing mode (as much as I despise IE, your cutting out IE7 users for instance) and those users won't be able to access your site at all.
Also, when I'm on the Internet I often have several tabs open with multiple website. It would be really annoying for me to have to switch to private mode just to see that website and not being able to access the other sites at the same time.
One thing you could do would be designing the site using sessions instead of cookies, so they won't be stored (as you don't use them...). And as for the history... really, what's the problem with that?
I've solved this issue by using two HTML pages. The main page define a status variable and set a cookie. The second page is opened in a new window (not tab), read the cookie and set status to the cookie value. Under MSIE, the cookie value is passed to the child page when the main page in normal mode. When in InPrivate Browsing mode, the cookie value is not passed to the child page (but is passed if you open a new tab).
The main.html page:
<script>
var myCookie="nocookie";
document.cookie="checkInPrivate=1";
var h=window.open("child.html", "_blank", "left=9999,height=200,width=200");
setTimeout(function() {
var status=null;
if (myCookie=="nocookie") {
status="unable to determine if we are InPrivate Browsing mode (child page did not set the cookie)";
} else if (myCookie.indexOf("checkInPrivate")>=0) {
status="not in InPrivate Browsing mode (child page did set the cookie)";
} else {
status="in InPrivate Browsing mode (child page set the cookie value but it was not provided)";
}
alert(status);
}, 200);
</script>
The child.html page:
Detecting MSIE's InPrivate Browsing mode...
<script>
window.opener.myCookie=document.cookie;
window.close();
</script>
I'm using InPrivate Browsing mode in order to prevent Browser Helper Objects (BHO) and browser extensions to be enabled, since BHO are most often malwares which can modify the web pages even if HTTPS and strong authentication are used. Internet Explorer 9 has a "Disable toolbars and extensions when InPrivate Browsing starts" in its "Privacy" settings.
However, this is not the ultimate way to prevent malicious browser extension: a malicious extension may change the main page behavior to make it think that the myCookie value has not been set and. We would wrongly assume that we are in InPrivate Browsing mode.
Note that I need cookies for my application so I do not use InPrivate Browsing for that purpose.
Write code to achieve following
1) In firefox test browser version. This method works with version >= 33.0 ( supports service workers ). Cannot use this method with old ( < 33.0 ) versions.
2) Try to set service worker.
3) If you can set,use or access a service worker you are 1000% not in private browsing mode as service workers cannot be interacted with on Firefox private browsing mode. I wish that they could be.
Quote:
"In Firefox, Service Worker APIs are hidden and cannot be used when the user is in private browsing mode"
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers
Not sure if its cause this question is old but Firefox does provide documentation on how to detect private browsing mode. However it involves using an import of theirs DXR PrivateBrowsingUtils:
try {
// Firefox 20+
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
...
}
} catch(e) {
// pre Firefox 20 (if you do not have access to a doc.
// might use doc.hasAttribute("privatebrowsingmode") then instead)
try {
var inPrivateBrowsing = Components.classes["#mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService).
privateBrowsingEnabled;
if (!inPrivateBrowsing) {
...
}
} catch(e) {
Components.utils.reportError(e);
return;
}
}
While creating my Safari extension, I found out that it was possible to query the boolean safari.self.browserWindow.activeTab.private. Below worked for me to check whether the browser was open in Private or not but only from the extension.
isPrivate = false;
try {
isPrivate = safari.self.browserWindow.activeTab.private;
} catch (_) {
isPrivate = true;
}
if (isPrivate === true){
console.log("Private window.");}
else {
console.log("Not private window.");}
Source: developer.apple.com | Instance Property private
function isPrivate(callback) {
callback || (callback = function(){});
var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
if(fs){
return fs(window.TEMPORARY, 1, callback.bind(this, false), callback.bind(this, true));
}
if(window.indexedDB && /Firefox/.test(window.navigator.userAgent)){
try {
var db = window.indexedDB.open('test');
var tryes = 0;
var interval = limit = 10;
var wait = function(check){
if(tryes >= limit){ return callback(true); } // Give up
return window.setTimeout(check, ++tryes * interval);
}
var evaluate = function(){
return db.readyState === 'done' ? callback(!db.result) : wait(evaluate);
}
return wait(evaluate);
} catch (e) {
return callback(true);
}
}
if (!!window.navigator.userAgent.match(/(MSIE|Trident|Edge)/)){
try {
return callback(!window.indexedDB);
} catch (e) {
return callback(true);
}
}
try {
window.openDatabase(null, null, null, null);
return callback(false);
} catch (e) {
return callback(true);
}
}
isPrivate( function(isPrivate) {
console.log('Private mode ===>', isPrivate);
});
You can find this gist to detect private browsing
var hasStorage = function() {
var mod,
result;
try {
mod = new Date;
localStorage.setItem(mod, mod.toString());
result = localStorage.getItem(mod) === mod.toString();
localStorage.removeItem(mod);
return result;
} catch (_error) {
return false;
}
},
hasCookies = function() {
var cookieEnabled = navigator.cookieEnabled ? true : false;
if (typeof navigator.cookieEnabled == 'undefined' && !cookieEnabled) {
document.cookie = 'testcookie';
cookieEnabled = (document.cookie.indexOf('testcookie') != -1) ? true : false;
}
return cookieEnabled;
};
if (!hasStorage()) {
document.getElementById('apple_storage').style.display = 'block';
} else if (!hasCookies()) {
document.getElementById('no_cookie').style.display = 'block';
}
<!-- ERROR FOR BLOCKED LOCAL STORAGE -->
<div id="apple_storage" style="display:none;">
<div class="modal-new alerts">
<h2>Attenion</h2>
Close
<div class="body">
<p>
Dear customer, to ensure proper use of the site it is necessary to abandon the
private browsing.
</p>
</div><!-- /.body -->
</div>
</div>
<!-- ERROR FOR BLOCKED COOKIES -->
<div id="no_cookie" style="display:none;">
<div class="modal-new alerts">
<h2>Attenion</h2>
Close
<div class="body">
<p>
Dear customer, to ensure proper use of the site it is necessary to enable cookies.
</p>
</div><!-- /.body -->
</div>
</div>

Device browser detection

I have built a parallax intro for a clients site - due to the limited budget the animation will only work on higher end browsers, IOS and ie9.
Therefore I need to create a detection script in the sites homepage which will detect the following
IF:
ie9/ firefox / chrome/ safari - stay on current site
IOS - Go to IOS version
Android - Skip to main site
IE8 and below - skip to main site
I have carried out 'is mobile' detections in the past with PHP - but the above is pretty specific so I'm not sure how to approach it.. The main site is aspx, so I could make the animation page into a aspx page also and use server side detection, or look at Javascript/jquery options or plugins - or a combination of both..?
Can anyone recommend a good solution?
In hopes of not getting into browser detection / feauture detection argument blah blah blah, http://www.quirksmode.org/js/detect.html has a good script to handle this
Try with following code, uses the navigator object::
var ua = navigator.userAgent;
if(navigator.appName == "Netscape"){ //for Firefox, Safari and Chrome
//do nothing, stay on this page.
return;
}
else if(navigator.appName == 'Microsoft Internet Explorer'){
//check for version
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null){
version = parseFloat( RegExp.$1 );
}
if(version >= 9.0){
//do nothing, stay on this page.
return;
}
else{
//redirect to the site for lower IE versions.
}
}
else if(ua.match(/Android/i)){
//code for skipping to Android version
}
else if(ua.match(/iPhone/i)){
//code for skipping to iPhone version
}
else if(ua.match(/iPad/i)){
//code for skipping to iPad version
}
there is a JQuery object $.browser which could give you what you need in javascript here is the api call.
On the Server Side there is a .net Request.Browser object also here is the MSDN Api for it.

How can I detect if a browser is Safari 5+ using Javascript?

I need a method to detect that the browser is Safari 5 or higher - but the javascript should not rely on useragent since it can get overriden! Any ideas?
I have found PPK's browser detection code to be very reliable. It utilizes navigator.vendor and navigator.userAgent.
It's not possible to reliably detect the browser without accepting that the user agent can be modified by the end-user and / or the browser itself.
As a consequence of point 1. it is almost always best to use capabilities support detection (e.g. such as with Modernizr).
As there are times when you need to specifically detect a browser, such as disabling or enabling a particular capability that is misreported / not detectable, e.g. File Drag and Drop in Safari 5
As an example, the following code provides a function isFileDragAndDropSupported() which makes use of the isSafari5() function to return that File Drag and Drop is supported on Safari 5 even though window.FileReader is not defined in Safari 5.
function isSafari5() {
return !!navigator.userAgent.match(' Safari/') && !navigator.userAgent.match(' Chrom') && !!navigator.userAgent.match(' Version/5.');
};
function isFileAPIEnabled () {
return !!window.FileReader;
};
function isFileDragAndDropSupported() {
var isiOS = !!navigator.userAgent.match('iPhone OS') || !!navigator.userAgent.match('iPad');
return (Modernizr.draganddrop && !isiOS && (isFileAPIEnabled() || isSafari5()));
};
Note: Modernizr is required only for the isFileDragAndDropSupported() function. The isSafari5() function will work stand-alone.

What is the correct way to detect Opera using jQuery?

Amazon.com recently updated their javascript, and it's causing problems with some Opera browsers.
Their browser detection code looks like so, but it's faulty:
function sitbReaderIsCompatibleBrowser() {
if (typeof(jQuery) == 'undefined') {
return false;
} else {
var version = jQuery.browser.version || "0";
var splitVersion = version.split('.');
return (
(jQuery.browser.msie && splitVersion[0] >= 6) // IE 6 and higher
|| (jQuery.browser.mozilla && (
(splitVersion[0] == 1 && splitVersion[1] >= 8) // Firefox 2 and higher
|| (splitVersion[0] >= 2)
))
|| (jQuery.browser.safari && splitVersion[0] >= 500) // Safari 5 and higher
|| (jQuery.browser.opera && splitVersion[0] >= 9) // Opera 5 and higher
);
}
}
Nothing obviously wrong jumps out at me with this code, but I've never used jQuery before so I don't know.
Even though this code looks like it's attempting to let Opera users through, when I visit the page with Opera 9.64 I get an "unsupported browser" message. If I change Opera's settings to report itself as Firefox, the page works perfectly! With that in mind, I'm pretty sure it's a problem with the script and not the browser.
Any jQuery experts have a suggestion?
You can replicate the behavior by visiting any book on Amazon and clicking the "look inside this book" link.
Prior to jQuery 1.3, you could use jQuery.browser:
if( $.browser.opera ){
alert( "You're using Opera version "+$.browser.version+"!" );
}
From version 1.3, you should use jQuery.support instead.
Main reason for this is that should should avoid checking for browsers, as features may change from version to version, making your code obsolete in no time.
You should always try to use feature detection instead. This will allow you to see if current browser supports the feature you're trying to use, regardless the browser brand, version, etc.
There is a special window.opera object which is present in all Opera 5+ browsers. So something as simple as:
if (window.opera && window.opera.buildNumber) {
// we are in Opera
}
would be enough.
I check for Opera like this:
if (/Opera/.test (navigator.userAgent)) // do something
Why would you want jQuery?
It is much better to detect javascript capabilities rather than browser userAgent.
ie DOM, XmlHttpRequest, eventing model (event.target vs event.srcElement), ActiveX, Java etc
By focusing on the API functions that you will require, rather than a target browser you will create a more robust set of scripts, and inevitably less special casing.
This link here at opera will probably tell you more
A very simple way from Opera themselves:
if (window.opera) {
//this browser is Opera
}
Source: http://my.opera.com/community/openweb/idopera/
The main reason why Amazon fails on Opera is because the send different code from the server side already... If you visit the same page with Firefox and then save that page and reopen it in Opera it works fine...
But they promised to fix that sometime in January...
I think this way is the best
if ( window.opera.version() == 12) {
}
This example check if opera version is 12. Very useful when I have problems with font-face in Opera.
I don't know for sure ( i never really check for opera anyway) but if the built-in jQuery functionality doesn't detect opera, may be a bug with the jQuery which needs to be fixed. I would suspect if that's the case, it should get resolved fairly quickly.
In current HTML5 times, you can also check for browser features instead often.
if (!window.FormData) { alert("xmlhttprequest L2 FormData interface not available"); }

Categories

Resources