URLスキーム:Javascriptでインストールされたアプリケーションを確認する

最近、URLスキームがブラウザに登録されているかどうかを判断する必要に直面しました。その結果、結果に応じて、アプリケーションのダウンロードボタンまたはそれを起動するダイレクトURLを表示します。



これには標準的なメカニズムがないことが判明しました。 しかし、ユーザーは[ダウンロード]ボタンとアプリケーションのプレインストールの必要性に関する赤いテキストに注意を払うことを望まなかったため、オプションを探す必要がありました。 これについては以下で説明します。







少なくとも2つのブラウザーで同じように安定して動作する単一の方法はなかったことをすぐに警告します。 したがって、美しいクロスブラウザソリューションのファンは失望します-この記事はハッキングでいっぱいです(マイナスしないでください、それはあなた自身に不快感を与えますが、タスクはタスクです)。



まず、リンクを作成します。



<a class="runlink" href="myapp://command_line_parameters">Run</a> <a class="downloadlink" style="display:none;" href="http://mysite.com/download/app.exe">Download</a>
      
      







ここで、ブラウザを決定し、適切なハンドラーを実行する一般的な関数を作成します。 さて、もう1つ、アプリケーションのダウンロード要求を表示し、答えが「はい」の場合にアプリケーションをロードします。



 function initApplicationLink(runlink, downloadlink) { //   var func = null; if (navigator.userAgent.indexOf('Firefox')>=0 ) func = checkFirefox; else if (navigator.userAgent.indexOf('Opera')>=0 ) func = checkOpera; else if (navigator.userAgent.indexOf('Chrome')>=0 ) func = checkChrome; else if (navigator.userAgent.indexOf('Safari')>=0 ) func = checkSafari; if ( func!=null ) { //   Download $(downloadlink).hide(); //          $(runlink).on('click', function(){ func(runlink, downloadlink); //   ,        return false; }); } else { //        Download $(downloadlink).show(); } } function downloadConfirmation(downloadlink) { if ( confirm('You need to install our application first. Do you really want to download it now?') ) document.location = $(downloadlink).attr('href'); }
      
      







FirefoxとOperaから始めましょう。これらは、この点で100%信頼できる美しい例外メカニズムを提供します。 しかし、残念ながら、実装はまだ異なります。



Firefoxには最も簡単なソリューションがあります。



 function checkFirefox(runlink, downloadlink) { //   ,      URL var f = createFrame(); try { f.contentWindow.location = $(runlink).attr('href'); } catch (e) { //  URL   ,      downloadConfirmation(downloadlink); } //     deleteFrame(f); }
      
      







Operaは、未登録プロトコルのURLをフレームにロードしようとしたときに例外をキャッチせず、未定義のフレーム属性(contentWindow.location)にアクセスしようとした場合を除いて、Firefoxと大差ありません。



 function checkOpera(runlink, downloadlink) { var f = createFrame(); f.contentWindow.location = $(runlink).attr('href'); setTimeout(function (){ try { //        // ( something   -) if ( f.contentWindow.location!='something' ) {} } catch (e) { downloadConfirmation(downloadlink); } deleteFrame(f); }, 0); }
      
      







FirefoxおよびOperaのcreateFrame()およびdeleteFrame()関数:



 function createFrame() { var f = document.createElement('iframe'); f.style.display = 'none'; return document.body.appendChild(f); } function deleteFrame(f) { document.body.removeChild(f); }
      
      







WindowsのSafariも例外をキャッチしますが、隠しフレームではこの数値は機能しませんでした。 または、通常のウィンドウを使用できます。 ソリューションはエレガントではありませんが、機能しています。



MacOS上のSafariの例外は、明らかに友好的ではありません。 したがって、純粋に松葉杖の方法を適用する必要があります。 秘Theは、アプリケーションを起動した後、ブラウザーウィンドウのフォーカスを確認することです。 アプリケーションが正常に起動した場合、ウィンドウはフォーカスを失い、このイベントのハンドラーでこの事実を記録しました。 アプリケーションが開かない場合、ウィンドウにフォーカスがあります。



残念ながら、この方法は100%安定していません。 たとえば、タイムアウト中にブラウザがアプリケーションを開くことができなかった場合、またはその逆の場合、ユーザーはタイムアウトが発生する前にアプリケーションを閉じ、ウィンドウが再びフォーカスを取得しました。 その結果、このようなオプションは次のような不愉快な結果をもたらします。 ダウンロードするように求めるウィンドウがポップアップ表示され、1秒後にアプリケーションが起動します。 またはその逆-アプリケーションが起動し、ユーザーがすぐにそれを閉じ、ダウンロードの提案を含むウィンドウが表示されます。 したがって、タイムアウトの増減はほぼ同様に悪いです(ほとんどの場合、ユーザーは新しく開かれたアプリケーションをすぐに閉じないので、増加はまだわずかに良いです)。 実際には、1秒のタイムアウトが最も受け入れられます。



 function checkSafari(runlink, downloadlink) { if ( navigator.userAgent.indexOf('Windows')>=0 ) { //        URL var w = window.open($(runlink).attr('href'), '', 'width=50, height=50'); setTimeout(function(){ try { //        if ( w.location!='about:blank' ) {} w.close(); window.focus(); } catch (e) { w.close(); window.focus(); downloadConfirmation(downloadlink); } }, 1000); } else { //  MacOS    iOS document.location = $(runlink).attr('href'); setTimeout(function(){ //   -  ,     if ( window.isFocused ) downloadConfirmation(downloadlink); }, 1000); } } //         window.isFocused = true; $(window).on('focus', function(){ window.isFocused = true; }) .on('blur', function(){ window.isFocused = false; });
      
      







Chromeは、タイムアウトを除いて、MacOSでSafariと完全に互換性があることが判明しました(Safariはアプリケーションの起動にほぼ1秒かかりましたが、Chromeは250ミリ秒未満で起動しました)。



(実際には、タイムアウト方法は、アプリケーションの起動時のコンピューターの負荷に大きく依存します。アプリケーションが起動しなかった場合、ChromeとSafariで状況が発生し、ダウンロードに関する提案のウィンドウが表示され、その後アプリケーションが起動しました。上記のタイムアウト)。



 function checkChrome(runlink, downloadlink) { document.location = $(runlink).attr('href'); setTimeout(function(){ if ( window.isFocused ) downloadConfirmation(downloadlink); }, 1000); }
      
      







そして最後に、Internet Explorerはすべての努力で安定した結果を示しませんでした。 Safari for Windowsは技術的にはIEに適しています(小さなウィンドウを開く場合)。 しかし、少なくとも50%の安定性を得ることはできませんでした。 そのため、IEは「その他のブラウザ」ブランチに移動しました。このブランチでは、チェックは行われず、両方のリンクが表示されるだけで、アプリケーションが起動およびダウンロードされます。 (誰かがIEの方法を提案してくれたら感謝します)。



ここで、リンクを初期化するだけです。



 initApplicationLink('.runlink', '.downloadlink');
      
      







注:このソリューションは、WindowsおよびMacOSプラットフォーム上のChrome、Firefox、Opera、Safari、およびIEの最新バージョンでテストされています。 モバイルブラウザでのテストはありませんでしたが、タイムアウトオプションはAndroidおよびiOSで動作することが証明されています。



All Articles