Android學習筆記_32_經過WebView實現JS代碼與Java代碼互相通訊

webview兩種實現方法,覆蓋onKeyDown()方法javascript

緩存html

WebSettings應用注意的幾個問題java

一、要實現JS代碼與Java代碼互相通訊,須要經過Android的WebView控件,在視圖佈局界面引入該控件,代碼以下:android

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
    />
</RelativeLayout>

二、準備html界面:web

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
    function show(jsondata){
        var jsonobjs = eval(jsondata);
        var table=document.getElementById("personTable");
        for(var y=0;y<jsonobjs.length;y++){
            var tr = table.insertRow(table.rows.length);
            var td1=tr.insertCell(0);
            td1.align="center";
            var td2=tr.insertCell(1);
            td2.align="center";
            
            td1.innerHTML=jsonobjs[y].name;
            td2.innerHTML="<a href='javascript:contact.call(\""+jsonobjs[y].phone+"\")'>"+jsonobjs[y].phone+"</a>";
        }
    }

</script>
</head>
<body onload="javascript:contact.showContacts()">
    <table border="0" cellspacing="0" id="personTable" width="100%">
        <tr>
            <td width="35%" align="right">姓名</td><td align="center">電話</td>
        </tr>
    </table>
    <a href="javascript:window.location.reload()">刷新</a>
</body>
</html>

  在上述代碼中相似"javascript:contact.showContacts()"這樣的寫法,它表明的意思是調用javascript對象contact的showContacts方法。而對象contact就要從後臺java代碼中獲取。json

三、在java代碼中建立javascript對象:瀏覽器

package com.example.html;

import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import com.example.service.ContactService;

import android.net.Uri;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.webkit.WebView;

public class MainActivity extends Activity {
    private WebView webView;
    private ContactService contactService;

    @SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" })
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) this.findViewById(R.id.webView);
        webView.loadUrl("file:///android_asset/contact.html");// 加載html文件
        webView.getSettings().setJavaScriptEnabled(true);// 啓用javascript

        // 第一個參數在javascript中的一個對象,第二個參數在javascript中當前對象的變量
        webView.addJavascriptInterface(new JSObject(), "contact");
        contactService = new ContactService();

    }

    private final class JSObject {
        // 顯示聯繫人列表,對於高版本的須要用@JavascriptInterface註釋,不然調不到該方法
        @JavascriptInterfacepublic void showContacts() {
            try {
                List<ContactService.Contact> contacts = contactService.getContacts();
                JSONArray jsonArray = new JSONArray();
                for (ContactService.Contact contact : contacts) {
                    JSONObject object = new JSONObject();
                    object.put("name", contact.getUsername());
                    object.put("phone", contact.getPhone());
                    jsonArray.put(object);
                }
                String json = jsonArray.toString();
                // 後臺調用前臺html文件中javascript的方法show
                webView.loadUrl("javascript:show('" + json + "')");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 打電話
        @SuppressWarnings("unused")
        public void call(String phone) {
            Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone));
            startActivity(intent);
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

  3.1 javascript調用java方法:緩存

  上面的內部類JSObject 能夠當作是javascript的對象,而contact能夠當作是該對象的名稱,內部的方法showContacts能夠當作javascript對象的方法。所以對於在上述代碼中"javascript:contact.showContacts()"的寫法表示,執行內部類JSObject網絡

中的方法showContacts。app

  3.2 java調用javascript方法:

  能夠經過WebView控件調用,例如:webView.loadUrl("javascript:show('" + json + "')")則表示,調用javascript中的show方法。

2、緩存

WebView中存在着兩種緩存:網頁數據緩存(存儲打開過的頁面及資源)、H5緩存(即appcache)。

1、網頁緩存

1、緩存構成
/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

2、緩存模式
較難理解的是如下兩個模式:
LOAD_DEFAULT,根據cache-control決定是否從網絡上取數據。
LOAD_CACHE_ELSE_NETWORK,只要本地有,不管是否過時,或者no-cache,都使用緩存中的數據。
如:m.taobao.com的cache-control爲no-cache,在模式LOAD_DEFAULT下,不管如何都會從網絡上取數據,若是沒有網絡,就會出現錯誤頁面;在LOAD_CACHE_ELSE_NETWORK模式下,不管是否有網絡,只要本地有緩存,都使用緩存。本地沒有緩存時才從網絡上獲取。
m.sina.com.cn的cache-control爲max-age=60,在兩種模式下都使用本地緩存數據。

總結:根據以上兩種模式,建議緩存策略爲,判斷是否有網絡,有的話,使用LOAD_DEFAULT,無網絡時,使用LOAD_CACHE_ELSE_NETWORK。


3、清除緩存
clearCache(boolean)。
CacheManager.clear。高版本中須要調用隱藏API。

4、控制大小
無系統API支持。
可選方式:定時統計緩存大小、按時間順序刪除緩存。

2、H5緩存

1、緩存構成
根據setAppCachePath(String appCachePath)提供的路徑,在H5使用緩存過程當中生成的緩存文件。

2、緩存模式
無模式選擇,經過setAppCacheEnabled(boolean flag)設置是否打開。默認關閉,即,H5的緩存沒法使用。

3、清除緩存
找到調用setAppCachePath(String appCachePath)設置緩存的路徑,把它下面的文件所有刪除就OK了。

4、控制大小
經過setAppCacheMaxSize(long appCacheMaxSize)設置緩存最大容量,默認爲Max Integer。
同時,可能經過覆蓋WebChromeClient.onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)來設置緩存超過先前設置的最大容量時的策略。

3、參考網址

如下地址有關於H5緩存的一些內幕,如每一個Application只調用一次WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()被忽略等一系列問題,須要仔細閱讀和實驗。
http://code.google.com/p/android/issues/detail?id=24180

 三 webview一些參數和事件的設置:

1) 設置WebView基本信息: 
    webview.getSettings().setJavaScriptEnabled(true);    //若是訪問的頁面中有Javascript,則webview必須設置支持Javascript。
    requestFocus();//觸摸焦點起做用       
    this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);// 取消滾動條
2)  設置WevView要顯示的網頁:
    互聯網用:webView.loadUrl("http://www.google.com"); 
    本地文件用:webView.loadUrl("file:///android_asset/XX.html");  本地文件存放在:assets文件中
3)   若是但願點擊連接由本身處理,而不是新開Android的系統browser中響應該連接。給WebView添加一個事件監聽對象(WebViewClient)並重寫其中的一些方法:
 shouldOverrideUrlLoading:對網頁中超連接按鈕的響應。當按下某個鏈接時WebViewClient會調用這個方法,並傳遞參數:按下的url。好比當webview內嵌網頁的某個數字被點擊時,它會自動認爲這是一個電話請求,
 會傳遞url:tel:123,若是你不但願如此可經過重寫shouldOverrideUrlLoading函數解決:
4) 另外還有其餘一些可重寫的方法  
4.1 接收到 Http 請求的事件 
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) 
4.2 打開連接前的事件
public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } 
這個函數咱們能夠作不少操做,好比咱們讀取到某些特殊的URL,因而就能夠不打開地址,取消這個操做,進行預先定義的其餘操做,這對一個程序是很是必要的。
 
4.3 載入頁面完成的事件
public void onPageFinished(WebView view, String url){ } 
一樣道理,咱們知道一個頁面載入完成,因而咱們能夠關閉loading條,切換程序動做。
 
4.4 載入頁面開始的事件
public void onPageStarted(WebView view, String url, Bitmap favicon) { } 
這個事件就是開始載入頁面調用的,一般咱們能夠在這設定一個loading的頁面,告訴用戶程序在等待網絡響應。
 
經過這幾個事件,咱們能夠很輕鬆的控制程序操做,一邊用着瀏覽器顯示內容,一邊監控着用戶操做實現咱們須要的各類顯示方式,同時能夠防止用戶產生誤操做。
      
5)       若是用webview點連接看了不少頁之後,若是不作任何處理,點擊系統「Back」鍵,整個瀏覽器會調用finish()而結束自身,若是但願瀏覽的網頁回退而不是退出瀏覽器,須要在當前Activity中處理並消費掉該Back事件。
       覆蓋Activity類的onKeyDown(int keyCoder,KeyEvent event)方法。
public boolean onKeyDown(int keyCoder,KeyEvent event){  
     if(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){  
         webview.goBack();   //goBack()表示返回webView的上一頁面  
         return true;  
     }  
    return false;                     
}         
                           

 支付寶網頁支付

/**
 * 網頁支付
 * @author libin
 *
 */
public class AlipayWebActivity extends Activity {
    private WebView mWebView;
    private static final String TAG = "AlipayWebActivity";
    protected static final int PAY_SUCCESS = 20;
    protected static final int LOAD_FINISH_CODE = 40;
    private static final int DEFAULT_CODE = 50;

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.web); FactoryUtil.getInstance().addActivity(this); mWebView = (WebView) findViewById(R.id.webview); mWebView.setBackgroundColor(0); initial(); } @SuppressLint({"SetJavaScriptEnabled", "HandlerLeak"}) @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void initial() { String url = getIntent().getStringExtra("url"); LogUtil.i(TAG, url); WebSettings webSettings = mWebView.getSettings(); mWebView.requestFocus(); webSettings.setJavaScriptEnabled(true); mWebView.setFocusable(true); webSettings.setBuiltInZoomControls(true); mWebView.setScrollBarStyle(0); if (MobileUtil.getMobileVersion() > 11) { mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } mWebView.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int newProgress) { LogUtil.i(TAG, "newProgress: " + newProgress); if (newProgress == 100) { mUihandler.sendEmptyMessage(LOAD_FINISH_CODE); } super.onProgressChanged(view, newProgress); } }); mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { LogUtil.i(TAG, "URL : " + url); loadUrl(view, url); return true;//中止在當前界面 } public void onPageFinished(WebView view, String url) { LogUtil.i(TAG, "onPageFinished" + url); //trade_status : TRADE_FINISHED if (url.contains("&cmd=success&ptype=url")) { BaseDialogUtil.alertDialog(AlipayWebActivity.this, "提示信息", "支付成功", false, new BaseDialogUtil.DialogOnClickListener() { @Override public void positive(DialogInterface dialoginterface, int id) { FactoryUtil.getInstance().exit(); } @Override public void negative(DialogInterface dialog, int id) { } }); } super.onPageFinished(view, url); } public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); LogUtil.i(TAG, "onPageStarted" + url); } }); loadUrl(mWebView, url); } @SuppressLint("HandlerLeak") private Handler mUihandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case PAY_SUCCESS: clearCache(); FactoryUtil.getInstance().exit(); break; case LOAD_FINISH_CODE: dissDialogGamm(); break; case DEFAULT_CODE: showProgress(AlipayWebActivity.this); } super.handleMessage(msg); } }; private void loadUrl(final WebView webView, final String url) { mUihandler.sendEmptyMessage(DEFAULT_CODE); webView.loadUrl(url); } public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { mWebView.goBack(); return true; } else if (keyCode == KeyEvent.KEYCODE_BACK) { onBackPressed(); return true; } return super.onKeyDown(keyCode, event); } private void clearCache() { mWebView.clearCache(true); mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); finish(); } }
相關文章
相關標籤/搜索