Android 網路程式設計系列(2)WebView 的使用

顧小魚發表於2017-11-10

前言

在 Android 中提供了這樣一個特殊的控制元件 WebView,用於顯示網頁。也屬於網路程式設計中的一部分,所以這次就來學習一下 WebView 的相關用法。

最基本用法

WebView 最基本的用法可以分為以下三步:

  1. 在 layout 檔案中新增 WebView 控制元件:
<?xml version="1.0" encoding="utf-8"?>
<WebView  
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>複製程式碼
  1. 呼叫 WebView 的 loadUrl() 方法,傳入要顯示的網址:
WebView mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("http://www.baidu.com");複製程式碼
  1. 在 AndroidManifest.xml 檔案中新增網路訪問的許可權:
<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>複製程式碼

通過以上三個步驟,就已經可以使用 WebView 了。接下來再介紹一下 WebView 的更進一步的內容。

WebView 支援 JavaScript

WebView 預設是不支援 JS 的,我們可以通過手動修改設定來讓 WebView 支援 JS。通過 getSettings() 法獲取到 WebSettings 這個類的例項,這個類是專門用於

//設定支援JS
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);複製程式碼

WebView 頁面處理

但是在載入網頁時,Android 預設是需要呼叫本機中瀏覽器來開啟網頁,而不是直接在本應用中展示。如果想在應用中直接展示網頁,就需要重寫 WebViewClient 類中的 shouldOverrideUrlLoading() 方法,return true 表示使用 WebView 直接展示網頁。

//設定在當前應用中直接展示網頁
mWebView.setWebViewClient(new MyWebViewClient());

class MyWebViewClient extends WebViewClient{
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, 
            String url) {
        view.loadUrl(url);
        return true;
    }
}複製程式碼

WebView 歷史記錄

WebView 自身維護了一個瀏覽歷史記錄的列表,但是在 WebView 中點選返回鍵時,當前頁面不管是不是能夠返回上一頁,都會直接退出 WebView。如果想實現和瀏覽器中一樣的到上一頁、下一頁的效果就需要藉助 WebView 的 goBack() 、goForword() 方法,同時重寫返回鍵的處理邏輯。

先來看看相關的方法說明:

boolean canGoBack ()
判斷此WebView是否可以回到上一頁
boolean cangGoForward ()
判斷此WebView是否可以到下一頁
boolean canGoBackOrForward (int steps)
通過傳進來的引數判斷是否能夠到達指定的頁面,引數為負表示回到上n頁,為正表示去下n頁

void goBack ()
回到上一頁
void goForword ()
去到下一頁
void goBackOrForward (int steps)
回到上n頁或者去到下n頁,steps為負表示後退,為正表示前進

void clearHistory ()
清除所有的歷史紀錄複製程式碼

例項程式碼如下,當按下返回鍵並且 WebView 可以回到上一頁時,就返回到上一頁,否則就按預設邏輯處理:

Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK) 
            && mWebView.canGoBack()) {
        mWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}複製程式碼

JS程式碼呼叫本地Java程式碼

WebView 支援使用 addJavaScriptInterface() 方法來讓 JavaScript 呼叫 App 中的原生 Java 程式碼,比如在網頁中彈出一個原生的對話方塊代替網頁中的 Alert。

void addJavascriptInterface (Object object, String name)
該方法的原理是將一個Java物件以指定的變數名字(程式碼中的name)注入到JS的上下文中,這個時候這個變數在JS中可以用於表示那個Java物件,從而呼叫該物件的方法。複製程式碼

首先需要在 Java 程式碼中建立一個 JavaScriptInterface,比如:

class MyJSInterface{
    private Context mContext;
    public MyInterface(Context context){
        this.mContext = context;
    }
    @JavascriptInterface
    public void showToast(String text){
    Toast.makeText(mContext, text, 1000).show();
    }
}複製程式碼

之後呼叫 WebView 的 addJavaScriptInterface() 方法,傳入上面這個“介面”類的例項和在 JS 中變數名稱:

mWebView.addJavascriptInterface (new MyJSInterface(this), 
        "android");複製程式碼

讓我們看看在 HTML 頁面中是如何呼叫到 Java程式碼的:

<html>
  <head> 
    <meta charset="utf-8"> 
    <title>JSDemo</title> 
    <script>
       function toast(msg) {
         window.android.showToast(msg)
       }
    </script>
  </head>
  <body>
    <button type="button" id="btn_toast" 
        onclick="toast('show a Toast')">
      toast
    </button>
  </body>
</html>複製程式碼

可以看到在 HTML 頁面上有一個按鈕,點選這個按鈕就會執行 JS 中的 toast() 方法,在這個方法裡面就是呼叫了 window.android.showToast() 方法。

使用 addJavaScriptInterface() 需要注意以下幾點:

  1. addJavascriptInterface() 方法中要繫結的 Java 物件及方法要執行另外的執行緒中,不能執行在構造它的執行緒中。

  2. 使用這個方法在 Android 4.2 以下的版本中會存在安全隱患,4.2 以下的版本沒有對註冊 Java 類的方法呼叫進行限制,所以 JavaScript 可以使用反射來訪問注入物件的公共欄位,以及其他任何沒有註冊的 Java 類。攻擊者可以通過這一漏洞對客戶端為所欲為,包括盜取個人隱私資料等。

  3. 在 Android 4.2(targetSdkVersion ≥ 17)以上的版本中這個漏洞被解決,在註冊 Java 物件需要呼叫的方法前必須加上@JavascriptInterface這個註解,否則 JS 程式碼不能呼叫該方法。

結束語

就先寫這些吧。這篇文章寫了很久,但還是沒寫好。因為其實並沒有講的很深入,只是介紹了一些皮毛,我自己的理解也還沒到位。下一篇文章努力做的更好一點,還是關於 WebView。

下次見。

參考文章

照例貼一下在學習過程中看過的一些優秀的部落格,真的從中學到了很多的東西。

developer.android.google.cn/reference/a…
谷歌開發者官網:WebView
jaq.alibaba.com/blog.htm?id…
阿里無線安全平臺:WebView 遠端程式碼執行漏洞淺析
www.jianshu.com/p/e3965d363…
談談WebView的使用(作者的想法很好)
www.kymjs.com/code/2015/0…
kymjs.com/code/2015/0…
張濤:深入講解WebView(上、下)

相關文章