目录
1.
2.AndroidWebView
3.JavascriptInterface
4.code
源码开发环境 JDK1.7
服务端环境 myeclipse10 Java EE6
Android环境 AndroidStudio1.5
Demo CSDN http://download.csdn.net/detail/linjiqian/9734627
1
Android一般使用WebView.loadUrl(url);
加载指定的网页文件展示,并且可以实现javascript脚本与本地java代码的交互。
原生应用在UI效果及运行效率上高于WebView,但是如果原生应用程序更改UI就需要用户更新手机上的APP才能体验到,而WebView充分解决了这个问题,这是混合移动开发最大优势,能把设计师最新的想法及时让用户体验,免去频繁更新APP的烦恼。
混合移动开发时页面大部分可以使用WebView加载前端工程师已经写好的静态页面,而安卓工程师需要准备一些功能接口对安卓手机本身进行操作,前端可以通过js脚本调用本地java提供的接口,实现功能。
静态页面有个打开手电筒的按钮,安卓工程师需写好打开手电筒的逻辑接口供js脚本调用,js脚本本身没有操作安卓API的能力。
2.AndroidWebView
使用WebView加载网页,JavaScript可以和本地Java代码相互调用。
package lwebview.com.thing.www.view;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by ThingLin on 2016/12/8.
*/
public class LWebView extends WebView {
private Activity mActivity;
private ProgressBar mProgressBar;
private TextView mTextViewTitle;
private View mBarLayout;
private WebViewClientBase mWebViewClientBase = new WebViewClientBase();
private WebChromeClientBase mWebChromeClientBase = new WebChromeClientBase();
public LWebView(Context context) {
super(context);
mActivity = (Activity) context;
init(context);
}
@SuppressLint("SetJavaScriptEnabled")
private void init(Context context) {
//a WebSettings object that can be used to control this WebView's setting 该webview的设置
WebSettings webSettings = this.getSettings();
//true if the WebView should execute JavaScript 允许执行js
webSettings.setJavaScriptEnabled(true);
//whether the WebView should support zoom 开启缩放
webSettings.setSupportZoom(true);
//whether to enable support for the viewport meta tag 支持meta标记
webSettings.setUseWideViewPort(true);
//默认情况下,点击webview中的链接,会使用Android系统自带的浏览器打开这个链接。如果希望点击链接继续在我们自己的Browser中响应,必须覆盖 webview的WebViewClient对象
this.setWebViewClient(mWebViewClientBase);
this.setWebChromeClient(mWebChromeClientBase);
this.onResume();
}
private class WebViewClientBase extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// log("默认情况下,点击webview中的链接,会使用Android系统自带的浏览器打开这个链接。如果希望点击链接继续在我们自己的Browser中响应,必须覆盖 webview的WebViewClient对象");
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//Notify the host application that a page has started loading 开始加载页面
log("WebViewClient 开始加载页面 onPageStarted url="+url +" favicon="+favicon);
if(null != mBarLayout){
mBarLayout.setVisibility(View.VISIBLE);
}
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
//Notify the host application that a page has finished loading 页面加载完成
if(null != mBarLayout){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBarLayout.setVisibility(View.GONE);
}
}, 500);
}
super.onPageFinished(view, url);
}
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
//Report an error to the host application. These errors are unrecoverable 出错
log("WebViewClient onReceivedError errorCode="+errorCode +",description="+description+" failingUrl="+failingUrl);
super.onReceivedError(view, errorCode, description, failingUrl);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
log("WebViewClient onReceivedError error= "+error);
super.onReceivedError(view,request,error);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
log("WebViewClient onReceivedSslError error="+error);
super.onReceivedSslError(view, handler, error);
}
@Override
public void onReceivedHttpError(
WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
log("WebViewClient onReceivedSslError ");
super.onReceivedHttpError(view,request,errorResponse);
}
@Override
public void doUpdateVisitedHistory(WebView view, String url,
boolean isReload) {
//Notify the host application to update its visited links database. reload重新加载
log("WebViewClient doUpdateVisitedHistory isReload="+isReload+ " url="+url);
super.doUpdateVisitedHistory(view, url, isReload);
}
}
private class WebChromeClientBase extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
//Tell the host application the current progress of loading a page. 页面加载进度
if(null != mProgressBar){
mProgressBar.setProgress(newProgress);
}
}
@Override
public void onReceivedTitle(WebView view, String title) {
//Notify the host application of a change in the document title 文档标题
if(null != mTextViewTitle){
mTextViewTitle.setText(title);
}
super.onReceivedTitle(view, title);
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg) {
log("WebChromeClient onCreateWindow isUserGesture=" + isUserGesture + " isDialog="+isDialog);
return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
}
}
public void setProgressBarView(ProgressBar progressBar){
this.mProgressBar = progressBar;
}
public void setTitleTextView(TextView textView){
this.mTextViewTitle = textView;
}
public void setBarLayout(View layout){
this.mBarLayout = layout;
}
private void log(String log) {
Log.e("LWebView", log);
}
}
3.JavascriptInterface
通过WebView.addJavascriptInterface(Object object, String name)
为WebView添加可供JS调用的本地方法。
object
参数的实现是一个普通的JavaClass,name
参数会被绑定成为js中window对象的一个属性,该属性指向object
参数,因此js中可以通过window.name.methodName()
调用object
对象有的本地方法。
Java本地调用js函数在android4.4之前使用WebView.loadUrl("javascript:methodName()");
形式,这种形式js函数的返回值要再通过js调用本地java方法传递。android4.4可以使用WebView.evaluateJavascript("javascript:methodName()", new ValueCallback
,js函数返回值在onReceiveValue回调函数中取得,evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。
值得注意的是语言间通信还是一贯采用字符串形式传递参数和值,复杂数据类型使用json数据形式。
Java提供本地方法供JavaScript调用:
mWebView.addJavascriptInterface(new JSCallJavaInterface(),"JSCallJava");
/**
* js调用java本地方法是子线程,需要注意
*/
private final class JSCallJavaInterface{
@JavascriptInterface
public String callJava(final String msg){
mHandler.post(new Runnable() {
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void run() {
Log.d("MainActivity", "JS Call Java msg=" + msg);
String jsmethod = "javascript:javaCallJS(\'JavaCallJSMethod"+msg+"\')";
// android 4.4 开始使用evaluateJavascript调用js函数 ValueCallback获得调用js函数的返回值
// mWebView.loadUrl(jsmethod);
mWebView.evaluateJavascript(jsmethod, new ValueCallback() {
@Override
public void onReceiveValue(String value) {
Log.d("MainActivity", "onReceiveValue value=" + value);
}
});
}
});
return "Java result "+msg;
}
// android 4.4之前使用额外增加一个回调方法让js调用该函数返回函数结果,4.4开始可以使用ValueCallback
@JavascriptInterface
public void onJavaCallJSResult(String msg){
Log.d("MainActivity","java call js result "+msg);
}
}
JavaScript调用Java本地方法:
a标签调用本地java
var result = window.JSCallJava.callJava('hello input click');
span_result.innerHTML = result;
4.code
MainActivity.java
package lwebview.com.thing.www.activity;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import lwebview.com.thing.www.view.LWebView;
import lwebview.com.thing.www.view.R;
public class MainActivity extends Activity {
private LinearLayout mLayout;
private LWebView mWebView;
private ProgressBar mProgressBar;
private TextView mTv_title;
private LinearLayout mBar_layout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initEvent();
}
private void initView() {
mLayout = (LinearLayout)View.inflate(this, R.layout.activity_main, null);
setContentView(mLayout);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mTv_title = (TextView) findViewById(R.id.tv_title);
mBar_layout = (LinearLayout) findViewById(R.id.bar_layout);
mWebView = new LWebView(this);
mWebView.clearCache(true);
mWebView.setBarLayout(mBar_layout);
mWebView.setProgressBarView(mProgressBar);
mWebView.setTitleTextView(mTv_title);
mWebView.setLayoutParams(new RelativeLayout.LayoutParams(-1, -1));
mLayout.addView(mWebView);
}
private void initData() {
mWebView.loadUrl("http://192.168.37.11/wv/w/html1.html");
}
private void initEvent() {
mWebView.addJavascriptInterface(new JSCallJavaInterface(),"JSCallJava");
}
private Handler mHandler = new Handler();
/**
* js调用java本地方法是子线程,需要注意
*/
private final class JSCallJavaInterface{
@JavascriptInterface
public String callJava(final String msg){
mHandler.post(new Runnable() {
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void run() {
Log.d("MainActivity", "JS Call Java msg=" + msg);
String jsmethod = "javascript:javaCallJS(\'JavaCallJSMethod"+msg+"\')";
// android 4.4 开始使用evaluateJavascript调用js函数 ValueCallback获得调用js函数的返回值
// mWebView.loadUrl(jsmethod);
mWebView.evaluateJavascript(jsmethod, new ValueCallback() {
@Override
public void onReceiveValue(String value) {
Log.d("MainActivity", "onReceiveValue value=" + value);
}
});
}
});
return "Java result "+msg;
}
// android 4.4之前使用额外增加一个回调方法让js调用该函数返回函数结果,4.4开始可以使用ValueCallback
@JavascriptInterface
public void onJavaCallJSResult(String msg){
Log.d("MainActivity","java call js result "+msg);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
//canGoBack() 有历史项目 为true 回退
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
html1.html
html1
html2.html
a标签调用本地java
jsCallJavaResult:
javaCallJS: