天天看點

Android與JS互調

相信大家看完代碼就會明白:

MainActivity.java

package com.example.testjs;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.RenderPriority;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import com.example.testjs.utils.Constant;

/**
 * 實作Android本地Java與JS的互調
 * 1.Android調用JS:
 * 		mWebView.loadUrl("javascript:" + "function()");
 * 
 * 2.JS調用Android:
 * 		a.設定WebView支援JS:mWebView.getSettings().setJavaScriptEnabled(true);
 * 		b.建立一個JS調用代理類:class JavascriptInterfaceProxy
 * 			1).Android 4.2 以後需要将代理類中的方法注解:@JavascriptInterface
 * 		c.mWebView.addJavascriptInterface(new JavascriptInterfaceProxy(), "MyJsInterface");
 * 
 * @author Yanbao_Wu
 *
 */
public class MainActivity extends Activity {
	
	public static final String TAG = MainActivity.class.getSimpleName();
	public static final int SAY_HELLO = 0;
	public static final int SAY_BYEBYE = 1;
	
	private WebView mWebView = null;
	
	@SuppressLint("HandlerLeak") 
	public Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SAY_HELLO:
				Toast.makeText(MainActivity.this, "just say hello from JS", Toast.LENGTH_SHORT).show();
				break;
				
			case SAY_BYEBYE:
				Toast.makeText(MainActivity.this, "Bye-bye called from JS", Toast.LENGTH_SHORT).show();

			default:
				break;
			}
		};
	};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        findId();
        initWebView(mWebView);
    }
    
    /**
     * @author Yanbao_Wu
     */
    public void findId(){
    	mWebView = (WebView) findViewById(R.id.webview_contend);
    }
    
    /**
     * Init the web settings.
     * 
     * @author Yanbao_Wu
     */
    @SuppressLint("SetJavaScriptEnabled") 
    public void initWebView(WebView mWebView){
    	mWebView.getSettings().setJavaScriptEnabled(true);
		mWebView.getSettings().setRenderPriority(RenderPriority.HIGH);
		mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
		// 設定可以使用localStorage
		mWebView.getSettings().setDomStorageEnabled(true);
		// 應用可以有資料庫
		mWebView.getSettings().setDatabaseEnabled(true);
		String cacheDirPath = getFilesDir().getAbsolutePath() + Constant.APP_H5_CACHE_DIRNAME;
		// 設定 H5緩存目錄
		mWebView.getSettings().setAppCachePath(cacheDirPath);
		// 應用可以有緩存
		mWebView.getSettings().setAppCacheEnabled(true);
		
		/**
		 *  注意:
		 * 		由于4.4之前使用的是WebKit核心,而4.4使用的是chromium核心,
		 * 	是以WebViewClient中的方法調用的次數和順序會不一樣,如果按照正常的邏輯處理,
		 *  可能會出現一些問題,這裡可以做些版本相容性判斷。
		 */
		mWebView.setWebViewClient(new WebViewClient(){
			@Override
			public void onPageStarted(WebView view, String url, Bitmap favicon) {
				// 自定義加載過程中的動畫,例如一個loading的界面
				super.onPageStarted(view, url, favicon);
			}
			
			@Override
			public void onPageFinished(WebView view, String url) {
				// TODO Auto-generated method stub
				super.onPageFinished(view, url);
			}
			
			@Override
			public void onReceivedError(WebView view, int errorCode,
					String description, String failingUrl) {
				// 可以自定義錯誤頁面覆寫WebView
				super.onReceivedError(view, errorCode, description, failingUrl);
			}
		});
		
		mWebView.setWebChromeClient(new WebChromeClient(){
			@Override
			public void onReceivedTitle(WebView view, String title) {
				/*
				 * 可以擷取Web頁面的Title來設定移動端的Title,
				 * 但是在部分手機上,調用goBack()方法時,不會觸發onReceivedTitle()方法是以onTitle沒有變化,
				 * 是以需要做簡單的處理:
				 * 		1.已知WebView最多隻有二級頁面,不存在更深層次的頁面時,可以在調用goBack的時候,直接将Title設定回去就可以了
				 * 		2.當WebView的頁面層次不确定時,可能會有很深層次的頁面,這時需要我們手動的去維護對應頁面的Title的一個棧了,我們可以
				 * 		使用HashMap去維護這樣的(url,title)的棧,當進去新的頁面時直接加到Map中即可,當回退是進行退棧操作就可以了
				 * 當WebView加載出錯時,Title會顯示"找不到該網頁",是以需要我們在onReceivedError方法中自行更改Title
				 */
				super.onReceivedTitle(view, title);
			}
		});
		
		/*
		 * 第一個參數代理類的對象,第二個參數供JS調用方法的對象名稱
		 * JS調用的方式大緻可以通過:
		 * 		MyJsInterface.testJS();
		 * 		MyJsInterface.testLowVerssion(); // Android 4.2以後不能調用
		 */
		mWebView.addJavascriptInterface(new JavascriptInterfaceProxy(), "MyJsInterface");
		
		mWebView.loadUrl("file:///android_asset/js.html");
    }
    
    /**
     * The proxy class which used by JS.
     * 
     * @author Yanbao_Wu
     */
    public class JavascriptInterfaceProxy{
    	
    	@JavascriptInterface
    	public void testJS(){
    		mHandler.sendEmptyMessage(SAY_HELLO);
    		mWebView.loadUrl("javascript:wave()");
    	}
    	
    	// 4.2以後不能被JS調用
    	public void testLowVerssion(){
    		mHandler.sendEmptyMessage(SAY_BYEBYE);
    	}
    }
    
    @Override
    protected void onDestroy() {
//		如果WebView中加載音頻後退出Activity音頻聲音無法消失,可通過以下方法解決
//    	rootLayout.removeView(webView);  
//    	webView.destroy();
    	super.onDestroy();
    }
}
           

下面是一個HTML的代碼,放在項目的assets目錄下:

<html>
        <script language="javascript">
        		
                function wave() {}
        </script>
        <body>
            <a onClick="MyJsInterface.testJS()">
                                <br>
                                Click me!
            </a>
        </body>
</html>
           

繼續閱讀