混合开发: Android与H5互相调用

11 篇文章 0 订阅

1.H5调起原生

1.1 对WebView进行初始化:

WebSettings settings = webview.getSettings();

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

1.2 创建一个CustomWebViewClient extends继承WebViewClient,也可以专门定义一个类JavaScriptMetod,专门用来管理给JS提供的调用方法。在这里,我将给JS提供的调用方法写在MyWebViewClient 中

@JavascriptInterface

public void receiveCommands(String strCommands)

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

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

public static final String JAVAINTERFACE = "javaInterface";

1.4 添加javascript接口:

CustomWebViewClient m = new CustomWebViewClient (this, webview);

webview.addJavascriptInterface(m, CustomWebViewClient .javaInterface);

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

1.5 现在就js就可以调用原生方法了

//参数一般为json格式

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

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

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

此种方式的缺点:window.javaInterface.receiveCommands(JSON.stringify(json))这样的js代码并不适用于ios,如果用以上的方法,就得分别为android和ios各写一套js代码。

1.6 JsBridge的通讯协议

(1)定义一个类CommandProtocal

        public String methodName; //方法名字
        public Object methodArgs; //方法参数
        public String callbackId;   //调用id
        public String returnCallbackId; // 返回数据的调用id
        public Object returnCallbackData; 调用返回的数据

public CommandProtocal (JSONObject json)

构造器中输入JSONObject 并转化成对应的字段

同时,也可以将对应的字段组成一个JSONObject 并输出。

(2)定义一个命令解析以后,执行方法的接口

    public interface ExecuteMethod {
        /**
         * 执行方法
         *
         * @param args     方法参数
         * @param callback 回调方法
         */
        void execute(Object args, Callback callback);
    }

(3)定义一个存储命令执行方法的HashMap,key就是方法的名字

Map<String, ExecuteMethod> mMap = new HashMap<>();

(4)原生绑定命令执行方法,提供给JS调用

    public void bindExecuteMethod(String name, ExecuteMethod method) {
        synchronized (this) {
            mMap.put(name, method);
        }
    }

(5)JS调用receiveCommands,原生接收到JsonArray类型的命令字符串,进行解析,根据methodName字段从mMap 中取出ExecuteMethod 回调execute(Object args, Callback callback)执行方法。

2. 第二种调用原生方法

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

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

WebSettings settings = webview.getSettings();

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

2.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显示吐司和打电话的操作。其中,protocol://android为自定义的H5与android间的通信协议,与http请求进行区分。code规定了要进行的操作,data为传输的数据。

2.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()方法的返回值问题,该方法的返回值有三种:

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

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

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

 

3.原生调用Js

//首先设置Webview支持JS代码 webView.getSettings().setJavaScriptEnabled(true);

若调用的js方法没有返回值,则可以直接调用mWebView.loadUrl(“javascript:do());其中do是js中的方法;

若有返回值时我们可以调用mwebview,evaluteJavascript方法;

@TargetApi(Build.VERSION_CODES.KITKAT)
    public void onSum(View view){
        webView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String value) {
                Toast.makeText(getApplicationContext(),
                        "相加结果:"+value, Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void onDoing(View view){
        String msg = "测试";
        webView.loadUrl("javascript:showInfoFromJava('"+msg+"')");
    }

对应的js方法:

function sum(a,b){
    return a+b;
    }

    function showInfoFromJava(){
    document.getElementById("p").innerHTML="Java成功调的JS方法";
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值