专栏首页恩蓝脚本Android中实现WebView和JavaScript的互相调用详解

Android中实现WebView和JavaScript的互相调用详解

前言

很多复杂的UI界面,在Android中需要配合大量xml代码和java代码实现,而使用HTML5可以非常轻松的实现出来,而且具有很好的跨平台特性,让我们不必为了多个平台而重写代码,H5学习成本也较低,上手快。虽然从目前来说H5在Android系统中的速度可能还欠佳一些,但相信随着手机的性能不断的提高,这些问题都会被解决

使用H5开发Android的UI界面,最重要的就是如何实现Js代码和Java代码之间的互相调用了

在讲解之前,让我们先把项目跑起来

效果图:

准备好index.html文件,将它放入Android工程下的assets文件夹中:

<!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 JSTest</title 
 <script src="app.js" </script 
</head 
<body 
<table border="1" width="100%" id="table" cellspacing="0" 
 <tr 
  <td width="50%" align="center" 姓名</td 
  <td width="50%" align="center" 电话</td 
 </tr 
</table 
<hr 
<input id="jsinput" 
<Button onclick="getMessage()" js传值给Toast</Button 
</body 
</html 

JavaScript的代码我单独写在一个js文件中了,把app.js文件也放入assets文件夹中:

function getMessage(){
 var message = document.getElementById("jsinput");
 contact.showToast(message.value);
}
function addPerson(persons){
 var personObjs = eval(persons);
 var table = document.getElementById("table");
 for(var i=0; i < personObjs.length; i++){
  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 = personObjs[i].name;
  td2.innerHTML = personObjs[i].phone;
 }
}

最后就是Java代码

public class MainActivity extends AppCompatActivity {
 private WebView mWebView;
 private Button mJsMethodBtn;
 private JsObject jsobj;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mJsMethodBtn = (Button) findViewById(R.id.btn_js_method);
  mWebView = (WebView) findViewById(R.id.web_view);
  mWebView.loadUrl("file:///android_asset/index.html");
  WebSettings setting = mWebView.getSettings();
  setting.setJavaScriptEnabled(true);
  setting.setDefaultTextEncodingName("utf-8");
  jsobj = new JsObject();
  mWebView.addJavascriptInterface(jsobj, "contact");
  mJsMethodBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    // 添加一个联系人
    jsobj.addPerson();
   }
  });
 }

 private class JsObject {
  // 此方法被js调用
  @JavascriptInterface
  public void showToast(String message) {
   Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
  }
  // 在Web页面增加一个联系人
  public void addPerson() {
   String json = "[{\"name\":\"zwt\",\"phone\":\"15949999999\"}]";
   mWebView.loadUrl("javascript:addPerson('" + json + "')");
  }
 } 
}

还有布局代码:

<?xml version="1.0" encoding="utf-8"? 
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="#EED5B7"
 android:orientation="vertical" 

 <WebView
  android:id="@+id/web_view"
  android:layout_width="match_parent"
  android:layout_height="360dp"/ 

 <Button
  android:id="@+id/btn_js_method"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="调用js方法"/ 
</LinearLayout 

一、JavaScript调用Android中的方法

这里实现的场景是点击Web页面中的Button,把input中输入的数据传递给Android系统,并通过Toast显示出来

对应的js代码:

function getMessage(){
 var message = document.getElementById("jsinput");
 contact.showToast(message.value);
}

对应的java代码:

// 此方法被js调用
@JavascriptInterface
public void showToast(String message) {
 Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
}

其中的“contact”其实指的就是我们在java代码中定义的JsObject类

他俩通过以下方法实现绑定:

mWebView.addJavascriptInterface(jsobj, "contact");

第一个参数传入的是一个java对象,第二参数是指定对应的js里调用该类时需要使用的自定义别名,这个方法的作用就是将一个Java对象和JavaScript联系起来

这里需要注意个问题,在SDK17以上的版本中,google为了安全考虑,只允许js调用带有@JavascriptInterface注解的Java方法,所以我们要给被js调用的java方法前加上@JavascriptInterface注解

二、Android调用JavaScript中的方法

用户点击Android中的Button控件后,传一个json数据给JavaScript方法,js解析json数据后添加一个新的联系人显示在Web页面上

对应的js代码:

function addPerson(persons){
 var personObjs = eval(persons);
 var table = document.getElementById("table");
 for(var i=0; i < personObjs.length; i++){
  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 = personObjs[i].name;
  td2.innerHTML = personObjs[i].phone;
 }
}

对应的java代码:

// 在Web页面增加一个联系人
public void addPerson() {
 String json = "[{\"name\":\"zwt\",\"phone\":\"15949999999\"}]";
 mWebView.loadUrl("javascript:addPerson('" + json + "')");
}

想要调用JavaScript中的某个方法,使用以下方法的标准格式就可以了:

mWebView.loadUrl("javascript:xxxMethod()");

“xxxMethod()”指的是JavaScript中的某个方法,如需调用其它方法,只要把后面的xxxMethod()替换成js中对应的方法就好

三、常见问题

1.Android与js互调不成功

  • 给WebView的setJavaScriptEnabled方法设置为true,使其允许js代码执行
  • 在API高于17的版本上,需要被js调用的java方法前加上@JavascriptInterface
  • 检查js中的别名是否写错,调用java方法时类的别名,一定要是mWebView.addJavascriptInterface(jsobj, “contact”);里面定义的别名

2.网页的alert弹不出

需要重写WebChromeClient中的onJsAlert()方法

mWebView.setWebChromeClient(new WebChromeClient() {
 @Override
 public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
  return super.onJsAlert(view, url, message, result);
 }
});

如果需要把web页面的alert弹出框替换成Android的AlertDialog,可以在onJsAlert()方法里进行重写,并设置return为true

3.Js调用java方法修改UI界面不成功

只要明白这一点:js调用的java方法,其实是运行在另外一个子线程WebViewCoreThread中 测试一下:把以下语句分别放在Activity的onCreate()方法里和被js调用的java方法中

Log.e(TAG, "运行线程name- " + Thread.currentThread().getName());

当onCreate执行时运行的log:

运行线程name- main

当JsObject类中的方法运行时的log:

运行线程name- WebViewCoreThread

很明显,子线程不允许修改主线程UI,所以我们想通过js调用java代码直接修改UI界面的做法是不被允许的 如果需要修改,可以通过Handler机制去解决

4.如何让手机的返回键跳到上一个Web页面

如果不对手机系统的返回键进行处理,那么我们按返回键会直接关闭当前Activity,而不会回到上一个Web页面 解决这个问题,我们可以重写Activity中的onBackPressed()方法:

@Override
public void onBackPressed() {
 super.onBackPressed();
 if (mWebView.canGoBack()) {
  mWebView.goBack();
 } else {
  finish();
 }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对ZaLou.Cn的支持。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android WebView的使用方法总结

    1、打开指定url网页; 2、点击链接可以跳转到下一页,并更新标题; 3、按back键或左箭头可以返回上一页; 4、当webview显示的是第一级url时...

    砸漏
  • Android中TabLayout添加小红点的示例代码

    本文介绍了Android中TabLayout添加小红点的示例代码,分享给大家,具体如下

    砸漏
  • Android初学者必须知道的10个技术

    如果你是往Android开发路上走,那么以下的10个技术功能实现是你必须要会的,来看看。

    砸漏
  • 傀儡SQL的使用(快速寻找可注入网站)

    大家都听过SQL注入,但是对于新手来说,想要从网上众多网站中寻找到自己想要找到的目标并不是那么的容易,所以对于新手来说到底应该怎么更好的找到注入点呢...

    网e渗透安全部
  • css3的一些新属性总结

    box-sizing规定了盒子的计算方式,常用于消除hover时,盒子之间的影响,有三个属性:

    一个淡定的打工菜鸟
  • <fieldset>标签

    <fieldset> 标签用于奖表单中的元素进行分组。该元素把 HTML 表单的一部分内容进行打包,生成一组与表单相关的字段。

    Html5知典
  • 如何提高你的能力,给年轻程序员的几条建议【大牛经验】

    一转眼工作已有8年,前两天公司一位初入职场的同事希望我给一些建议与经验。我觉得这个话题很有价值,这里以个人的想法与经历写成此文,希望给年轻的开发者们一些启发。

    Java帮帮
  • Hybird App(一)----第一次接触

    之前一直在做JAVA的项目,最近要开发移动端,对App的开发刚开始的时候是没有任何概念的,有接触也就是玩手机用过的N多App,这算是真正意义山的第一次和App...

    令仔很忙
  • 在国内,35岁以上的程序员的出路有哪些?都在从事什么行业?

    自身作为35+程序员,还在一线写代码,说到对自己年龄的担忧也是时常提醒自己不要放弃了继续学习新的东西,毕竟年龄大了年轻点的程序员时刻都在成长,所以这种无形的压力...

    程序员互动联盟
  • Kotlin 使用 Spring WebFlux 实现响应式编程 Kotlin 使用 Spring WebFlux 实现响应式编程参考资料

    IBM的研究称,整个人类文明所获得的全部数据中,有90%是过去两年内产生的。在此背景下,包括NoSQL,Hadoop, Spark, Storm, Kylin在...

    一个会写诗的程序员

扫码关注云+社区

领取腾讯云代金券