讓那些煩人的廣告,滾出我們的APP!
1-現像
最近越來越多的使用者向客服反映,在使用我們的App過程中,會莫名其妙的在底部出現廣告,甚至黃色資訊。這些資訊不但困擾了使用者,影響使用者的使用,最關鍵是使得使用者散失對我們公司的信任,覺得我們公司的開發技術不行(什麼???什麼?技術不行??出來,出來,我要和你大戰三百回合、)。那麼這個時候不僅僅是要給使用者一個合理的解釋,查出現象的原因,杜絕現象的再發生就顯得迫不及待了。
2-原因
當時接到使用者反饋,我們第一時間對現象發生的原因進行了一系列猜想:
1.是不是我們專案中的第三方jar非官方版本,被植入了一些廣告程式碼
2.dns劫持
3.http劫持
做技術的都明白,那就是經驗有的時候是助力,也是阻力。很多時候我們會被我們的經驗所羈絆。很多資深技術,看到第一條的現象很容易冒出腦海的肯定是:劫持。
那麼第一條的理由是不是可能導致這種現象,從實現來說,完全可以做到的。現在很多開發人員平常開發過程隨意之極,頻繁的在專案使用一些小眾且不規範的第三方jar包。而這些第三方jar也會是一些廣告的來源。甚至是安全隱患的來源。
另一方面我們根據我們的猜想對使用者及時進行了回訪,以便驗證我們的猜想的正確性。
1.用的是4g還是wifi?
2.如果是wifi,是不是路邊免費的wifi?
3.在什麼頁面出現?(方便定位是h5頁面還是原生介面,對大部分使用者,千萬不要問他是h5還是原生,只能自己分析,如果原生介面也出現那麼第三方jar出現問題的概率很大,如果只是h5介面,那麼劫持的可能性很大)
4.使用的是android 還是ios客戶端
綜合使用者的答案,我們總結如下:
1.4g,wifi都出現了。
2.出現的位置都是h5頁面。
3.android ios都出現了
3-排查
那基本可以定位是網路劫持原因。那麼網路劫持有2種
1.dns劫持
2.http劫持
什麼是DNS劫持:
首先DNS是什麼。在因特網中,機器相互識別靠的是ip,而ip單純的無意義數字的結合,很難被人類熟記,所以產生了域名,例如www.baidu.com 就是域名。那麼問題來了,我們輸入域名,機器又不認識,那麼機器怎麼去訪問?那麼就輪到DNS出場了,DNS在作為域名和IP地址相互對映的一個分散式資料庫,就是我們的瀏覽器,會將域名拿到DNS去解析出ip地址來訪問,DNS劫持是指在劫持的網路範圍內攔截域名解析的請求,分析請求的域名,把審查範圍以外的請求放行,否則返回假的IP地址或者什麼都不做使請求失去響應,其效果就是對特定的網路不能反應或訪問的是假網址。
通俗來說,就是他給我們指向了另一個地址,或者讓我們無法訪問。電信以前的互聯星空的,每次聯網開啟的第一個網頁永遠是互聯星空。就是典型的DNS劫持。
什麼是http劫持:
百度百科的說法:HTTP劫持是在使用者與其目的網路服務所建立的專用資料通道中,監視特定資料資訊,提示當滿足設定的條件時,就會在正常的資料流中插入精心設計的網路資料報文,目的是讓使用者端程式解釋“錯誤”的資料,並以彈出新視窗的形式在使用者介面展示宣傳性廣告或者直接顯示某網站的內容。
通俗來說,你要去百度的首頁,他會給你百度首頁,然後再百度首頁的某個部位+個廣告。 更具欺騙性,危害更大。(畢竟直接給你導向另外一個網址,使用者也不是傻逼,上當的可能性很小。)而這也是現在很多免費wifi植入廣告的手段,因為這樣能更多的點選。
而很明顯,我們遇到的是第二種
4-解決方案
原因定位之後,就是制定解決方案了。根據這個http劫持的特性,我們可以很簡單的給出解決方案:
https。https是以安全為目標的HTTP通道,簡單講是HTTP的安全版。就是說資料交流是加密的那麼所謂的在返回資料裡面加點廣告就無從談起了。而且https也能解決dns劫持(基本杜絕)。而https的成本並不高。連某些黃色網站都開始用https。(我擦,不要問我網址)
當時由於距離發版本時間不足2天,而申請https證書要3-4天,那麼我們需要一個臨時解決方案。那麼怎麼解決呢。
既然這些猥瑣的劫持者通過插入一段js,那麼不讓他執行這段js就好了。
因為android3.0以後webview提供了方法可以方便的攔截到所有的ajax請求,那麼所有的js,圖片下載都可以攔截到。我們可以做個區分,對要執行的js做一個篩選。
從API 11開始引入,API 21棄用
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return Tool.getResponse(WebViewActivity.this,url,control);
}
從API 21開始引入
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
return Tool.getResponse(WebViewActivity.this,request.getUrl().toString(),control);
}
webview在WebViewClient裡提供的2種攔截ajax請求的方法
所有我們做了白名單和黑名單的機制,因為現在hybird的開發流行,app嵌入了很多h5,而h5頁面的製作也參雜了很多第三方的jar,如果只是單純的把公司域名下的請求之外的請求攔截,很容易導致h5的某些功能無法使用,所有我們採用了攔截開關的機制。在前2天上報非白名單的url,方便我們派出一些誤傷的url,這樣加入到白名單,以後開啟攔截的開關,就能做到無誤傷。(https才是正統的解決方案,攔截請求的侷限性太大,而且很容易導致功能誤傷)。
然後我拿著我開啟了攔截開關的app,上了上海的8號線,連上了花生免費wifi,果然---廣告都不見了。
貼一些程式碼。這邊一定要注意,攔截的話一定不能返回null,返回null的話,webview回去正常載入
從API 11開始引入,API 21棄用
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return new WebResourceResponse("text/html", "UTF-8", new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
從API 21開始引入
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
return new WebResourceResponse("text/html", "UTF-8", new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
5-拓展
中國的網路大環境,http劫持廣告很難從源頭杜絕。隨著越來越多的app嵌入h5,會有越來越多的人在手機端遇到這種劫持廣告,作為開發者,一定不要覺得說,這是使用者使用免費wifi的原因或者這是運營商的植入廣告。我們有的時候改變不了大環境,那麼我們做出更多的努力,在app端讓劫持廣告更難成功。
碼農的路上,縱情向前!