I'm developing an Android app with Phonegap. I need check if an internet connection is "true". If is false, show an alert, "else" redirect to website.
But not working, it seems that the app simply ignores this "script".
code:
<head>
<script>
var state = navigator.connection.type;
if (state == window.Connection.NONE)
{
alert("nao");
}
else
{
<meta http-equiv="refresh" content="0; url=http://website.com.br/abc" />
}
</script>
I use this function in my Android/Phonegap Application:
function CheckConnection() {
if(!navigator.network) {
navigator.network = window.top.navigator.network;
}
// return the type of connection found
return ( (navigator.network.connection.type === "none" || navigator.network.connection.type === null || navigator.network.connection.type === "unknown" ) ? false : true );
}
I want to point out that this may not be the most reliable. Also you don't want to confuse a slow connection with no connection so the timeout attribute must be set for a long period of time for slow connections. I also use jquery for the ajax request because the javascript would be a lot of code so make sure you have the jquery library on hand. First create a php file to make a request to (I'll call it test.php):
<?php
//test.php
echo 'request success';
?>
The initiator for the request (checks your internet connection):
Javascript/Jquery:
<script type="text/javascript">
$.ajax({
url: "test.php",
error: function(){
// will fire when timeout is reached
alert('no internet');
},
success: function(){
//do something
//success function do this if the request is a success
},
timeout: 30000 // sets timeout to 30 seconds remember you want it to be long to ensure that it isn't just a slow connection
});
</script>
Hope this helps and again it may not be the best way. I'd think that java might have a method/class to see about internet. I'd also think that you are using java since this appears to be an Android app--Correct? Tell me if this didn't work for you.
If you are working in cordova ver >= 3.0.0 then first you need to install Network Connection plugin using CLI(Command-Line Interface), which events added by org.apache.cordova.network-information
online
offline
cordova plugin add org.apache.cordova.network-information
$(document).ready(function() {
document.addEventListener("offline", onOffline, false);
document.addEventListener("online", onOnline, false);
});
function onOffline() {
// YOUR CODE FOR OFFLINE
}
function onOnline() {
// YOUR CODE FOR ONLINE
}
I see you are using an experimental API and that's why its not working.
As you are developing on PhoneGap then you have to add the corresponding plugin to retrieve network info.
cordova plugin add org.apache.cordova.network-information
check details and examples of this plugin here.
once you added the plugin, now to test network connection.
var state = navigator.network.connection.type;
if (state == navigator.network.connection.type)
{
alert("nao");
}
else
{
<meta http-equiv="refresh" content="0; url=http://website.com.br/abc" />
}
Related
I have installed a custom application in my system and I want to check..Is application is installed or registered in registry?
I want to perform some action based on that status but I am unable to detect or read registry from Browser. I have gone through sooo many question/solutions but they did not work for me.
If you can help me to achieve my wish...that would be really helpful for me.
When I trigger my custom URI then following Log prints in console based on
If Application installed then Launched external handler for 'myApp://dgsda'.
If Not Installed then Not allowed to launch 'myApp://dgsda' because a user gesture is required.
But I am unable to catch these logs.
I am sharing few approaches that I have tried.
Custom URI : myapp://anything
var timeout = setTimeout(function () {
window.location = newUri
}, 1000)
window.location = uri;
With Above approach Timeout is always executing
var iframe = document.querySelector('#hiddenIframeUriHandler')
if (!iframe) {
iframe = _createHiddenIframe(document.body, 'about:blank')
}
try {
iframe.contentWindow.location.href = uri;
successCb()
} catch (e) {
if (e.name === 'NS_ERROR_UNKNOWN_PROTOCOL') {
failCb()
}
}
Please do let me know if you need any further information.
I have created a custom URL protocol handler.
http://
mailto://
custom://
I have registered a WinForms application to respond accordingly. This all works great.
But I would like to be able to gracefully handle the case where the user doesn't have the custom URL protocol handler installed, yet.
In order to be able to do this I need to be able to detect the browser's registered protocol handlers, I would assume from JavaScript. But I have been unable to find a way to poll for the information. I am hoping to find a solution to this problem.
Thanks for any ideas you might be able to share.
This would be a very, very hacky way to do this... but would this work?
Put the link in as normal...
But attach an onclick handler to it, that sets a timer and adds an onblur handler for the window
(in theory) if the browser handles the link (application X) will load stealing the focus from the window...
If the onblur event fires, clear the timer...
Otherwise in 3-5seconds let your timeout fire... and notify the user "Hmm, looks like you don't have the Mega Uber Cool Application installed... would you like to install it now? (Ok) (Cancel)"
Far from bulletproof... but it might help?
There's no great cross-browser way to do this. In IE10+ on Win8+, a new msLaunchUri api enables you to launch a protocol, like so:
navigator.msLaunchUri('skype:123456',
function()
{
alert('success');
},
function()
{
alert('failed');
}
);
If the protocol is not installed, the failure callback will fire. Otherwise, the protocol will launch and the success callback will fire.
I discuss this topic a bit further here:
https://web.archive.org/web/20180308105244/https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
This topic is of recent (2021) interest; see https://github.com/fingerprintjs/external-protocol-flooding for discussion.
HTML5 defines Custom scheme and content handlers (to my knowledge Firefox is the only implementor so far), but unfortunately there is currently no way to check if a handler already exists—it has been proposed, but there was no follow-up. This seems like a critical feature to use custom handlers effectively and we as developers should bring attention to this issue in order to get it implemented.
There seems to be no straightforward way via javascript to detect the presence of an installed app that has registered a protocol handler.
In the iTunes model, Apple provides urls to their servers, which then provide pages that run some javascript:
http://ax.itunes.apple.com/detection/itmsCheck.js
So the iTunes installer apparently deploys plugins for the major browsers, whose presence can then be detected.
If your plugin is installed, then you can be reasonably sure that redirecting to your app-specific url will succeed.
What seams the most easy solution is to ask the user the first time.
Using a Javascript confirm dialog per example:
You need this software to be able to read this link. Did you install it ?
if yes: create a cookie to not ask next time; return false and the link applies
if false: window.location.href = '/downloadpage/'
If you have control of the program you're trying to run (the code), one way to see if the user was successful in running the application would be to:
Before trying to open the custom protocol, make an AJAX request to a server script that saves the user's intent in a database (for example, save the userid and what he wanted to do).
Try to open the program, and pass on the intent data.
Have the program make a request to the server to remove the database entry (using the intent data to find the correct row).
Make the javascript poll the server for a while to see if the database entry is gone. If the entry is gone, you'll know the user was successful in opening the application, otherwise the entry will remain (you can remove it later with cronjob).
I have not tried this method, just thought it.
I was able to finally get a cross-browser (Chrome 32, Firefox 27, IE 11, Safari 6) solution working with a combination of this and a super-simple Safari extension. Much of this solution has been mentioned in one way or another in this and this other question.
Here's the script:
function launchCustomProtocol(elem, url, callback) {
var iframe, myWindow, success = false;
if (Browser.name === "Internet Explorer") {
myWindow = window.open('', '', 'width=0,height=0');
myWindow.document.write("<iframe src='" + url + "'></iframe>");
setTimeout(function () {
try {
myWindow.location.href;
success = true;
} catch (ex) {
console.log(ex);
}
if (success) {
myWindow.setTimeout('window.close()', 100);
} else {
myWindow.close();
}
callback(success);
}, 100);
} else if (Browser.name === "Firefox") {
try {
iframe = $("<iframe />");
iframe.css({"display": "none"});
iframe.appendTo("body");
iframe[0].contentWindow.location.href = url;
success = true;
} catch (ex) {
success = false;
}
iframe.remove();
callback(success);
} else if (Browser.name === "Chrome") {
elem.css({"outline": 0});
elem.attr("tabindex", "1");
elem.focus();
elem.blur(function () {
success = true;
callback(true); // true
});
location.href = url;
setTimeout(function () {
elem.off('blur');
elem.removeAttr("tabindex");
if (!success) {
callback(false); // false
}
}, 1000);
} else if (Browser.name === "Safari") {
if (myappinstalledflag) {
location.href = url;
success = true;
} else {
success = false;
}
callback(success);
}
}
The Safari extension was easy to implement. It consisted of a single line of injection script:
myinject.js:
window.postMessage("myappinstalled", window.location.origin);
Then in the web page JavaScript, you need to first register the message event and set a flag if the message is received:
window.addEventListener('message', function (msg) {
if (msg.data === "myappinstalled") {
myappinstalledflag = true;
}
}, false);
This assumes the application which is associated with the custom protocol will manage the installation of the Safari extension.
In all cases, if the callback returns false, you know to inform the user that the application (i.e., it's custom protocol) is not installed.
You say you need to detect the browser's protocol handlers - do you really?
What if you did something like what happens when you download a file from sourceforge? Let's say you want to open myapp://something. Instead of simply creating a link to it, create a link to another HTML page accessed via HTTP. Then, on that page, say that you're attempting to open the application for them. If it doesn't work, they need to install your application, which they can do by clicking on the link you'll provide. If it does work, then you're all set.
This was a recommended approach for IE by Microsoft support
http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx#related_topics
"If you have some control over the binaries being installed on a user’s machine, checking the UA in script seems like a relevant approach:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform
" -- By M$ support
Every web page has access to the userAgent string and if you drop a custom post platform value, detecting this in javascript using navigator.userAgent is quite simple.
Fortunately, other major browsers like Firefox and Chrome (barring Safari :( ), do not throw "page not found" errors when a link with a custom protocol is clicked and the protocol is not installed on the users machine. IE is very unforgiving here, any trick to click in a invisible frame or trap javascript errors does not work and ends up with ugly "webpage cannot be displayed" error. The trick we use in our case is to inform users with browser specific images that clicking on the custom protocol link will open an application. And if they do not find the app opening up, they can click on an "install" page. In terms of XD this wprks way better than the ActiveX approach for IE.
For FF and Chrome, just go ahead and launch the custom protocol without any detection. Let the user tell you what he sees.
For Safari, :( no answers yet
I'm trying to do something similar and I just discovered a trick that works with Firefox. If you combine it with the trick for IE you can have one that works on both main browsers (I'm not sure if it works in Safari and I know it doesn't work in Chrome)
if (navigator.appName=="Microsoft Internet Explorer" && document.getElementById("testprotocollink").protocolLong=="Unknown Protocol") {
alert("No handler registered");
} else {
try {
window.location = "custom://stuff";
} catch(err) {
if (err.toString().search("NS_ERROR_UNKNOWN_PROTOCOL") != -1) {
alert("No handler registered");
}
}
}
In order for this to work you also need to have a hidden link somewhere on the page, like this:
<a id="testprotocollink" href="custom://testprotocol" style="display: none;">testprotocollink</a>
It's a bit hacky but it works. The Firefox version unfortunately still pops up the default alert that comes up when you try to visit a link with an unknown protocol, but it will run your code after the alert is dismissed.
You can try something like this:
function OpenCustomLink(link) {
var w = window.open(link, 'xyz', 'status=0,toolbar=0,menubar=0,height=0,width=0,top=-10,left=-10');
if(w == null) {
//Work Fine
}
else {
w.close();
if (confirm('You Need a Custom Program. Do you want to install?')) {
window.location = 'SetupCustomProtocol.exe'; //URL for installer
}
}
}
This is not a trivial task; one option might be to use signed code, which you could leverage to access the registry and/or filesystem (please note that this is a very expensive option). There is also no unified API or specification for code signing, so you would be required to generate specific code for each target browser. A support nightmare.
Also, I know that Steam, the gaming content delivery system, doesn't seem to have this problem solved either.
Here's another hacky answer that would require (hopefully light) modification to your application to 'phone home' on launch.
User clicks link, which attempts to launch the application. A unique
identifier is put in the link, so that it's passed to the
application when it launches. Web app shows a spinner or something of that nature.
Web page then starts checking for a
'application phone home' event from an app with this same unique ID.
When launched, your application does an HTTP post to your web app
with the unique identifier, to indicate presence.
Either the web page sees that the application launched, eventually, or moves on with a 'please download' page.
Hi, I created app in which i get data from some server i want to that if internet is not connected then user will not able to use app. I put
document.addEventListener("deviceready", function(){ onDeviseReady(); }, false);
function onDeviseReady()
{
document.addEventListener("offline", offLine, false);
}
function offLine()
{
navigator.notification.alert(
'No Internet Connected',message,'Message','Done');
}
Now what i should do in function message(){} so that the user not be able to move here until user connected to the internet
i put in alert box in message function but this is not i want
PREFACE
Your app needs Internet Connection to run, so you should check either the device is connected to the internet or not. For that you can create a utility function (say hasConnection) which returns boolean true on internet connection or boolean false on no internet connection.
The hasConnection Function
function hasConnection() {
var networkState = navigator.network.connection.type;
if(networkState === Connection.NONE) {
return false;
}
return true;
}
And depending on the hasConnction return value you can take the right decision.
SAMPLE EXAMPLE
document.addEventListener('deviceready',onDeviceReady, false);
function onDeviceReady(){
if(!hasConnection()){ //there is no internet connection
navigator.notification.alert(
'No Internet Connection!', // message
function(){
/*
If you are using jQuery mobile for UI you can create a seperate page #no-connection-page and display that page :
$.mobile.changePage('#no-connection-page',{'chageHash':false});
*/
}, // callback
'Connection Required', // title
'OK' // buttonName
);
return false;
} else {
//There is internet Connection, get the data from server and display it to the end user
//Again, If you are using jQuery mobile, display the page that should be displayed only when Internet Connection is available
//$.mobile.changePage('#has-connection-page');
}
/*
If the device is connected to the internet while your app is running,
you can add a listener for 'online' event and take some action. For example :
*/
document.addEventListener('online', function(){
//Now the device has internet connection
//You can display the '#has-connection-page' :
//$.mobile.changePage('#has-connection-page');
});
//You can use the listener for 'offline' event to track the app if the connection has gone while the app is running.
}
ONE NOTE
Make sure that you have :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
in android Manifest.
AT LAST
I am also creating android app using Phonepage / Cordova and jQuery-mobile that needs internet connection and using this approach, working fine for me. I hope it helps you.
The Facebook OAuth popup is throwing an error in Chrome on iOS only. Both developers.facebook.com and google have turned up nothing about this. Ideas?
You can use the redirection method as follow for this case (by detecting the user agent being chrome ios):
https://www.facebook.com/dialog/oauth?client_id={app-id}&redirect_uri={redirect-uri}
See more info here https://developers.facebook.com/docs/facebook-login/login-flow-for-web-no-jssdk/
Remark: I personnaly use the server OAuth in that case but this should do the trick and is quite simple
This is how I did it (fixing iOS chrome specifically)
// fix iOS Chrome
if( navigator.userAgent.match('CriOS') )
window.open('https://www.facebook.com/dialog/oauth?client_id='+appID+'&redirect_uri='+ document.location.href +'&scope=email,public_profile', '', null);
else
FB.login(null, {scope: 'email,public_profile'});
Here is a complete workaround for your FB JS Auth on Chrome iOS issue http://seanshadmand.com/2015/03/06/facebook-js-login-on-chrome-ios-workaround/
JS functions to check auth, open FB auth page manually and refresh auth tokens on original page once complete:
function openFBLoginDialogManually(){
// Open your auth window containing FB auth page
// with forward URL to your Opened Window handler page (below)
var redirect_uri = "&redirect_uri=" + ABSOLUTE_URI + "fbjscomplete";
var scope = "&scope=public_profile,email,user_friends";
var url = "https://www.facebook.com/dialog/oauth?client_id=" + FB_ID + redirect_uri + scope;
// notice the lack of other param in window.open
// for some reason the opener is set to null
// and the opened window can NOT reference it
// if params are passed. #Chrome iOS Bug
window.open(url);
}
function fbCompleteLogin(){
FB.getLoginStatus(function(response) {
// Calling this with the extra setting "true" forces
// a non-cached request and updates the FB cache.
// Since the auth login elsewhere validated the user
// this update will now asyncronously mark the user as authed
}, true);
}
function requireLogin(callback){
FB.getLoginStatus(function(response) {
if (response.status != "connected"){
showLogin();
}else{
checkAuth(response.authResponse.accessToken, response.authResponse.userID, function(success){
// Check FB tokens against your API to make sure user is valid
});
}
});
}
And the Opener Handler that FB auth forwards to and calls a refresh to the main page. Note the window.open in Chrome iOS has bugs too so call it correctly as noted above:
<html>
<head>
<script type="text/javascript">
function handleAuth(){
// once the window is open
window.opener.fbCompleteLogin();
window.close();
}
</script>
<body onload="handleAuth();">
<p>. . . </p>
</body>
</head>
</html>
My 2 cents on this as noone of the answers were clear to me. Im firing the login js dialog on a button click, so now when it's chrome ios I check first if the user it's logged into facebook and if not I send them to the login window. The problem with this is that chome ios users needs to click connect button twice if they are not logged into facebook. If they are logged into facebook one click is enough.
$( 'body' ).on( 'click', '.js-fbl', function( e ) {
e.preventDefault();
if( navigator.userAgent.match('CriOS') ) {
// alert users they will need to click again, don't use alert or popup will be blocked
$('<p class="fbl_error">MESSAGE HERE</p>').insertAfter( $(this));
FB.getLoginStatus( handleResponse );
} else {
// regular users simple login
try {
FB.login( handleResponse , {
scope: fbl.scopes,
return_scopes: true,
auth_type: 'rerequest'
});
} catch (err) {
$this.removeClass('fbl-loading');
}
}
});
That bit of code make it works for chrome ios users. On handle response I simple take care of fb response and send it to my website backend for login/register users.
var handleResponse = function( response ) {
var $form_obj = window.fbl_button.parents('.flp_wrapper').find('form') || false,
$redirect_to = $form_obj.find('input[name="redirect_to"]').val() || window.fbl_button.data('redirect');
/**
* If we get a successful authorization response we handle it
*/
if (response.status == 'connected') {
var fb_response = response;
/**
* Make an Ajax request to the "facebook_login" function
* passing the params: username, fb_id and email.
*
* #note Not all users have user names, but all have email
* #note Must set global to false to prevent gloabl ajax methods
*/
$.ajax({...});
} else {
//if in first click user is not logged into their facebook we then show the login window
window.fbl_button.removeClass('fbl-loading');
if( navigator.userAgent.match('CriOS') )
window.open('https://www.facebook.com/dialog/oauth?client_id=' + fbl.appId + '&redirect_uri=' + document.location.href + '&scope=email,public_profile', '', null);
}
};
Hope it helps!
Not a real answer but based on this thread worth noting that is started working for our app, on Chrome when on the iPhone we did General>Reset>Reset Location & Privacy
I got a solution for ios facebook website login in google chrome . Actually the issue was with google chrome in ios when we click on facebook login button it give internally null to the window.open in ios chrome .
There are two solution either to check it is chrome in ios(chrios) and then generate custom login screen ( still not chance that it will we correct ).
Second what i have used. Is to use facebook login from backhand create a api hit will populate facebook screen and then when login is done it will redirect to your server from where you will redirect to your website page with facebook data.
one other benefit of it is that you create 2 website for same website owner you can not set two website url in facebook developer account .In this way you can create many website facebook login with same facebook appid .
This is a very common issue which all developers have faced while implementing the FB login feature. I have tried most of the Internet solutions but none of them worked. Either window.opener do not work in Chrome iOS or sometime FB object is not loaded while using /dialog/oauth.
Finally I solved this by myself after trying all the hacks!
function loginWithFacebook()
{
if( navigator.userAgent.match('CriOS') )
{
var redirect_uri = document.location.href;
if(redirect_uri.indexOf('?') !== -1)
{
redirect_uri += '&back_from_fb=1';
}
else
{
redirect_uri += '?back_from_fb=1';
}
var url = 'https://www.facebook.com/dialog/oauth?client_id=[app-id]&redirect_uri='+redirect_uri+'&scope=email,public_profile';
var win = window.open(url, '_self');
}
else
{
FB.login(function(response)
{
checkLoginState();
},
{
scope:'public_profile,email,user_friends,user_photos'
});
}
}
Notice that above I'm passing an extra param to the redirect url so that once the new window opens with above redirect uri I could read the values and can say yes this call is from Chrome iOS window. Also make sure this code runs on page load.
if (document.URL.indexOf('back_from_fb=1') != -1 && document.URL.indexOf('code=') != -1)
{
pollingInterval = setInterval(function()
{
if(typeof FB != "undefined")
{
FB.getLoginStatus(function(response) {}, true);
checkLoginState();
}
else
{
alert("FB is not responding, Please try again!", function()
{
return true;
});
}
}, 1000);
}
I have created a custom URL protocol handler.
http://
mailto://
custom://
I have registered a WinForms application to respond accordingly. This all works great.
But I would like to be able to gracefully handle the case where the user doesn't have the custom URL protocol handler installed, yet.
In order to be able to do this I need to be able to detect the browser's registered protocol handlers, I would assume from JavaScript. But I have been unable to find a way to poll for the information. I am hoping to find a solution to this problem.
Thanks for any ideas you might be able to share.
This would be a very, very hacky way to do this... but would this work?
Put the link in as normal...
But attach an onclick handler to it, that sets a timer and adds an onblur handler for the window
(in theory) if the browser handles the link (application X) will load stealing the focus from the window...
If the onblur event fires, clear the timer...
Otherwise in 3-5seconds let your timeout fire... and notify the user "Hmm, looks like you don't have the Mega Uber Cool Application installed... would you like to install it now? (Ok) (Cancel)"
Far from bulletproof... but it might help?
There's no great cross-browser way to do this. In IE10+ on Win8+, a new msLaunchUri api enables you to launch a protocol, like so:
navigator.msLaunchUri('skype:123456',
function()
{
alert('success');
},
function()
{
alert('failed');
}
);
If the protocol is not installed, the failure callback will fire. Otherwise, the protocol will launch and the success callback will fire.
I discuss this topic a bit further here:
https://web.archive.org/web/20180308105244/https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
This topic is of recent (2021) interest; see https://github.com/fingerprintjs/external-protocol-flooding for discussion.
HTML5 defines Custom scheme and content handlers (to my knowledge Firefox is the only implementor so far), but unfortunately there is currently no way to check if a handler already exists—it has been proposed, but there was no follow-up. This seems like a critical feature to use custom handlers effectively and we as developers should bring attention to this issue in order to get it implemented.
There seems to be no straightforward way via javascript to detect the presence of an installed app that has registered a protocol handler.
In the iTunes model, Apple provides urls to their servers, which then provide pages that run some javascript:
http://ax.itunes.apple.com/detection/itmsCheck.js
So the iTunes installer apparently deploys plugins for the major browsers, whose presence can then be detected.
If your plugin is installed, then you can be reasonably sure that redirecting to your app-specific url will succeed.
What seams the most easy solution is to ask the user the first time.
Using a Javascript confirm dialog per example:
You need this software to be able to read this link. Did you install it ?
if yes: create a cookie to not ask next time; return false and the link applies
if false: window.location.href = '/downloadpage/'
If you have control of the program you're trying to run (the code), one way to see if the user was successful in running the application would be to:
Before trying to open the custom protocol, make an AJAX request to a server script that saves the user's intent in a database (for example, save the userid and what he wanted to do).
Try to open the program, and pass on the intent data.
Have the program make a request to the server to remove the database entry (using the intent data to find the correct row).
Make the javascript poll the server for a while to see if the database entry is gone. If the entry is gone, you'll know the user was successful in opening the application, otherwise the entry will remain (you can remove it later with cronjob).
I have not tried this method, just thought it.
I was able to finally get a cross-browser (Chrome 32, Firefox 27, IE 11, Safari 6) solution working with a combination of this and a super-simple Safari extension. Much of this solution has been mentioned in one way or another in this and this other question.
Here's the script:
function launchCustomProtocol(elem, url, callback) {
var iframe, myWindow, success = false;
if (Browser.name === "Internet Explorer") {
myWindow = window.open('', '', 'width=0,height=0');
myWindow.document.write("<iframe src='" + url + "'></iframe>");
setTimeout(function () {
try {
myWindow.location.href;
success = true;
} catch (ex) {
console.log(ex);
}
if (success) {
myWindow.setTimeout('window.close()', 100);
} else {
myWindow.close();
}
callback(success);
}, 100);
} else if (Browser.name === "Firefox") {
try {
iframe = $("<iframe />");
iframe.css({"display": "none"});
iframe.appendTo("body");
iframe[0].contentWindow.location.href = url;
success = true;
} catch (ex) {
success = false;
}
iframe.remove();
callback(success);
} else if (Browser.name === "Chrome") {
elem.css({"outline": 0});
elem.attr("tabindex", "1");
elem.focus();
elem.blur(function () {
success = true;
callback(true); // true
});
location.href = url;
setTimeout(function () {
elem.off('blur');
elem.removeAttr("tabindex");
if (!success) {
callback(false); // false
}
}, 1000);
} else if (Browser.name === "Safari") {
if (myappinstalledflag) {
location.href = url;
success = true;
} else {
success = false;
}
callback(success);
}
}
The Safari extension was easy to implement. It consisted of a single line of injection script:
myinject.js:
window.postMessage("myappinstalled", window.location.origin);
Then in the web page JavaScript, you need to first register the message event and set a flag if the message is received:
window.addEventListener('message', function (msg) {
if (msg.data === "myappinstalled") {
myappinstalledflag = true;
}
}, false);
This assumes the application which is associated with the custom protocol will manage the installation of the Safari extension.
In all cases, if the callback returns false, you know to inform the user that the application (i.e., it's custom protocol) is not installed.
You say you need to detect the browser's protocol handlers - do you really?
What if you did something like what happens when you download a file from sourceforge? Let's say you want to open myapp://something. Instead of simply creating a link to it, create a link to another HTML page accessed via HTTP. Then, on that page, say that you're attempting to open the application for them. If it doesn't work, they need to install your application, which they can do by clicking on the link you'll provide. If it does work, then you're all set.
This was a recommended approach for IE by Microsoft support
http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx#related_topics
"If you have some control over the binaries being installed on a user’s machine, checking the UA in script seems like a relevant approach:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform
" -- By M$ support
Every web page has access to the userAgent string and if you drop a custom post platform value, detecting this in javascript using navigator.userAgent is quite simple.
Fortunately, other major browsers like Firefox and Chrome (barring Safari :( ), do not throw "page not found" errors when a link with a custom protocol is clicked and the protocol is not installed on the users machine. IE is very unforgiving here, any trick to click in a invisible frame or trap javascript errors does not work and ends up with ugly "webpage cannot be displayed" error. The trick we use in our case is to inform users with browser specific images that clicking on the custom protocol link will open an application. And if they do not find the app opening up, they can click on an "install" page. In terms of XD this wprks way better than the ActiveX approach for IE.
For FF and Chrome, just go ahead and launch the custom protocol without any detection. Let the user tell you what he sees.
For Safari, :( no answers yet
I'm trying to do something similar and I just discovered a trick that works with Firefox. If you combine it with the trick for IE you can have one that works on both main browsers (I'm not sure if it works in Safari and I know it doesn't work in Chrome)
if (navigator.appName=="Microsoft Internet Explorer" && document.getElementById("testprotocollink").protocolLong=="Unknown Protocol") {
alert("No handler registered");
} else {
try {
window.location = "custom://stuff";
} catch(err) {
if (err.toString().search("NS_ERROR_UNKNOWN_PROTOCOL") != -1) {
alert("No handler registered");
}
}
}
In order for this to work you also need to have a hidden link somewhere on the page, like this:
<a id="testprotocollink" href="custom://testprotocol" style="display: none;">testprotocollink</a>
It's a bit hacky but it works. The Firefox version unfortunately still pops up the default alert that comes up when you try to visit a link with an unknown protocol, but it will run your code after the alert is dismissed.
You can try something like this:
function OpenCustomLink(link) {
var w = window.open(link, 'xyz', 'status=0,toolbar=0,menubar=0,height=0,width=0,top=-10,left=-10');
if(w == null) {
//Work Fine
}
else {
w.close();
if (confirm('You Need a Custom Program. Do you want to install?')) {
window.location = 'SetupCustomProtocol.exe'; //URL for installer
}
}
}
This is not a trivial task; one option might be to use signed code, which you could leverage to access the registry and/or filesystem (please note that this is a very expensive option). There is also no unified API or specification for code signing, so you would be required to generate specific code for each target browser. A support nightmare.
Also, I know that Steam, the gaming content delivery system, doesn't seem to have this problem solved either.
Here's another hacky answer that would require (hopefully light) modification to your application to 'phone home' on launch.
User clicks link, which attempts to launch the application. A unique
identifier is put in the link, so that it's passed to the
application when it launches. Web app shows a spinner or something of that nature.
Web page then starts checking for a
'application phone home' event from an app with this same unique ID.
When launched, your application does an HTTP post to your web app
with the unique identifier, to indicate presence.
Either the web page sees that the application launched, eventually, or moves on with a 'please download' page.