如果客戶提出一個需求要在網頁打開計算器,你可千萬別以為是很簡單的事,事實上,如果不借助“外力”是根本辦不到。
背景
某項目客戶提了這么一個需求
總結下就是能在任意瀏覽器中打開任意瀏覽器,乍聽之下覺得很扯是不是,覺得是個傻逼需求是不是,事實上,我的第一反應也是這樣的,但了解事情背景后發現這是個很合理的需求,背景是客戶有幾個個遺留的老系統,其中核心業務系統只能運行在IE上,某BI系統只能運行在firefox上,你可能覺得很奇怪,只支持IE這個可以理解,只支持firefox這個有點匪夷所思,但事實確實如此,我們也不必去深究,現在客戶要做門戶,需要在門戶上單點到所有系統,那么就有了上面的需求。
沙盒模型
想象一下如果能讀寫本地文件會發生什么事
這里的不是指運行在server端的nodejs ,指的是運行在網頁端的
如果真的是這樣,那么互聯網也不可能存在這么久,因為網站是公開的,任何人可以訪問的,你的手機電腦是私人的,私密的,你不能讓一個公開性質的網站去訪問你私人的設備,但我們經常聽說不要隨便打開某某網頁,小心中毒是什么回事呢,打開網頁不會中毒,但網頁會引導甚至自動下載病毒然后誘導你去運行病毒,比如某度全家桶,運行后導致電腦中毒,也就是說就算你瀏覽不良網站,只要不手賤去下載來歷不明的程序就不會有問題。
那么保證瀏覽器不做壞事的核心就是沙盒模型理念(sandbox)也稱沙箱,沙盒模型規定
簡單說就是,不能讀,不能寫,不能看。在電影中,楚門所在的那個小鎮就是一個沙盒,楚門無法接觸外面的世界,他感覺不到他的世界是虛假的。有了沙盒模型,我們才能愉快的上網沖浪,享受互聯網帶來的便利。
如何打開本地程序
那么你可能會問,那為什么網頁可以打開迅雷,打開qq這些程序呢,以迅雷為例,當我們在網頁上點擊迅雷下載時系統會打開本地迅雷程序進行下載,這個是怎么辦到的呢,如果仔細觀察就會發現迅雷的下載地址比較特殊
thunder://QUFodHRwOi8veDEwOC55c2JpcmQuY29tOjEwNy9kYXRhL3d3dy55c2JpcmQuY29t07DK08TxL7jWzPrPwC1CbHUlNUIxMjgweDcyMCU1RC5ybXZiWlo=
他不是我們常見的http協議,協議名是thunder,這個就是一個自定義協議,當操作系統配置了自定義協議和應用程序的關聯關系后,瀏覽器就能根據這個配置打開相應的程序,在windows中,這個配置關系是在注冊表中配置的,開篇提到的需要借助外力才能實現瀏覽器打開本地程序指得就是這個,下面就是迅雷thunder協議在注冊表中的配置
注冊表配置
比如我們需要實現在chrome中打開ie,我們規定協議ie://,只需按照步驟配置注冊表即可
編寫html代碼
打開IE
瀏覽器點擊后彈出窗口,點擊打開就可以打開IE
當然你也可以將以下腳本保存為reg后綴的文件,直接點擊就可以導入注冊表,效果和你手動配置的是一樣的
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\ie]
"URL Protocol"=""
@="iexplore"
[HKEY_CLASSES_ROOT\ie\shell]
[HKEY_CLASSES_ROOT\ie\shell\open]
[HKEY_CLASSES_ROOT\ie\shell\open\command]
@="iexplore"
如果你在windows控制臺輸入start 就能打開ie,同樣,start firefox打開火狐,start chrome打開chrome,star命令能夠在指定文件夾搜索應用程序匹配并打開,可以參考這里
那這樣是不是就解決了客戶的需求了,我們只需配幾個自定義協議就可以了,答案是不可以,因為這種方式無法指定打開的url,雖然可以通過ie://指定參數,但是ie會打開原始地址,也就是ie://而不是,所以我們需要編寫一個中間程序完成解析url打開指定應用。
開發應用
因為是windows應用,而且是需要安裝在客戶電腦上,所以java就不用考慮了,有以下選型
console會彈出一個黑窗,體驗不好,.NET對運行環境有要求,很難做到兼容,所以考慮用C語言開發windows GUI程序,功能很簡單,就是解析url打開指定應用,既然是開發windows c,那么就要祭出上古神器vc++6.0
看到這熟悉又親切的啟動畫面,我忍不住發了條朋友圈,祭奠那死去的青春。核心代碼如下
#include "stdafx.h"
#include "resource.h"
#include "Windows.h"

#include "shellapi.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow) {
if(lpCmdLine==NULL||strlen(lpCmdLine)==0) {
MessageBox(NULL, "無法打開應用程序 原因:缺少參數", "提示", 0);
return 0;
}
lpCmdLine=lpCmdLine+7;
lpCmdLine[strlen(lpCmdLine)-1]='\0';
char *p = strchr(lpCmdLine, ':');
int size=p-lpCmdLine;
char protocal[30];
memcpy(protocal,lpCmdLine,size);
protocal[size]='\0';
char url[1000];
memset(url,'\0',1000);
strcpy(url,p+1);
int ret=(int)ShellExecute(NULL, "open", protocal, url, NULL, SW_MAXIMIZE);
if(ret<32) {
if(ret==2) {
MessageBox(NULL, strcat("啟動失敗沒有安裝",protocal), "提示", 0);
} else {
MessageBox(NULL, "啟動失敗未知原因請聯系管理員", "提示", 0);
}
}
return 0;
}
代碼做了以下內容
打包應用
應用開發好了,但如何交付到客戶手上,不可能讓每個客戶都去配置下注冊表,我們需要一個安裝包,客戶點擊下一步就能完成所有安裝工作的安裝包,強烈推薦這個安裝包制作工具,我到現在才知道原來安裝程序是用工具做出來的,我以為都是自己寫的,可以制作一個安裝程序,引導用戶完成安裝,功能很強大,其中包括了讀寫注冊表功能
command后面默認值為[APPDIR]sso.exe "%1",APPDIR表示安裝路徑,名稱放空就會創建一個Default的value
還需要在sso下創建一個URL 的值
測試
編寫以下html用于測試
瀏覽器測試
<script src="protocolcheck.js"></script>
<script type="text/javascript">
function check() {
window.protocolCheck("sso://",
function () {
let msg = confirm("未安裝相關工具,點擊確定下載安裝")
if (msg) {
window.open("http://zhengjianfeng.cn/sso/ssoclient.msi", "_blank");
}
});
}
</script>
瀏覽器測試
其中check是檢測是否配置了自定義協議,其中.js是檢測自定義協議工具包,可以從這里下載
*請認真填寫需求信息,我們會在24小時內與您取得聯系。