天天看点

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>
           

继续阅读