1. 程式人生 > >WebView的使用以及Android與Js的互動

WebView的使用以及Android與Js的互動

1.WebView基礎使用

1.想要使用WebView,需要在<manifest>中新增許可權:

<uses-permission android:name="android.permission.INTERNET" />
2.我們可以在xml檔案中使用<WebView>控制元件,也可以在我們自己的activity中直接建立
 WebView webview = new WebView(this);
 setContentView(webview);
3.我們想要根據WebView來做一些自己的操作,一般通過兩個事件來處理,分別是WebViewClient和WebChromeClient。

 WebChromeClient會在一些影響瀏覽器ui互動動作

發生時被呼叫,比如WebView關閉和隱藏、頁面載入進展、js確認框和警告框、js載入前、js操作超時、webView獲得焦點等等

(2).WebViewClient可以提供頁面載入各個階段的回撥,包括onPageStarted()和onPageFinished()等方法,也可以呼叫shouldOverrideUrlloading()來攔截url。這段程式碼還有一個作用,就是當需要從一個網頁跳轉到另一個網頁時,我們希望目標網頁仍然在當前WebView中,而不是開啟系統瀏覽器。相關方法檢視文件(https://developer.android.com/reference/android/webkit/WebViewClient.html

4.我們想要實現android和js的互動,必須獲得一個WebSettings物件,呼叫setJavaScriptEnabled()方法,

webview.getSettings().setJavaScriptEnabled(true);

 注意:因為安全問題的考慮google在使用android API17以上的版本的時候,需要通過@JavascriptInterface來註解的Java函式才能被識別可以被js呼叫。

5.載入網頁呼叫loadUrl(str)方法

 webview.loadUrl("http://developer.android.com/");

可以傳入一個網路地址,也可以傳入一個本地的html資原始檔。

6.webview載入微信公眾號連線,“閱讀原文”無響應

由於dom記憶體沒有啟用,所以導致了js載入失敗

getSettings().setDomStorageEnabled(true);

7.webview獲得內容長度

//        getContentHeight 返回的是整個html 的高度,但並不等同於當前整個頁面的高度,
//        因為WebView 有縮放功能, 所以當前整個頁面的高度實際上應該是原始html 的高度再乘上縮放比例.
//        因此,更正後的結果,準確的判斷方法應該是:
        mWebView.getContentHeight()*mWebView.getScale();

8.WebView快取

當我們載入Htlm的時候,會在我們的data/包名/下生成database和cache兩個資料夾。

我們請求的url記錄會儲存在webviewCache.db裡,而url的內容則是儲存在webviewcache資料夾下。

webview存在著兩種快取:網頁資料快取(儲存開啟過的頁面及資源)、H5快取(即AppCache)

1). 快取模式的設定:

webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);  //設定 快取模式  
總共有五種模式可選擇:

LOAD_CACHE_ONLY  不使用網路,只讀取本地快取資料

LOAD_DEFAULT   根據cache-control來決定是否從網路上讀取資料

LOAD_CACHE_NORMAL   API level 17中已經廢棄,從API level 11 開始作用同LOAD_DEFAULT模式

LOAD_NO_CACHE   不使用快取,只從網路獲取資料

LOAD_CACHE_ELSE_NETWORK   只要本地有,無論是否過去,或者no-cache,都是用快取中的資料

2). H5快取

通過setAppCacheEnabled(boolean falg) 設定h5快取是否開啟,預設關閉。

通過setAppCachePath(String appCachePath) 提供的路徑,在h5使用快取過程中生成的快取檔案。

通過setAppCacheMaxSize(long appCacheMaxSize) 設定快取最大容量。

		// 開始app快取
		webview.getSettings().setAppCacheEnabled(true);
		// 設定緩衝大小 
		webview.getSettings().setAppCacheMaxSize(1024 * 1024 * 16);
		// 設定緩衝路徑
		String appCacheDir = getApplicationContext().getDir("cache",
				Context.MODE_PRIVATE).getPath();
		webview.getSettings().setAppCachePath(appCacheDir);
3). 其他相關的設定
// 開啟 DOM storage API 功能
webSettings.setDomStorageEnabled(true);
//開啟 database storage API 功能
webSettings.setDatabaseEnabled(true);
//設定可以訪問檔案
webSettings.setAllowFileAccess(true);
//設定支援縮放
webSettings.setBuiltInZoomControls(true);

http://blog.sina.com.cn/s/blog_61cf99580102vj36.html
http://blog.csdn.net/t12x3456/article/details/13769731/#comments

2.Android呼叫Js

只需要在loadUrl裡面的引數格式為“javascript:方法名()”,例如,html中有一個方法名叫做javaCallJs(),在android中呼叫這個方法的程式碼如下:

mWebView.loadUrl("javascript:javaCallJs()");
實現如下效果:


JavaCallJsActivity.java

package com.example.android_js;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.Button;

/**
 * Created by jian on 2016/10/31.
 */
public class JavaCallJsActivity extends Activity {

    private Button btn1, btn2, btn3;
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_javacalljs1);

        initView();

        // 設定webview的javascript可用
        mWebView.getSettings().setJavaScriptEnabled(true);
        // 載入html,可網路,可本地
        mWebView.loadUrl("file:///android_asset/JavaCallJs.html");
        // 不加下面這句話,是無法調起alert的
        mWebView.setWebChromeClient(new WebChromeClient());
    }

    private void initView() {
        btn1 = (Button) findViewById(R.id.java_call_js1_btn1);
        btn2 = (Button) findViewById(R.id.java_call_js1_btn2);
        btn3 = (Button) findViewById(R.id.java_call_js1_btn3);
        mWebView = (WebView) findViewById(R.id.java_call_js1_webview);

        btn1.setOnClickListener(mOnClickListener);
        btn2.setOnClickListener(mOnClickListener);
        btn3.setOnClickListener(mOnClickListener);
    }

    View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.java_call_js1_btn1:
                    mWebView.loadUrl("javascript:javaCallJsNoArgs()");
                    break;
                case R.id.java_call_js1_btn2:
                    mWebView.loadUrl("javascript:javaCallJsExistArgs('我是聶建')");
                    break;
                case R.id.java_call_js1_btn3:
                    mWebView.loadUrl("javascript:showAlert('出現了alert!')");
                    break;
            }
        }
    };

}
activity_javacalljs1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              android:padding="10dp">

    <Button
        android:id="@+id/java_call_js1_btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="java呼叫js無參方法"/>

    <Button
        android:id="@+id/java_call_js1_btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="java呼叫js有參方法"/>

    <Button
        android:id="@+id/java_call_js1_btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="java呼叫js的dialog"/>

    <WebView
        android:id="@+id/java_call_js1_webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
JavaCallJs.html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>Java呼叫JavaScript</title>
		<style>
			#javacalljs1,
			#javacalljs2 {
				color: red;
			}
		</style>
		<script type="text/javascript">
			function javaCallJsNoArgs() {
				document.getElementById("javacalljs1").innerHTML += "Java呼叫了我的無參函式<br\>";
			}

			function javaCallJsExistArgs(args) {
				document.getElementById("javacalljs2").innerHTML += "Java呼叫了我的有參函式,引數是:" + args + "<br\>";
			}

			function showAlert(args) {
				alert(args);
			}
		</script>
	</head>

	<body>
		這是NieJian寫的Java呼叫Js的驗證頁面!<br /><br /> 點選按鈕:“java呼叫js無參方法”。會出現以下內容:
		<br />
		<div id="javacalljs1"></div><br /><br /> 點選按鈕:“java呼叫js有參方法”。會出現以下內容:
		<br />
		<div id="javacalljs2"></div>
	</body>

</html>

3.Js呼叫Android

Js呼叫Android,首先要在android程式碼中註冊一個物件,呼叫如下方法:

void addJavascriptInterface (Object object,String name)
Object: the Java object to inject into this WebView's JavaScript context. Null values are ignored.
String: the name used to expose the object in JavaScript
這個方法是將object這個java物件注入到webview中,然後在webview中通過name這個欄位來唯一標識呼叫object這個java物件中的方法。
 For applications targeted to API level JELLY_BEAN_MR1 and above, only public methods that are annotated with 
JavascriptInterface can be accessed from JavaScript. For applications targeted to API level JELLY_BEAN or below, 
all public methods (including the inherited ones) can be accessed
根據文件介紹,API17開始,就必須新增 @JavascriptInterface 註解,,而且方法必須是public修飾,否則,不生效,API16及以下的public方法可以不添加註解。
class JsObject {
    @JavascriptInterface
    public String toString() { return "injectedObject"; }
 }
 webView.addJavascriptInterface(new JsObject(), "injectedObject");
 webView.loadData("", "text/html", null);
 webView.loadUrl("javascript:alert(injectedObject.toString())");
下面是一個小案例,實現效果如下:

JsCallJavaActivity.java

package com.example.android_js;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;

/**
 * Created by jian on 2016/10/31.
 */
public class JsCallJavaActivity extends Activity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_javacalljs2);

        initWebView();
    }

    private void initWebView() {
        mWebView = (WebView) findViewById(R.id.java_call_js2_webview);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDefaultTextEncodingName("utf-8");

        // 新增一個物件,讓js物件可以訪問該物件的方法
        mWebView.addJavascriptInterface(new MyObject(), "niejian_android");
        mWebView.loadUrl("file:///android_asset/JsCallJava.html");
    }

    class MyObject {
        /**
         * API 17必須新增 @JavascriptInterface註解,否則會導致反射失敗,呼叫無效
         */
        @JavascriptInterface
        public void javaCallJsMethod1() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mWebView.loadUrl("javascript:javaCallJsNoArgs()");
                }
            });
        }

        @JavascriptInterface
        public void javaCallJsMethod2() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mWebView.loadUrl("javascript:javaCallJsExistArgs('我是聶建')");
                }
            });
        }
    }
}
JsCallJava.html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>JavaScript呼叫Java</title>
		<style>
			#content1,
			#content2 {
				color: red;
			}
		</style>
		<script type="text/javascript">
			function javaCallJsNoArgs() {
				document.getElementById("content1").innerHTML = "js呼叫java,Java再回調js的無參方法"
			}

			function javaCallJsExistArgs(args) {
				document.getElementById("content2").innerHTML = "js呼叫java,Java再回調js的無參方法,引數是:" + args;
			}
		</script>
	</head>

	<body>
		這是NieJian寫的Java呼叫Js的驗證頁面2!<br />
		<input type="button" value="JS->Java->JS “無參方法”,請點選,檢視下方" onclick="window.niejian_android.javaCallJsMethod1()" /><br />
		<div id="content1"></div>
		<br /><br />
		<input type="button" value="JS->Java->JS “有參方法”,請點選,檢視下方" onclick="window.niejian_android.javaCallJsMethod2()" /><br />
		<div id="content2"></div>
	</body>

</html>



原始碼下載