Js代码和Java代码之间的互相调用了

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

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

在讲解之前,让我们先把项目跑起来 
效果图: 
Js代码和Java代码之间的互相调用了_第1张图片

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


<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>JSTesttitle>
    <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传值给ToastButton>
body>
html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

最后就是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 + "')");
        }
    }    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

还有布局代码:


<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

一、JavaScript调用Android中的方法

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

对应的js代码:

function getMessage(){
    var message = document.getElementById("jsinput");
    contact.showToast(message.value);
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

对应的java代码:

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

其中的“contact”其实指的就是我们在java代码中定义的JsObject类 
他俩通过以下方法实现绑定:

mWebView.addJavascriptInterface(jsobj, "contact");
  • 1
  • 1
  • 第一个参数传入的是一个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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

对应的java代码:

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

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

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

“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);
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果需要把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());
  • 1
  • 1

当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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

你可能感兴趣的:(Js代码和Java代码之间的互相调用了)