Android開發中WebView與原生JS的數據交互詳解

本文來分享詳細的在Android開發中,如何利用WebView與原生JS的數據交互,本教程附有代碼和效果圖,是一個不可多得的好教程。

關於WebView

我們知道目前android市場上的一些應用採用的開發方式大致分爲三種:Native App、Web App、Hybrid App。本文主要是Hybrid App中實現的主要技術native組件與js的數據交互的理解以及實現。

Android API中提供了WebView組件來實現對html的渲染。所謂的HybridApp開發方式即是彙集了HTML5、CSS3、jS的相關開發技術,以及數據交換格式json/XML。這顯然是Web開發工程師的技能。正是因爲如此,衆多中小企業選擇了這種開發方式來減少對android開發工程師的過度依賴,至於這三種開發方式的比較與優劣不在本文考慮之列。

有了WebView這個組件,Android應用開發技術也就轉嫁到html與java數據交互上來。說白了就是js與WebView的數據交互,這就是本文所要討論的。


WebView與js的數據交互

1. WebView中載入靜態頁面


將WebView添加到應用中。和原生控件一樣,在layout引入WebView控件。代碼片段如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
android:orientation="horizontal" >
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" 
/>
</LinearLayout>

載入頁面:



webView = (WebView) findViewById(R.id.webview);
webView.loadUrl("file:///file:///android_asset/page.html");

page.html存儲在工程文件的assets根目錄下。

2. 引入jquery mobile

引入js框架讓我們編寫的html頁面更接近於原生控件的顯示效果。目前主流的移動應用js框架有:jquery mobile和sencha touch(jquery mobile與sencha touch的選型不在本文討論範圍)。本文選擇使用jquery mobile。



首先,在webview添加對js的支持:

WebSettings setting = webView.getSettings();
setting.setJavaScriptEnabled(true);//支持js

增加對中文的支持:

WebSettings setting = webView.getSettings();
setting.setDefaultTextEncodingName("GBK");//設置字符編碼

設置頁面滾動條風格:

webView.setScrollBarStyle(0);//滾動條風格,爲0指滾動條不佔用空間,直接覆蓋在網頁上

jquery mobile提供的標準頁面模板TemplateForJQuery.html:

<!DOCTYPE html> 
<html> 
<head> 
<title>Page Title</title> 

<meta name="viewport" content="width=device-width, initial-scale=1"> 

<link rel="stylesheet" href="css/jquery.mobile-1.1.1.min.css" />
<script src="js/jquery.js"></script>
<script src="js/jquery.mobile-1.1.1.min.js"></script>
</head> 
<body> 

<div data-role="page">

<div data-role="header">
<h1>Page Title</h1>
</div><!-- /header -->

<div data-role="content"> 
<p>Page content goes here.</p> 
</div><!-- /content -->

<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->

</body>
</html>

頁面依賴的js庫、css等均放在assets目錄下,目錄組織結構如下:



運行應用後的截圖:


下面是button 的截圖,與原生控件沒什麼明顯區別,有種以假亂真的感覺:


3. 良好的用戶體驗

運行我們的應用發現,在擁有大量js的頁面被載入時,一直處於等待中,這是很糟糕的用戶體驗。可以加入進度條解決。注意到webview提供的兩個方法:setWebViewClient和setWebChromeClient。其中setWebChromeClient方法正是可以處理progress的加載,此外,還可以處理js對話框,在webview中顯示icon圖標等。對於處理progress的代碼片段如下:

webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {// 載入進度改變而觸發
if (progress == 100) {
handler.sendEmptyMessage(1);// 如果全部載入,隱藏進度對話框
}
super.onProgressChanged(view, progress);
}
});

其中通過handler 消息機制來處理UI線程的更新:



handler = new Handler() {
public void handleMessage(Message msg) {// 定義一個Handler,用於處理下載線程與UI間通訊
if (!Thread.currentThread().isInterrupted()){
switch (msg.what) {
case 0:
pd.show();// 顯示進度對話框
break;
case 1:
pd.hide();// 隱藏進度對話框,不可使用dismiss()、cancel(),否則再次調用show()時,顯示的對話框小圓圈不會動。
break;
}
}
super.handleMessage(msg);
}
};

對於setWebViewClient方法,一般用來處理html的加載(需要重載onPageStarted(WebView view, String url, Bitmap favicon))、關閉(需要重載onPageFinished(WebViewview, String url)方法)。



setWebViewClient和setWebChromeClient的作用:前者主要用於處理webView的控制問題,如加載、關閉、錯誤處理等;後者主要處理js對話框、圖標、頁面標題等。

4. 獲取java中的數據

單獨構建一個接口,作爲處理js與java的數據交互的橋樑,本文封裝的代碼AndroidToastForJs.java如下:

public class AndroidToastForJs {

private Context mContext;

public AndroidToastForJs(Context context){
this.mContext = context;
}

//webview中調用toast原生組件
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}

//webview中求和
public int sum(int a,int b){
return a+b;
}

//以json實現webview與js之間的數據交互
public String jsontohtml(){
JSONObject map;
JSONArray array = new JSONArray();
try {
map = new JSONObject();
map.put("name","aaron");
map.put("age", 25);
map.put("address", "中國上海");
array.put(map);

map = new JSONObject();
map.put("name","jacky");
map.put("age", 22);
map.put("address", "中國北京");
array.put(map);

map = new JSONObject();
map.put("name","vans");
map.put("age", 26);
map.put("address", "中國深圳");
map.put("phone","13888888888");
array.put(map);
} catch (JSONException e) {
e.printStackTrace();
}
return array.toString();
}
}




Webview提供的傳入js的方法:

webView.addJavascriptInterface(new AndroidToastForJs(mContext), "JavaScriptInterface");

Html頁面jsonData.html設計的部分代碼如下:

<script type="text/javascript">
var result = JavaScriptInterface.jsontohtml();
var obj = eval("("+result+")");//解析json字符串
function showAndroidToast(toast) 

JavaScriptInterface.showToast(toast); 
}
function getjsonData(){
var result = JavaScriptInterface.jsontohtml();
var obj = eval("("+result+")");//解析json字符串
for(i=0;i<obj.length;i++){
var user=obj[i];
document.write("<p>姓名:"+user.name+"</p>");
document.write("<p>年齡:"+user.age+"</p>");
document.write("<p>地址:"+user.address+"</p>");
if(user.phone!=null){
document.write("<p>手機號碼:"+user.address+"</p>");
}
}

function list(){
document.write("<div data-role='header'><p>another</p></div>");
}
</script>
</head> 
<body> 
<div data-role="page" >
<div data-role="header" data-theme="c">
<h1>Android via Interface</h1>
</div><!-- /header -->
<div data-role="content"> 
<button value="say hello" onclick="showAndroidToast('Hello,Android!')" data-theme="e"></button>
<button value="get json data" onclick="getjsonData()" data-theme="e"></button> 
</div><!-- /content -->
<div data-role="collapsible" data-theme="c" data-content-theme="f">
<h3>I'm <script>document.write(obj[0].name);</script>,click to see my info</h3>
<p><script>document.write("<p>姓名:"+obj[0].name+"</p>");</script></p>
<p><script>document.write("<p>年齡:"+obj[0].age+"</p>");</script></p>
<p><script>document.write("<p>地址:"+obj[0].address+"</p>");</script></p>
</div>
<div data-role="footer" data-theme="c">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->
</body>

點擊say hello按鈕運行的截圖如下:




另外一篇關於webview與js交互

對於android初學者應該都瞭解webView這個組件。之前我也是對其進行了一些簡單的瞭解,但是在一個項目中不得不用webview的時候,發現了webview的強大之處,今天就分享一下使用webview的一些經驗。


1、首先了解一下webview。

webview介紹的原文如下:A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

從上面你應該瞭解到了基本功能,也就是顯示網頁。之所以我說webview功能強大是因爲它和js的交互非常方便,很簡單就可以實現。



2、webview能做什麼?

①webView可以利用html做界面佈局,雖然目前還比較少人這麼使用,不過我相信當一些客戶端需要複雜的圖文(圖文都是動態生成)混排的時候它肯定是個不錯的選擇。

②直接顯示網頁,這功能當然也是它最基本的功能。

③和js交互。(如果你的js基礎比java基礎好的話那麼採用這種方式做一些複雜的處理是個不錯的選擇)。



3、如何使用webview?

這裏直接用一個svn上取下的demo,先上demo後講解。demo的結構圖如下:


WebViewDemo.java

package com.google.android.webviewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

/**
* Demonstrates how to embed a WebView in your activity. Also demonstrates how
* to have javascript in the WebView call into the activity, and how the activity 
* can invoke javascript.
* <p>
* In this example, clicking on the android in the WebView will result in a call into
* the activities code in {@link DemoJavaScriptInterface#clickOnAndroid()}. This code
* will turn around and invoke javascript using the {@link WebView#loadUrl(String)}
* method.
* <p>
* Obviously all of this could have been accomplished without calling into the activity
* and then back into javascript, but this code is intended to show how to set up the 
* code paths for this sort of communication.
*
*/
public class WebViewDemo extends Activity {

private static final String LOG_TAG = "WebViewDemo";

private WebView mWebView;

private Handler mHandler = new Handler();

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);

mWebView.setWebChromeClient(new MyWebChromeClient());

mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

mWebView.loadUrl("file:///android_asset/demo.html");
}

final class DemoJavaScriptInterface {

DemoJavaScriptInterface() {
}

/**
* This is not called on the UI thread. Post a runnable to invoke
* loadUrl on the UI thread.
*/
public void clickOnAndroid() {
mHandler.post(new Runnable() {
public void run() {
mWebView.loadUrl("javascript:wave()");
}
});

}
}

/**
* Provides a hook for calling "alert" from javascript. Useful for
* debugging your javascript.
*/
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d(LOG_TAG, message);
result.confirm();
return true;
}
}
}



demo.html

<html>
<script language="javascript">
/* This function is invoked by the activity */
function wave() {
alert("1");
document.getElementById("droid").src="android_waving.png";
alert("2");
}
</script>
<body>
<!-- Calls into the javascript interface for the activity -->
<a onClick="window.demo.clickOnAndroid()"><div style="width:80px;
margin:0px auto;
padding:10px;
text-align:center;
border:2px solid #202020;" >
<img id="droid" src="android_normal.png"/><br>
Click me!
</div></a>
</body>
</html>



main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<TextView 
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:text="@string/intro"
android:padding="4dip"
android:textSize="16sp"
/>

<WebView
android:id="@+id/webview"
android:layout_width="fill_parent" 
android:layout_height="0dip"
android:layout_weight="1"
/>

</LinearLayout>



4、如何交互?

①android如何調用js。

調用 形式:

mWebView.loadUrl("javascript:wave()");

其中wave()是js中的一個方法,當然你可以把這個方法改成其他的方法,也就是android調用其他的方法。

②js如何調用android。

調用形式:

<a onClick="window.demo.clickOnAndroid()">

代碼中的“demo”是在android中指定的調用名稱,即

mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

代碼中的clickOnAndroid()是“demo”對應的對象:new DemoJavaScriptInterface() 中的一個方法。

③雙向交互。

當然是把前面的兩種方式組合一下就可以了。



5、講解demo。

現在你一定了解了android和js的交互了。是時候分析一些demo了,根據上面講的你也應該比較清楚了。具體交互流程如下:

①點擊圖片,則在js端直接調用android上的方法clickOnAndroid();

②clickOnAndroid()方法(利用線程)調用js的方法。

③被②調用的js直接控制html。



個人總結:利用webView的這種方式在有些時候UI佈局就可以轉成相應的html代碼編寫了,而html佈局樣式之類有DW這樣強大的工具,而且網上很多源碼,很多代碼片。在UI和視覺效果上就會節省很多時間,重複發明輪子沒有任何意義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章