WebView进阶(一) :Android WebView与JS互相调用

前言:

  这是本人的第一篇博客,有不正确或者不规范之处,敬请见谅!回归正文,由于最近在做Android端与H5界面之间的交互,之前没做过类似的功能,在网上找了很多资料,说法不一,而且实现起来也各有不同。
  我在做功能之前,自己动手做了一个小Demo,当时是用的H5界面中的JavaScript调用Android端的方法进行实现,这个方法是可行的,也就是此文的方法二。
  但是在实际开发中,由于要和IOS统一, 而IOS那边当时想用url的方式,也就是此文要说的方法一,开始他说IOS端做不到用我说的方法二(即调用方法的方式),此时又不能说让web端实现两套代码或者实现判断,这毕竟是不好的。所以我们一开始就选择了通过url的方式。
  后来他通过查阅资料,发现也可以通过调用方法的方式去实现。所以最后的总结就是,方法一和方法二都是可以使用的,但我们开发的时候选择了方法一。下面我们就从方法一开始谈起。

方法一:

项目地址:https://github.com/fsrmeng/WebView-Master
简书地址:http://www.jianshu.com/p/798f4eeb7d04
  其实通过url的方式,就是相当于定义协议规则,也就是条件,我们拿到这个条件,进行判断,实现自己的逻辑代码。这里有一个关键的web前端代码: window.location.href=“url”,此处的url就是我们定义的协议规则。一旦H5走到上段代码,Android WebView就会调用shouldOverrideUrlLoading(WebView view, String url)
  我们定义了url 为“app://showgame.toast?”+JSON.stringify(json),而通过获取到app这个字段来判断是否是http协议,这里的json其实就是传递过来的参数,代码如下:

mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                try {
                    //这一步很关键,web端传过来的有可能是其它编码格式
                    url = URLDecoder.decode(url, "utf-8");

                    //通过判断拦截到的url是否含有pre,来辨别是http请求还是调用android方法的请求
                    String[] parts = url.split("[?]");
                    String code = parts[0];

                    String pre = "app://";
                    if (!url.contains(pre)) {
                        //该url是http请求,用webview加载url
                        view.loadUrl(url);
                        return true;
                    }

                    //该url是调用android方法的请求,通过解析url中的参数来执行相应方法
                    String params = JavaScriptManager.getJSParams(url, code);
                    //在这里实现各种android方法的逻辑代码
                    JavaScriptManager.invokeAndroidMethod(mContext, code, params, mWebView);
                    return true;

                } catch (Exception e) {
                    e.printStackTrace();
                    view.loadUrl(url);
                    return true;
                }
            }
        });

  这里我创建了一个管理类JavaScriptManager,并在其中创建了两个方法,一个是getJSParams(url, code),另一个是invokeAndroid(mContext, code, params, mWebView)
  接下来再看JavaScriptManager类两个方法的实现:

/**
     * 获取JS传来的参数
     * @param url
     * @param pre
     * @return
     */
    public static String getJSParams(String url, String pre) {
        String params = "";
        if (url.contains(pre)) {
            int index = url.indexOf(pre);
            int end = index + pre.length();
            params = url.substring(end + 1);
        }
        return params;
    }
/**
     *JS调用Android中的方法,根据code去判断调用具体的方法
     * @param mContext
     * @param code
     * @param params
     * @param mWebView
     */
    public static void invokeAndroidMethod(Context mContext, String code, String params, final WebView mWebView) {
        if (code.equals("app://showgame.toast")) {
            try {
                JSONObject json = new JSONObject(params);
                String toast = json.optString("data");
                Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return;
        }else if (code.equals("app://showgame.getHotelData")) {
            try {
                final JSONObject json = new JSONObject(params);
                final String callback = json.optString("callback");
                json.put("hotel_name", "维多利亚大酒店");
                json.put("order_status", "已支付");
                json.put("orderId", "201612291809626");
                json.put("seller", "携程");
                json.put("expire_time", "2017年1月6日 23:00");
                json.put("price", "688.0");
                json.put("back_price", "128.0");
                json.put("pay_tpye", "支付宝支付");
                json.put("room_size", "3间房");
                json.put("room_count", "3");
                json.put("in_date", "2017年1月6日 12:00");
                json.put("out_date", "2017年1月8日 12:00");
                json.put("contact", "赵子龙先生");
                json.put("phone", "18888888888");
                json.put("server_phone", "0755-85699309");
                json.put("address", "深圳市宝安区兴东地铁站旁边");

                invokeJavaScript(mContext, callback, json.toString(), mWebView);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return;
        }
    }

这里封装的方法很实用,以后诸如类似的JS调用Android端方法的话,就可以定义类似的协议,从而只需要在invokeAndroidMethod(Context mContext, String code, String params, final WebView mWebView)方法中,根据code,通过协议判断,从而实现不同的逻辑代码,也就实现了JS调用Android端不同的方法。
注意:这里还有一点需要特别说明,那就是我们需要让自己的WebView支持JS:

mWebView.getSettings().setJavaScriptEnabled(true);

  其实开发中遇到的远没有这么简单,开始是写了Demo能运行,但是一旦和web前端联调的时候,总是会出现各种各样的问题,这里将总结以下几点:
  1.运行起来后,发现并不会走shouldOverrideUrlLoading()方法,这时候不要怀疑自己的程序出现问题了,因为既然Demo能运行起来,那就肯定不是我们这边的问题,而是web端的问题(即使浏览器、IOS或者部分安卓手机能运行),其实遇到这个问题,我们也是研究了很长时间,但是最终找到了问题的所在,就是可能web端需要把所有的代码都写在一个HTML文件中,而不是通过引用JS文件的方式,最好也不要用什么框架,但是问题所存在的原因,我不知道,因为我并不懂web端,其实web端同事也不知道!
  2.解决了第一个问题之后,应该就能调用我们上面说得这个方法了,但是此时可能会发现传过来的参数中文乱码了。当时web端通过各种编码格式,都行不通,后来我在我这边拿到这个url,进行utf-8编码,这样就不会乱码了。也就是我在shouldOverrideUrlLoading()中写得:

//这一步很关键,web端传过来的有可能是其它编码格式
url = URLDecoder.decode(url, "utf-8");

写在最后

  本文提供了Android WebView与JS互相调用的方法一,方法二将在我接下来的博客中展示,敬请期待!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值