• 客户端相关知识学习(三)之Android原生与H5交互的实现


    Android原生与H5交互的实现

    H5调用原生的方式

    方式可能有多种,根据开发经验,接触过两种方式。

    方法一:Android向H5注入全局js对象,也就是H5调Android

    1.首先对WebView进行初始化

    WebSettings settings = webview.getSettings();

    settings.setJavaScriptEnabled(true); //允许在WebView中使用js

    2.创建一个类JavaScriptMetod,专门用来给js提供可调用的方法

    3.创建该类的构造方法,提供两个参数,WebView对象和上下文对象

    private Context mContext;

    private WebView mWebView;

    public JavaScriptMethod(Context context, WebView webView) {

      mContext = context;

      mWebView = webView;

    }

    4.创建一个字符串常量,作为android与js通信的接口,即字符串映射对象

    public static final String JAVAINTERFACE = "javaInterface";

    5.接下来就是创建给js调用的方法,方法的参数接收一个json字符串(注意:在Android4.2之后,为了提高代码安全性,方法必须使用注解@JavascriptInterface,否则无法调用)

    @JavascriptInterface

    //andorid4.2(包括android4.2)以上,如果不写该注解,js无法调用android方法

    public void showToast(String json){

      Toast.makeText(context, json, Toast.LENGTH_SHORT).show();

    }

    6.在WebView初始化代码中执行如下代码

    //创建上面创建类的对象

    JavaScriptMetod m = new JavaScriptMetod(this, webview);

    //其实就是告诉js,我提供给哪个对象给你调用,这样js就可以调用对象里面的方法

    //第二个参数就是该类中的字符串常量

    webview.addJavascriptInterface(m, JavaScriptMetod.javaInterface);

    现在,在js中就可以调用JavaScriptMetod中的方法了,调用方式如下

    //参数一般为json格式

    var json = {"name":"javascript"};

    //javaInterface是上面所说的字符串映射对象

    window.javaInterface.showToast(JSON.stringify(json));

    网络上介绍js与android原生交互的文章里,大部分都是上面这种方式,但是这种方式并不适用于ios,也就是说,window.javaInterface.showToast(JSON.stringify(json))这样的js代码并不适用于ios,如果用以上的方法,就得分别为android和ios各

    写一套js代码。这样很显然是不太合理的,所以在实际开发中,一般都使用接下来的第二种方法。

    方法二:H5发起自定义协议请求,Android拦截请求,再由Android调用H5中的回调函数

    这种方法实现的思想是js发出一个url请求,并将所需的参数添加到该url中。android端通过webView.setWebViewClient()拦截url,解析url中携带的参数,并根据参数信息进行相应的操作。

    1.与方法一相同,首先都需要对webview进行初始化

    WebSettings settings = webview.getSettings();

    settings.setJavaScriptEnabled(true); //允许在WebView中使用js 

    2.首先看js中的代码是怎么写的

    $("#showtoast").click(function () {

      var json = {"data": "I am a toast"};

      window.location.href="protocol://android?code=toast&data="+JSON.stringify(json);

    });

    $("#call").click(function () {

      var json = {"data": "10086"};

      window.location.href="protocol://android?code=call&data="+JSON.stringify(json);

    });

    这里定义两个点击事件,分别控制android显示toast和打电话的操作。其中,protocol://android为自定义的H5与android间的通信协议,与http请求进行区分。code规定了要进行的操作,data为传输的数据。

    3.android中的代码

    webView.setWebViewClient(new WebViewClient() {

      @Override

      public boolean shouldOverrideUrlLoading(WebView view, String url) {

      /**

      * 通过判断拦截到的url是否含有pre,来辨别是http请求还是调用android方法的请求

      */

      String pre = "protocol://android";

      if (!url.contains(pre)) {

        //该url是http请求,用webview加载url

        return false;

      }

      //该url是调用android方法的请求,通过解析url中的参数来执行相应方法

      Map map = getParamsMap(url, pre);

        String code = map.get("code");

        String data = map.get("data");

        parseCode(code, data);

        return true;

      }

    });

    其中,getParamsMap()方法从拦截到的url解析出code,data参数,parseCode()方法将根据不同的code进行相应的操作,代码如下:

    private Map getParamsMap(String url, String pre) {

      ArrayMap queryStringMap = new ArrayMap<>();

        if (url.contains(pre)) {

          int index = url.indexOf(pre);

          int end = index + pre.length();

          String queryString = url.substring(end + 1);

          String[] queryStringSplit = queryString.split("&");

          String[] queryStringParam;

          for (String qs : queryStringSplit) {

            if (qs.toLowerCase().startsWith("data=")) {

              //单独处理data项,避免data内部的&被拆分

              int dataIndex = queryString.indexOf("data=");

              String dataValue = queryString.substring(dataIndex + 5);

              queryStringMap.put("data", dataValue);

            } else {

              queryStringParam = qs.split("=");

              String value = "";

                if (queryStringParam.length > 1) {

                  //避免后台有时候不传值,如“key=”这种

                  value = queryStringParam[1];

                }

              queryStringMap.put(queryStringParam[0].toLowerCase(), value);

            }

          }

        }

      return queryStringMap;

    }

    private void parseCode(String code, String data) {

      if(code.equals("call")) {

        try {

          JSONObject json = new JSONObject(data);

          String phone = json.optString("data");

          //执行打电话的操作,具体代码省略

          PhoneUtils.call(this, phone);

        } catch (JSONException e) {

          e.printStackTrace();

        }

      return;

    }

    if(code.equals("toast")) {

      try {

        JSONObject json = new JSONObject(data);

        String toast = json.optString("data");

        Toast.makeText(this, toast, Toast.LENGTH_SHORT).show();

      } catch (JSONException e) {

        e.printStackTrace();

      }

      return;

     }

    }

    最后,特别说明一下shouldOverrideUrlLoading()方法的返回值问题,该方法的返回值有三种:

    • 返回true,即根据代码逻辑执行相应操作,webview不加载该url;

    • 返回false,除执行相应代码外,webview加载该url;

    • 返回super.shouldOverrideUrlLoading(),点进父类中,我们可以看到,返回的还是false。

  • 相关阅读:
    sql经典语句大全
    经典SQL语句大全
    Bat命令学习
    [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
    配置WebSite的IIS时遇到的问题与解决方法
    数据库SQL优化大总结之 百万级数据库优化方案
    数据库索引以及优化
    搭建android开发环境
    SQL2008根据日志恢复
    WebService处理大数据量数据
  • 原文地址:https://www.cnblogs.com/kunmomo/p/11556135.html
Copyright © 2020-2023  润新知