您的位置:首页 > 移动开发

《在WebView中如何让JS与Java安全地互相调用》核心JS全解析

2015-09-22 17:39 676 查看

1.说明:

《[在WebView中如何让JS与Java安全地互相调用](http://www.pedant.cn/2014/07/04/webview-js-java-interface-research/)》核心JS全解析

2. 核心JS解析如下,欢迎拍砖!!!

javascript: (function(win) {
    console.log("HostApp initialization begin");
    //win.HostApp对象
    var H = {
        //回调函数队列
        queue : [],
        //Java执行完毕后,调用此回调方法并传入一个索引。此回调方法根据索引,去回调函数队列中找到对应的回调方法
        callback : function() {
            //获取Java传入的所有参数数组
            var argArr = Array.prototype.slice.call(arguments, 0);
            console.log("queqe:" + this.queue);
            console.log("argArr:" + argArr);
            //获取第一个参数——回调方法的索引
            var index = argArr.shift();
            console.log("index:" + index);
            //获取第二个参数——是否是一个永久的方法(默认非永久)。当非永久方法的时候,使用完队列中的此回调方法后,删除此方法。
            var isPerManent = argArr.shift();
            console.log("isPerManent:" + isPerManent);
            console.log("argArr:" + argArr);
            console.log("queue[index]:" + this.queue[index]);
            //利用apply,将当前上下文和参数传入回调方法中
            //(注意参数数组argArr的前面两个参数已经被shift取完并删除了,剩下的参数为此回调方法需要返回的数据,故传入此回调方法中)
            this.queue[index].apply(this, argArr);
            //如果是非永久的js方法,则回调完此方法之后,从队列中删除此方法
            //(注意,方法虽然删除了,但只是删除的索引。也就是说,假设其它地方保留有此方法的索引,那么此方法不会被GC回收)
            if (!isPerManent) {
                delete this.queue[index]
            }
        }
    };
    console.log("queqe:" + this.queue);
    H.alert = H.alert = H.alert = H.delayJsCallBack = H.getIMSI = H.getOsSdk = H.goBack = H.overloadMethod = H.overloadMethod = H.passJson2Java = H.passLongType = H.retBackPassJson = H.retJavaObject = H.testLossTime = H.toast = H.toast = function() {
        //获取业务中调用方法时,传入的所有参数数组
        var argArr = Array.prototype.slice.call(arguments, 0);
        //第一个参数默认都是调用的方法本身的名字
        //(虽然在业务中,没有传入方法的名字这个参数,但是下面的代码中,使用Object.getOwnPropertyNames方法,
        //获取了HostApp所有的属性,(当属性为function类型时)并将属性名当作第一个参数,拼接到业务传入的参数的最前面)
        if (argArr.length < 1) {
            throw "HostApp call error, message:miss method name"
        }
        //将要传入J***A端的类型数组
        var typeArr = [];
        //循环所有业务传入的参数,获取每个参数的类型,存入到类型数组中。
        for (var h = 1; h < argArr.length; h++) {
            var arg = argArr[h];
            var argType = typeof arg;
            typeArr[typeArr.length] = argType;
            //如果发现传入的参数是回调函数,则将回调函数存入HostApp的回调函数队列中,并将参数的值替换为在回调函数在队列中的索引
            //(注意,此时,尽管参数的值在argArr中只存了一个在队列中的索引,但参数的类型在typeArr中仍然存为function类型)
            if (argType == "function") {
                var queueLength = H.queue.length;
                H.queue[queueLength] = arg;
                argArr[h] = queueLength
            }
        }
        //传入方法名,参数类型数组以及业务传入的所有的参数,执行弹出框事件,让J***A端捕获。获取返回值,并转化为json对象。
        var promptResultObj = JSON.parse(prompt(JSON.stringify({
            method : argArr.shift(),
            types : typeArr,
            args : argArr
        })));
        //如果返回码不为200,抛出异常
        if (promptResultObj.code != 200) {
            throw "HostApp call error, code:" + promptResultObj.code
                    + ", message:" + promptResultObj.result
        }
        //返回从J***A端获取到的返回值。
        //(注意,业务中传入了回调方法的时候,大多数情况下,返回值通过在回调方法中获取。此时可以参考HostApp上的回调函数队列和callback方法)
        return promptResultObj.result
    };
    //使用getOwnPropertyNames获取HostApp对象的所有属性,并循环。
    //注意,forEach的第一个参数是数组元素(也就是HostApp的属性名),第二个参数是数组索引,后面依次是数组中的所有元素。
    Object.getOwnPropertyNames(H).forEach(
            function(attrName) {
                var attrObj = H[attrName];
                if (typeof attrObj === "function" && attrName !== "callback") {
                    //此处是一个匿名的闭包函数,被HostApp的一个属性所引用。
                    //当HostApp中此属性一直存在时,局部变量attrName和attrObj可以被闭包函数永久访问,而不会被GC回收。
                    //显然,此处就已经把真实的函数(HostApp上所有相关属性,如getIMSI、getOsSdk)放到了一个只有闭包函数可以访问的局部变量attrObj里面了。
                    //总之,当前HostApp上所有的属性,只是一个闭包函数。但是,此闭包函数可以访问到之前的真实属性。
                    H[attrName] = function() {
                        return attrObj.apply(H, [ attrName ]
                                .concat(Array.prototype.slice
                                        .call(arguments, 0)))
                    }
                }
            });
    win.HostApp = H;
    console.log("HostApp initialization end")
})(window);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: