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互動動作
(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>