編輯:關於Android編程
最近在開發過程中遇到一個問題,就是WebView使用的時候,還是需要解決之前系統(4.2之前)導致的一個漏洞,雖然現在這個系統版本用戶很少了,但是也不能忽視,關於這個漏洞,這裡就不多做解釋了,可能有的同學早就了解了,本來想寫一篇文章詳細介紹一下,但是網上的知識太多了,而且都很詳細,就沒弄了,這裡大致簡單明了的說幾句:
這個漏洞導致的原因主要是因為Android中WebView中的JS訪問本地方法的方式存在缺陷,我們做過交互的都知道,Android中的交互方式是通過WebView的一個方法:
addJavascriptInterface(new JSObject(), "myObj");
第一個參數:Android本地對象;第二個參數就是JS代碼中需要使用的對象
所以這裡看其實就相當於一個映射關系,把Android中的本地對象和JS中的對象關聯即可。
那麼這裡就存在這樣的一個問題了,在4.2系統之前,JS中通過對象調用的方法無需任何注解約束,那麼就意味著JS中拿到這個對象,就可以調用這個對象中所有的方法,而我們知道Android中的對象有一個公共的方法getClass()方法,而這個方法可以獲取到當前類類型Class,而這個類型有一個很關鍵的方法就是Class.forName,這個方法可以加載一個類,這裡可以加載java.lang.Runtime這個類,而這個類就可以執行本地命令了,那麼就會發生危險了,比如這裡可以執行命令獲取本地設備的SD卡中的文件等信息,非常危險的。
上面可能說的還是有些同學不太了解,下面就用一段簡單的JS代碼來了解一下:
看到這段JS之後的同學應該好理解了,因為我們Android本地通過WebView進行了對象映射,那麼WebView加載頁面中如果包含這段JS代碼,那麼就會存在這個問題,這裡先遍歷window中所有的對象,然後查找這個對象是否有getClass方法,有的話就在利用反射調用Runtime類執行具體命令即可。其實這個漏洞也得力於JS中的語法特性,這裡可以看到JS語法非常的靈活。
當然對於Android4.2之後系統修復了這個漏洞,修復方法也很簡單,加上注解約束:@JavascriptInterface 就是只有加上這個注解的方法才會被JS調用,那麼我們知道getClass是Object類中的,肯定沒有這個注解,那麼上面的JS代碼肯定執行不到了。就這樣解決了這個漏洞。
還有一個問題,就是Android系統默認的會給WebView添加一個JS映射對象:searchBoxJavaBridge_ 這個對象是Android3.0之後默認加上去的,也就是說通過這個對象也是可以操作的上面的代碼的。
說完了,這個漏洞,下面開始說今天的正題了,為什麼要先介紹這個漏洞呢?原因就是如果要在4.2以下版本中解決這個漏洞的話就需要借助今天介紹的內容了,首先來看看今天的內容主要是介紹Android中WebView的JS和本地交互的三種方式:
第一種方式:通過addJavascriptInterface方法進行添加對象映射
這種方式不多解釋了,也是Android中最常用的方式,但是這種方式會存在風險就是上面說到的漏洞問題。
這裡定義一個簡單的本地對象,在需要被調用的方法加上約束注解。JS代碼也很簡單:
這種方式的好處在於使用簡單明了,本地和JS的約定也很簡單,就是對象名稱和方法名稱約定好即可,缺點就是存在漏洞問題。
第二種方式:利用WebViewClient接口回調方法攔截url
這種方式其實實現也很簡單,就是我們可以添加WebViewClient回調接口,在shouldOverrideUrlLoading回調方法中攔截url,然後解析這個url的協議,如果發現是我們約定好的協議就開始解析參數執行具體邏輯:
代碼也很簡單,這個方法可以攔截WebView中加載url的過程,得到對應的url,我們就可以通過這個方法,和網頁JS約定好一個協議,看一下JS代碼:
這個JS代碼執行之後,就會觸發本地的shouldOverrideUrlLoading方法,然後進行參數解析,調用指定方法。
這個方法是不會存在第一種方法的漏洞問題,但是細心的同學可以發現,這裡本地和JS之間的約定有點繁瑣,比如要約定好協議,參數名稱等信息,沒有第一種方式方便。而且最主要的問題是,這個只能主動的調用本地化方法,如果想得到方法的返回值,只能通過WebView的loadUrl方法去執行JS方法,把返回值傳遞回去:mWebView.loadUrl("javascript:clicktworesult("+res+")");
看到這種方式是非常繁瑣的。在Android中也是不提倡使用的。
注意:在iOS中沒有像Android中的第一種方式,他也是為了安全考慮,所以iOS中的交互就是采用的第二種方式,通過攔截url來進行操作的,當時候介紹iOS這部分內容的時候在詳細介紹。
第三種方式:利用WebChromeClient回調接口的三個方法攔截消息
這個方法的原理其實和第二種方式差不多,只是攔截的接口方法不一樣:
Android中的WebView添加WebChromeClient接口,可以攔截JS中的幾個提示方法,也就是幾種樣式的對話框,在JS中有三個常用的對話框方法:
1. alert是彈出警告框,在文本裡面加入\n就可以換行。
2. confirm彈出確認框,會返回布爾值,通過這個值可以判斷點擊時確認還是取消。true表示點擊了確認,false表示點擊了取消。
3. prompt彈出輸入框,點擊確認返回輸入框中的值,點擊取消返回null。
那麼這三種對話框都是可以在本地攔截到的,那麼第三種方法的原理就是攔截這些方法,得到他們的消息內容,然後解析即可,比如這裡我們攔截了prompt方法內容:
本地攔截的方法參數說明:
為什麼要攔截prompt方法,因為這個方法可以返回想要的值,而對於alert是無法得到返回值的,confirm只能得到兩個返回值。只有prompt方法可以返回各種類型的值,操作最方便。
然後在這個方法中和第二種方法一樣的原理解析消息內容即可
下面直接看看上面的三種方式的執行效果:
第一種方式:
第二種方式:
第三種方式:
其中html代碼如下:
好了,到這裡我們就介紹完了Android中WebView的JS和本地交互的三種方式:
第一種方式:是最普遍的用法,方便簡單,但是在4.2系統以下存在漏洞問題
第二種方式:是通過攔截url,解析約定之後的協議調用本地方法,缺點是約束協議比較繁瑣,而且傳回執行之後的返回值比較麻煩。但是不會存在漏洞問題,而這種方式也是iOS中采用的方式。
第三種方式:其實和第二種方式差不多,只是攔截的方法變了,這裡攔截的是JS中的三種對話框方法,而這三種對話框方法的區別就在於返回值問題,alert對話框方法沒有返回值,confirm對話框方法只有兩種狀態的返回值,prompt對話框方法可以返回任意類型的返回值。缺點和第二種方法一樣,協議約定比較繁瑣,但是不會存在漏洞問題。
最後在來介紹一下文章中開始介紹的漏洞問題,雖然google在4.2之後修復了這個漏洞,但是對於4.2之前的用戶該如何處理這個漏洞呢?這裡主要就是需要借助第三種方式了,攔截prompt方法,修復步驟很簡單:
1、我們自己顯示一個WebView的包裝器,重寫他的addJavascriptInterface方法,然後在內部自己維護一個對象映射關系Map
2、在WebView加載頁面的方法中構造一段本地JS代碼:
關於這段JS代碼的含義:
1> 上面代碼中的jsInterface就是要注冊的對象名,它注冊了兩個方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2),如果有返回值,就添加上return。
2> prompt中是我們約定的字符串,它包含特定的標識符MyApp:,後面包含了一串JSON字符串,它包含了方法名,參數,對象名等。
3> 當JS調用onButtonClick或onImageClick時,就會回調到Java層中的onJsPrompt方法,我們再解析出方法名,參數,對象名,再反射調用方法。
4> window.jsInterface這表示在window上聲明了一個Js對象,聲明方法的形式是:方法名:function(參數1,參數2)
而加載這段JS代碼的時機是什麼時候呢?
剛開始時在當WebView正常加載URL後去加載Js,但發現會存在問題,如果當WebView跳轉到下一個頁面時,之前加載的Js就可能無效了,所以需要再次加載。這個問題經過嘗試,需要在以下幾個方法中加載Js,它們是WebChromeClient和WebViewClient的方法:onLoadResource,doUpdateVisitedHistory,onPageStarted,onPageFinished,onReceivedTitle,onProgressChanged
3、讓JS調用一個Javascript方法,這個方法中是調用prompt方法,通過prompt把JS中的信息傳遞過來,這些信息應該是我們組合成的一段有意義的文本,可能包含:特定標識,方法名稱,參數等。在onJsPrompt方法中,我們去解析傳遞過來的文本,得到方法名,參數等,再通過反射機制,調用指定的方法,從而調用到Java對象的方法。
4、關於返回值,可以通過prompt返回回去,這樣就可以把Java中方法的處理結果返回到Js中。
通過這幾步,就可以簡單的修復漏洞問題,但是還是需要注意幾個問題:
1> 需要過濾掉Object類的方法由於通過反射的形式來得到指定對象的方法,他會把基類的方法也會得到,最頂層的基類就是Object,所以我們為了不把getClass方法注入到Js中,所以我們需要把Object的公有方法過濾掉。這裡嚴格說來,應該有一個需要過濾方法的列表。目前我的實現中,需要過濾的方法有:
"getClass","hashCode","notify","notifyAll","equals","toString","wait",
2> 在Android 3.0以下,系統自己添加了一個叫searchBoxJavaBridge_的Js接口,要解決這個安全問題,我們也需要把這個接口刪除,調用removeJavascriptInterface方法。這個searchBoxJavaBridge_好像是跟google的搜索框相關的。
3> 在實現過程中,我們需要判斷系統版本是否在4.2以下,因為在4.2以上,Android修復了這個安全問題。我們只是需要針對4.2以下的系統作修復。
在Android中WebView的作用還是舉足輕重的,加上現在很多應用都開始采用網頁版功能,那麼在這個過程中無法避免就是需要JS和本地交互,本文就詳細的介紹了現階段的三種交互方式,每種方式都有缺點和優點,當然最好的方式還是采用系統提供的也就是本文介紹的第一種方式,但是需要修復Android4.2以下存在的漏洞問題即可。
本文實例講述了Android編程之語音識別實現方法。分享給大家供大家參考,具體如下:語音識別技術在手機上應用得相當廣泛,人類日常最頻繁的溝通方式是語音,而在手機應用中,大
圖片的拖拉功能是處理圖片進一個有用且常用的功能,由於手機屏幕尺寸的限制,往往無法在手機上一次性的顯示一張比較大的圖片,也就是 說,我們在手機上一次性只能看到圖片的一部分,
在android項目的開發中,有時為了實現和用戶更好的交互,在通知欄這一小小的旮旯裡,我們通常需要將內容豐富起來,這個時候我們就需要去實現自定義的通知欄,例如下面360或
一、前言2分鐘只是一個虛數哈,不過只要你速度快,兩分鐘還真是能搞定的哦。在2.1.8版本以前,極光的配置還是非常麻煩的,需要在清單文件(AndroidManifest.x