突破Android微信微博瀏覽器限制直接拉起應

想飛的魚發表於2017-08-19

前言
眾所周知,微信微博等應用為了防止使用者在使用過程當中跳出程式本身,對瀏覽器裡面的自定義協議開啟做了限制。這個需求很正常,是個產品經理都能想到。

但作為微博微信這種體量的應用來說,我要多說幾句:“右上角使用瀏覽器開啟”成了每個前端開發者的標配,可以說浪費了多少的人力和財力,亦可以說造就了多少的就業機會。APP做得越大,越應該有社會責任感。這種簡單粗暴的方式讓千千萬萬的開發者感到心痛,無語。請把選擇權交還給使用者,既然使用者點開了瀏覽器,我們也理解你們為自己APP操碎了心,是否可以做成彈框再讓使用者選擇:是否開啟xx應用?

現狀
H5頁面增加自定義協議拉起APP在移動端來講是個非常特色的互動,而且也可以極大提高使用者體驗,基本是每個應用的標配。通過

<a href="orpheus://playlist/19850925" />

就可以在點選的時候觸發拉起應用(前提是系統已經安裝支援這個協議的應用,這個例子裡面叫orpheus。

微信微博瀏覽器如何封禁自定義協議呢?

public boolean shouldOverrideUrlLoading(WebView view, String url) 

Android的WebView控制元件有個叫shouldOverrideUrlLoading的回撥,任何連結的開啟(包括http和各種自定義協議)都會先走這個回撥,交給應用本身來判斷是否要接手處理,return true表示接手,WebView就不再處理,否則WebView就繼續處理。
處理自定義協議其實不是WebView自帶的功能,而是需要開發者在這個回撥裡面去實現。比如類似這樣:

Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

那微信微博與其說攔截,倒不如說他們只判斷了自己白名單的協議然後放行。

方法
除了苦逼的前端開發者實現個右上角用瀏覽器開啟功能,還有一些思路可以參考。
1.偽裝成白名單協議
我們知道微信有白名單,比如合作的京東就可以直接開啟,所以我們可以把我們的應用做成京東的協議名稱,這樣如果使用者手機上面沒有安裝京東,就能直接拉起你的應用。如果安裝了京東,則會跳出彈框讓使用者選用哪個開啟(這個是系統行為)。這個方案有點猥瑣。
2.用右上角瀏覽器開啟的時候可以把自己應用置頂。我們知道右上角用瀏覽器開啟其實也是微信呼叫了上述那段程式碼,只不過協議固定是http或者https。當然微信還是做過修改的,第一個位置固定放QQ瀏覽器(即使沒有安裝)。除了第一個位置剩餘是按系統讀取的順序排列的。因為Intent其實是有優先順序的,那如何利用系統Intent優先順序來讓自己的應用在這個彈框裡面排在第二位呢?

首先應用當然要實現支援http/https協議,不然你都不會出現在這個頁面裡面。然後給Intent配置域名資訊,如下:
這樣在自己域名匹配上面排列就會靠前。甚至你可以在這個協議實現上面,直接將http/https的url轉換成native引數,直接開啟native頁面,省去中間webview跳轉。
如果url轉成native引數有點麻煩,你可以在分享連結的時候帶上Intent.toUri作為引數,這樣後續收到url之後直接Intent.parseUri得到Intent,跳轉到指定頁面就簡單了。當然這種做法有限制,比如引數不能缺失,也不能支援其他平臺分享過來的連結。如果應用的不同平臺能統一跳轉協議也是很不錯的。

突破
還能再做點什麼嗎?答案是肯定的。這個突破不是絕對的,而必須要求程式在後臺有個活著的程式。如果你感興趣請繼續往下看。

首先我們知道系統的很多彈框都是用Activity實現的,他可以彈出在任何應用的任意一個介面上面,說到底這個彈框也是屬於系統的某個應用,比如手機管家等等。那為什麼一個APP在後臺能啟動的一個Activity可以在任意另外一個APP上面呢?
祕密就在於Intent.FLAG_ACTIVITY_NEW_TASK這個flag,我們知道如果context.startActivity裡面的context不是Activity,是必須要加這個flag才能啟動成功。
第一個問題解決了,在android上面是有可能讓我們的一個頁面呈現在微信之上。那如何觸發呼叫呢?聰明的你可能想到了,對,就是在H5頁面上面給自己應用發請求。
在自己應用裡面實現一個非常簡單的HttpServer,接聽來自本機的請求,一旦收到請求則直接使用Intent.FLAG_ACTIVITY_NEW_TASK拉起Activity。

可惜是當你去嘗試在H5頁面裡面給127.0.0.1或者localhost發請求的時候發現根本收不到,因為狡猾的微信微博瀏覽器限制了這兩個本機地址,限制方式也很簡單,還是剛才的shouldOverrideUrlLoading判斷下url的host是不是這2個就可以了。於是聰明的你肯定又想到了繞過的方式。沒錯隨便弄個域名解析到127.0.0.1上面。

於是整個鏈路快要完成了,剩下就是一些額外的工作,比如客戶端和H5頁面約定一串埠,按照約定順序依次遍歷直到請求得到響應。因為埠有可能被佔用。然後再約定一個加解密方式以防止被惡意攻擊。

這種方式有沒有可能被微信微博封禁呢?因為原理都是系統實現,唯一的可能點就是對域名進行解析發現還是127.0.0.1的話繼續攔截。但這個做法有點代價,首先shouldOverrideUrlLoading不能阻塞呼叫,這樣就影響正常使用了。如果做成非同步的就需要新增一個dns查詢服務,這個完全看xx產品經理的意思。可能原來不會考慮,這篇文章發出去了用的人多了估計會考慮了。。。請給開發者留一條活路。

寫到這裡我猜你肯定在想,程式活著這個條件是個硬傷,雖然多邁出了一步但還是受限不少。於是又引出了一個古老的話題:如何程式保活。這不是本篇文章的範疇,我也不推薦你去研究和花費心思,這也不是一個正確的方向。
最後給一個提示:你的公司有沒有兄弟產品,亦或是有沒有使用一個公共的SDK呢?

更多細節請參考我給的例子,點選這裡連結可以參看。有任何問題歡迎留言討論,喜歡就點贊,請支援原創。

更多文章請關注微信公眾號:安卓之美

相關文章