------------恢復內容開始------------
url protocol技術能夠使得應用程序可以通過一個自定義協議的url link啟動。
以下所描述的操作,均基於實用QT框架開發跨平台的應用時遇到的問題及解決辦法。
一.windows下:
1.可以在軟件安裝或者軟件第一次本地運行的時候寫注冊表項。舉個通過bat文件注冊表例子:
大概解釋一下,這個腳本的功能是通過生成一個臨時的atsexam.reg注冊表文件,然后通過regedit進行注冊。
在程序安裝的時候可以執行這個腳本,將程序的一些關鍵信息寫入注冊表,可以看到該程序啟動時可以帶一個參數(%1)。
后續就是在主程序int main(int agrc,char* argv[])中獲取這個參數,並根據參數做處理了。
二.Mac 下:
1.如果不需要傳遞參數的話,比較簡單,直接打開生成的app包(右鍵,查看包內容,打開Contents),編輯Info.plist文件,增加Url types項,給Url types的Item0增加一個URL Scheme節點,並賦予自定義的協議值。關於增加這個節點可以通過Xcode,也可以直接編輯info.plist文件,這個文件是個xml格式文件,但是每個節點的標簽記起來比較繁瑣,沒有通過XCode來的快。
2.如果需要傳遞參數的話,比較復雜,沒辦法像Windows下,通過注冊表中啟動程序路徑后面增加一個 %1,就可以把通過url啟動時的url傳遞給應用程序處理。但通過查閱網上的資料,知道的大概有三種辦法:
a) 原生開發:
因為不是專門搞Mac開發的,所以不懂,但把鏈接放在這,可以參考:https://stackoverflow.com/questions/6561661/url-scheme-qt-and-mac/6699518#6699518
b)使用QT的eventfilter:
QT的eventfilter,顧名思義就是事件過濾器。可以接受來自系統的事件,當一個與app相關的鏈接被打開時,會觸發一個FileOPen類型的事件,所以可以通過過濾這個事件來獲取傳遞給app的參數了,對於通過url protocol打開應用程序時,這個url就會被傳遞給app。然后再程序中就可以處理了。
eventfilter的用法大致如下:
1)定義一個類繼承QObject,並override類的eventfilter方法,並定義一個signals,當檢測到該參數時,向外傳遞;
2)在該方法中過濾QEvent::FileOpen類型的事件,當檢測到該種事件時,可以通過獲取event的url內容來獲取到需要傳遞給app的參數;
3)發送signals,將參數傳遞出去;
4)在main函數中,為application對象安裝事件過濾器,通過調用installeventfilter安裝。並通過QObject::connect()方法將事件過濾器中發送出來的信號鏈接到槽函數上(一般可以使用lambda表達式)。
5)在槽函數中處理參數解析邏輯。
具體的代碼,網上可以找到,就不再貼了,如果是簡單的程序邏輯,可以通過這種辦法搞定。
但是有一個現象需要注意就是:如果我們想通過傳遞的參數來決定程序的啟動狀態時(比如:當判斷到參數不合理時不啟動程序,當參數不同時啟動不同的頁面?),可能做不到這一點,因為很大概率上,我們接收到信號的時候,程序的初始化已經完畢了,這與我們的邏輯不符。如何解決呢?可以大致想到如下幾種解決辦法:
i) 定義一個全局變量,主程序初始化時,如果需要通過接受的參數來初始化,那我們就等待該全局變量置位,看着很理想,但是已測試發現,行不通,如果我們的主進程在還沒有接收到置位信號時就來到等待狀態,那么程序很大概率就會一直處於等待狀態了。也就是因為進程被掛起所以也收不到event了,收不到event了,所以也沒法過濾了,沒法過濾了,所以也就沒辦法得到參數了。貌似就是死循環了,可見行不通。
ii)再i)的基礎上寫一個定時器,不再主進程等待,而是去定時器等待,主線程繼續能接受事件,這種思路看着可行,但是程序的響應啊,以及把主界面的一些邏輯甚至窗體初始化放到了另一個線程中構建,可能會引入其他的問題,考慮到此,也就並沒有嘗試。
iii)再寫一個app,由這個app來響應url protocol。在該app中按照上述注冊這些事件過濾器,當過濾到該事件后,可以通過啟動一個process來啟動真正的應用程序,通過process啟動的程序,可以將參數傳遞進去。此處的邏輯便與windows相一致了。這個輔助的app可以寫一個定時器,稍微等待一段時間就自己退出即可。通過測試,這種辦法是可行的,但是記得這個process是通過startdetached啟動的,這樣就可以與輔助app無關啦,代碼如下:
但是這個有個問題就是你需要兩個app,這兩個app都附帶有QT相關的庫,比較重。還有個小問題就是:你會發現通過url protocol啟動的時候會有2個圖標顯示在dock里,看着很別扭,有沒有辦法能做的像只啟動一個app呢,辦法當然是有的,很簡單:
打開輔助的app包的info.plist文件。增加一個項,application is agent,並將其設置為YES即可。如此便只會顯示一個app圖標了,搞定。
c) 使用apple script(重點):
既然都有了上述辦法,按理說我們的問題可以解決了,但是還是不夠完美,因為這個包比較大,如果不做一個QT依賴的排除的話,應用程序包太大比友好。所以就有了重點解決方法:使用applescript,具體applescript的使用可以參考相關手冊,我沒有深入研究,但是看他的語法,感覺特別口語化。那具體怎么做呢?
先說一下大致思路:將編寫的apple script保存為app bundle格式,就是.app。這個腳本的內容后面描述,我們先看里頭,里頭也會存在info.plist文件,根據上面的研究,我們重點設置兩項內容:Url types和application is agent,如何設置可以參考上面。
腳本的內容很簡單,如下所示:
on open location this_URL return do shell script "open -b 'ff.youreappidentify' --args" & space & quoted form of this_URL end open location
你只需要替換ff.youreappidentify為你的目標app的identify即可。這個identify怎么看呢,是在info.plist里頭,可以自己找找看,當然這項內容是可以更改的。
最后可以將這個app放到我們的目標app的目錄里即可。這樣通過url protocol 我們可以打開applescript,進兒applescript打開我們的app。形成一個打開鏈條,即只有一個圖標,也比較輕量。
但是需要主要,不過是url types還是identify都需要被移動一次,才能被系統監測到,不然調用的過程中可能沒反應。不過這種現象可能只存在與開發機上,用戶的電腦上,如果要用程序,至少存在一次拷貝,所以問題不大。
很可能第一種辦法是最好的,但是奈何沒做過Mac下的開發,不懂。不知道像chrome,zoom這些軟件在Mac上是如何實現的?
------------恢復內容結束------------