最近在做webview与js通信,遇到一些坑,记录一下
首先,webview与js确定一个类名,作为通信的依据,比如"android",webview设置
webSettings.setJavaScriptEnabled(true) 表示让WebView支持调用Js;
webView.addJavascriptInterface(new AndroidtoJs(this), "android");
写用于让js调用的方法,比如
public class AndroidtoJs extends Object
{
Activity activity;
public AndroidtoJs(Activity activity)
{
this.activity = activity;
}
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void getimg(String bean)
{
Log.e("acntiontype", bean);
Gson gson = new Gson();
GetImageBean imageBean = new GetImageBean();
try
{
imageBean = gson.fromJson(bean, GetImageBean.class);
}
catch (Exception e)
{
e.printStackTrace();
}
methodtype = imageBean.getMethodtype();
if (imageBean.getMethodtype().equals("1"))
{//照片
runOnUiThread(new Runnable()
{
@Override
public void run()
{
//选择相册或相机的对话框
showSignaturePopWindow();
}
});
}
}
}
js调用app的方法名getimg,传入参数,webview会根据参数,进行相应的操作,
坑1:在js调用android定义的方法中,操作UI,会报 java.lang.IllegalStateException: Calling View methods on another thread than the UI thread.at 异常,这个主要是Android的相关View和控件不是线程安全的,所以将js调用我们的代码放在UI线程中
runOnUiThread(new Runnable()
{
@Override
public void run()
{
showSignaturePopWindow();
}
});
js代码里边,可以写
android.getimg(bean)之类的,来调用android方法
app调用js方法名setImg(String name)
webView.loadUrl("javascript:setImg(" + result + ")");
注:调用js带参数的方法,参数要用单引号,比如
//在android调用js有参的函数的时候参数要加单引号
webView.loadUrl("javascript:message('" + name + "')");
坑2:如果传的参数是图片的base64,在网页不显示的话,可以在base64之前加上"data:image/jpeg;base64,"
4.4以上版本
webView.evaluateJavascript("javascript:jsMethod()", new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//value即为js返回值
}
});
4.4以下版本
通过loadUrl调用js的alert方法,然后在android端监听alert弹出
webView.loadUrl("javascript:alert(jsMethod())");
public class MyWebChromeClient extends WebChromeClient
{
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result)
{
Log.i(TAG, "onJsAlert: " + message);
if (message.contains("false"))
{
showBackDialog();
//message即为返回值
result.confirm();
return true;
}
/* //true,拦截JavaScript的弹窗。如果拦截了,不会出现弹窗。
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result)
{
Log.i(TAG, "onJsConfirm: " + message);
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
{
Log.i(TAG, "onJsPrompt: " + message);
return super.onJsPrompt(view, url, message, defaultValue, result);
}
@Override
public void onReceivedTitle(WebView view, String title)
{
super.onReceivedTitle(view, title);
}
}
我没有找到在android中判断调用的js是否存在的方法,就是用了try catch,在异常中处理方法不存在的逻辑
有的时候,在网页中操作,跳转到其他网页,按返回键,应该一层一层返回到首页,如果已经是首页了,点击返回,应该跳出该页面,在返回事件中,通过webView.canGoBack()来判断,通过 webView.goBack();返回
if (webView.canGoBack())
{
webView.goBack();
}
else
{
super.onBackPressed();
}
如果webview中,需要根据需要切换url,不清空之前浏览的历史的话,会返回到之前url的页面,清空历史,就在WebViewClient的onPageFinished中进行
//是否切换url,如果切换了,清空历史
private boolean isReloadData = false;
.....
webView.clearHistory();
webView.clearCache(true);
isReloadData = true;
webView.loadUrl(url);
...
@Override
public void onPageFinished(WebView view, String url)
{ //重载url以后,清空历史,设置为初始值,如果一直清空,canGoBack()会一直返回false
if(isReloadData){
view.clearHistory();
}
isReloadData = false;
}
这里加一个isReloadData判断的原因,是只有在切换url的时候,把之前的历史清空,其他的不进行操作,加载url,然后点击页面中的一些操作,跳转到其他url,如果把之前的都清空了,canGoBack()会一直返回false,就没办法返回到首页
参考文章
Android和H5交互一篇就够了
在加载下一个WebView之前,如何清除以前的WebView内容
WebView调用js方法获取返回值的完美解决方案
混合开发-Android 判断 js 方法是否存在
Android WebView 不支持 H5 input type=“file” 解决方法
WebView中JS调用Android Method 遇到的坑整理