Android中WebView与JS的交互

上家公司的主打产品是一个游戏社交类应用,里边有一套用户等级系统和一套付费系统。由于这个两套系统的界面不是固定的,而且支持的状态也根据用户的等级而有所不同,有时还需要根据节日或者当前推广的内容进行动态的调整。所以采用了webview加载页面的方式来实现。当然就免除不了会有Android原生方法与JS方法互相调用的情况。这里通过一个简单的例子阐述互调的实现方法,还有注意事项。

实现

1 定义一个提供方法给JS调用的类

final class TaskInterface {

    private Context context;

    public TaskInterface(Context context) {
        this.context = context;
    }

    @JavascriptInterface
    public void showString(final String message) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(
                        context);
                builder.setTitle(getString(R.string.app_name));
                builder.setMessage(message);
                builder.setPositiveButton("确定", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                builder.show();
            }
        });
    }

    @JavascriptInterface
    public void showNum(final int num) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(
                        context);
                builder.setTitle(getString(R.string.app_name));
                builder.setMessage("js传递给android的参数为:" + num);
                builder.setPositiveButton("确定", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                builder.show();
            }
        });
    }

    @JavascriptInterface
    public void showJsonString(final String object) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(
                        context);
                builder.setTitle(getString(R.string.app_name));
                JSONObject jsonObject;
                try {
                    jsonObject = new JSONObject(object);
                    builder.setMessage("name的值为:"
                            + jsonObject.getString("name") + "||||"
                            + "age的值为:" + jsonObject.getString("age"));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                builder.setPositiveButton("确定", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                builder.show();
            }
        });
    }
}

这里定义了三个供JS调用的方法,需要为每个方法添加@JavascriptInterface:因为安全问题,在Android4.2以上版本,JS只能访问带有 @JavascriptInterface注解的Java函数

2 将该类的实例注入到WebView中

WebSettings webSettings = webView.getSettings();
// 需要与JS交互,必须先设置为true
webSettings.setJavaScriptEnabled(true);
// 将提供方法给JS调用的实例注入到WebView中
// Task:可以理解为JS使用该实例的一个标识
webView.addJavascriptInterface(new TaskInterface(this), "Task");

3 在JS调用Android提供的方法

// 有两种常用调用形式
javascript:Task.showString('传递简单字符串')
window.Task.showNum(324343)

4 WebView调用JS的方法

// callJsMethod()为JS定义的方法
webView.loadUrl("javascript:callJsMethod()");

JS调用Android方法可传递的参数类型

<!DOCTYPE html>
<html>
<head>
    <title>Android与JS互调</title>
</head>
<body>
    <h1 align="center">Android与JS互调</h1>
    <script>
        function callJsMethod(){
            document.getElementById("div").innerHTML+="<br\>这是android调用js方法动态添加的内容";
        }  
    </script>

    <p></p>
    <h3>Android调用JS动态添加的标签</h3>
    <p></p>
    <div onclick="window.Task.showNum(324343)"><u>js调用android方法:传递整形数据</u></div>
    <p></p>
    <div onclick="javascript:Task.showString('传递简单字符串')"><u>js调用android方法:传递简单字符串</u></div>
    <p></p>
    <div onclick="act.showObject()"><u>js调用android方法:传递json格式字符串</u></div>
    <p></p>
    <div onclick="window.Task.showString('js调用android方法的另一种形式:window.Task.showDialog')"><u>js调用android方法的另一种形式</u></div>
    <p></p>

    <p></p>
    <h3>Android调用JS动态添加的标签</h3>
    <div id="div"/>

</body>
    <script>

        var act = {
            showObject:function(){
                var params = {
                    "name": "jacky",
                    "age": 123456
                };
                params = JSON.stringify(params);
                javascript:Task.showJsonString(params);
            }
        };
    </script>
</html>

该html文件给出了三种格式:
整形数据,可以直接获取到
字符串,也可以获取到
复杂数据:拼装成Json格式,再调用JS的方法转换成字符串后返回

3 总结

调用的过程中,经常会遇到没有正确调用的情况。但由于又没有错误的提示,难免会给调试增加难度。这里给出几点遇到过的坑:

1 4.2以上的系统需要增加@JavascriptInterface注解

2 JS调用的Android方法,内部的实现需要放在主线程进行

3 JS调用Java函数时,传递的参数格式有误也会导致调用不正常

4 官方文档

其实,官方对于一些常用的api都会有详细的说明或者解释,我们可以多查看这些说明,对于我们的开发有很大的帮助。这是给出addJavascriptInterface方法的官方说明。其实挺详细,对于一般的用法都有说明

/**
     * Injects the supplied Java object into this WebView. The object is
     * injected into the JavaScript context of the main frame, using the
     * supplied name. This allows the Java object's methods to be
     * accessed from JavaScript. For applications targeted to API
     * level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
     * and above, only public methods that are annotated with
     * {@link android.webkit.JavascriptInterface} can be accessed from JavaScript.
     * For applications targeted to API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below,
     * all public methods (including the inherited ones) can be accessed, see the
     * important security note below for implications.
     * <p> Note that injected objects will not
     * appear in JavaScript until the page is next (re)loaded. For example:
     * <pre>
     * class JsObject {
     *    {@literal @}JavascriptInterface
     *    public String toString() { return "injectedObject"; }
     * }
     * webView.addJavascriptInterface(new JsObject(), "injectedObject");
     * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
     * webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
     * <p>
     * <strong>IMPORTANT:</strong>
     * <ul>
     * <li> This method can be used to allow JavaScript to control the host
     * application. This is a powerful feature, but also presents a security
     * risk for apps targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or earlier.
     * Apps that target a version later than {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
     * are still vulnerable if the app runs on a device running Android earlier than 4.2.
     * The most secure way to use this method is to target {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
     * and to ensure the method is called only when running on Android 4.2 or later.
     * With these older versions, JavaScript could use reflection to access an
     * injected object's public fields. Use of this method in a WebView
     * containing untrusted content could allow an attacker to manipulate the
     * host application in unintended ways, executing Java code with the
     * permissions of the host application. Use extreme care when using this
     * method in a WebView which could contain untrusted content.</li>
     * <li> JavaScript interacts with Java object on a private, background
     * thread of this WebView. Care is therefore required to maintain thread
     * safety.
     * </li>
     * <li> The Java object's fields are not accessible.</li>
     * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#LOLLIPOP}
     * and above, methods of injected Java objects are enumerable from
     * JavaScript.</li>
     * </ul>
     *
     * @param object the Java object to inject into this WebView's JavaScript
     *               context. Null values are ignored.
     * @param name the name used to expose the object in JavaScript
     */
    public void addJavascriptInterface(Object object, String name) {
        checkThread();
        mProvider.addJavascriptInterface(object, name);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值