糖果派对官方网站_可以赌钱的糖果游戏_手机版
Hybrid 应用程式功底篇(五卡塔尔(英语:State of Qatar)->JSBridge落到实处示例

Hybrid 应用程式功底篇(五卡塔尔(英语:State of Qatar)->JSBridge落到实处示例

作者:网络编程    来源:未知    发布时间:2019-12-24 20:43    浏览量:

bb电子糖果派对 1

说明

JSBridge实现示例

想实现向excel中插入图片,一直没有实现,总是有这那的问题在网上找了一个例程

目录

  • 前言
    • 参考来源
    • 楔子
  • JS实现部分
    • 说明
    • 实现
  • Android实现部分
    • 说明
    • JSBridge类 实现
    • Callback类 实现
    • Webview容器关键代码 实现
    • API 类实现
  • iOS实现部分
    • 说明
    • WebViewJavascriptBridgeBase 实现
    • WebViewJavascriptBridge 实现
    • Webview容器关键代码 实现
voidCInsertImageDlg::OnOpenexcel(){//TODO:AddyourcontrolnotificationhandlercodehereCFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"AllFiles(*.xls)|*.xls||",AfxGetMainWnd());//构造文件打开对话框CStringstrPath;//声明变量if(dlg.DoModal()==IDOK)//判断是否按下"打开"按钮{strPath=dlg.GetPathName();//获得文件路径m_ePath.SetWindowText(strPath);//显示文件路径}}voidCInsertImageDlg::OnOpenimage(){//TODO:AddyourcontrolnotificationhandlercodehereCFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"图片文件|*.bmp;*.jpg;*.jpeg||",AfxGetMainWnd());//构造文件打开对话框CStringstrPath;//声明变量if(dlg.DoModal()==IDOK)//判断是否按下"打开"按钮{strPath=dlg.GetPathName();//获得图片文件路径m_iPath.SetWindowText(strPath);//显示文件路径}}voidCInsertImageDlg::OnButinsert(){//TODO:AddyourcontrolnotificationhandlercodehereCStringePath,iPath;m_ePath.GetWindowText(ePath);m_iPath.GetWindowText(iPath);_Applicationapp;Workbooksbooks;_Workbookbook;Worksheetssheets;_Worksheetsheet;Shapesshp;//创建Excel2000服务器(启动Excel)if(!app.CreateDispatch("Excel.Application",NULL)){AfxMessageBox("创建Excel服务失败!");exit(1);}books.AttachDispatch(app.GetWorkbooks());book.AttachDispatch(books.Add(_variant_t(ePath)));//得到Worksheetssheets.AttachDispatch(book.GetWorksheets());sheet.AttachDispatch(sheets.GetItem(_variant_t("Sheet1")));shp.AttachDispatch(sheet.GetShapes());shp.AddPicture(iPath,false,true,0,0,400,300);app.SetVisible(true);//释放对象sheet.ReleaseDispatch();sheets.ReleaseDispatch();book.ReleaseDispatch();books.ReleaseDispatch();app.ReleaseDispatch();}

前言

也是有错误,在此请教下大家

参考来源

前人栽树,后台乘凉,本文参考了以下来源

  • Hybrid APP架构设计思路
  • marcuswestin/WebViewJavascriptBridge

楔子

本文介绍JSBridge的完整实现,包括JS部分,Android原生,iOS原生部分

JS实现部分

说明

这是一份剔除了业务之后的JSbridge实现代码(JS部分)。JS实现代码就一套

实现

实现代码如下

(function() {
    (function() {
        var hasOwnProperty = Object.prototype.hasOwnProperty;
        var JSBridge = window.JSBridge || (window.JSBridge = {});
        //jsbridge协议定义的名称
        var CUSTOM_PROTOCOL_SCHEME = 'CustomJSBridge';
        //最外层的api名称
        var API_Name = 'namespace_bridge';
        //进行url scheme传值的iframe
        var messagingIframe = document.createElement('iframe');
        messagingIframe.style.display = 'none';
        messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
        document.documentElement.appendChild(messagingIframe);

        //定义的回调函数集合,在原生调用完对应的方法后,会执行对应的回调函数id
        var responseCallbacks = {};
        //唯一id,用来确保每一个回调函数的唯一性
        var uniqueId = 1;
        //本地注册的方法集合,原生只能调用本地注册的方法,否则会提示错误
        var messageHandlers = {};
        //当原生调用H5注册的方法时,通过回调来调用(也就是变为了异步执行,加强安全性)
        var dispatchMessagesWithTimeoutSafety = true;
        //本地运行中的方法队列
        var sendMessageQueue = [];

        //实际暴露给原生调用的对象
        var Inner = {
            /**
             * @description 注册本地JS方法通过JSBridge给原生调用
             * 我们规定,原生必须通过JSBridge来调用H5的方法
             * 注意,这里一般对本地函数有一些要求,要求第一个参数是data,第二个参数是callback
             * @param {String} handlerName 方法名
             * @param {Function} handler 对应的方法
             */
            registerHandler: function(handlerName, handler) {
                messageHandlers[handlerName] = handler;
            },
            /**
             * @description 调用原生开放的方法
             * @param {String} handlerName 方法名
             * @param {JSON} data 参数
             * @param {Function} callback 回调函数
             */
            callHandler: function(handlerName, data, callback) {
                //如果没有 data
                if(arguments.length == 3 && typeof data == 'function') {
                    callback = data;
                    data = null;
                }
                _doSend({
                    handlerName: handlerName,
                    data: data
                }, callback);
            },
            /**
             * iOS专用
             * @description 当本地调用了callHandler之后,实际是调用了通用的scheme,通知原生
             * 然后原生通过调用这个方法来获知当前正在调用的方法队列
             */
            _fetchQueue: function() {
                var messageQueueString = JSON.stringify(sendMessageQueue);
                sendMessageQueue = [];
                return messageQueueString;
            },
            /**
             * @description 原生调用H5页面注册的方法,或者调用回调方法
             * @param {String} messageJSON 对应的方法的详情,需要手动转为json
             */
            _handleMessageFromNative: function(messageJSON) {
                setTimeout(_doDispatchMessageFromNative);
                /**
                 * @description 处理原生过来的方法
                 */
                function _doDispatchMessageFromNative() {
                    var message;
                    try {
                        message = JSON.parse(messageJSON);
                    } catch(e) {
                        //TODO handle the exception
                        console.error("原生调用H5方法出错,传入参数错误");
                        return;
                    }

                    //回调函数
                    var responseCallback;
                    if(message.responseId) {
                        //这里规定,原生执行方法完毕后准备通知h5执行回调时,回调函数id是responseId
                        responseCallback = responseCallbacks[message.responseId];
                        if(!responseCallback) {
                            return;
                        }
                        //执行本地的回调函数
                        responseCallback(message.responseData);
                        delete responseCallbacks[message.responseId];
                    } else {
                        //否则,代表原生主动执行h5本地的函数
                        if(message.callbackId) {
                            //先判断是否需要本地H5执行回调函数
                            //如果需要本地函数执行回调通知原生,那么在本地注册回调函数,然后再调用原生
                            //回调数据有h5函数执行完毕后传入
                            var callbackResponseId = message.callbackId;
                            responseCallback = function(responseData) {
                                //默认是调用EJS api上面的函数
                                //然后接下来原生知道scheme被调用后主动获取这个信息
                                //所以原生这时候应该会进行判断,判断对于函数是否成功执行,并接收数据
                                //这时候通讯完毕(由于h5不会对回调添加回调,所以接下来没有通信了)
                                _doSend({
                                    handlerName: message.handlerName,
                                    responseId: callbackResponseId,
                                    responseData: responseData
                                });
                            };
                        }

                        //从本地注册的函数中获取
                        var handler = messageHandlers[message.handlerName];
                        if(!handler) {
                            //本地没有注册这个函数
                        } else {
                            //执行本地函数,按照要求传入数据和回调
                            handler(message.data, responseCallback);
                        }
                    }
                }
            }

        };
        /**
         * @description JS调用原生方法前,会先send到这里进行处理
         * @param {JSON} message 调用的方法详情,包括方法名,参数
         * @param {Function} responseCallback 调用完方法后的回调
         */
        function _doSend(message, responseCallback) {
            if(responseCallback) {
                //取到一个唯一的callbackid
                var callbackId = Util.getCallbackId();
                //回调函数添加到集合中
                responseCallbacks[callbackId] = responseCallback;
                //方法的详情添加回调函数的关键标识
                message['callbackId'] = callbackId;
            }
            var uri;
            //android中,可以通过onJsPrompt或者截取Url访问都行
            var ua = navigator.userAgent;
            if(ua.match(/(iPhonesOS)s([d_]+)/)||ua.match(/(iPad).*OSs([d_]+)/)) {
                //ios中,通过截取客户端url访问
                //因为ios可以不暴露scheme,而是由原生手动获取
                //正在调用的方法详情添加进入消息队列中,原生会主动获取
                sendMessageQueue.push(message);
                uri = Util.getUri();
            }else{
                //android中兼容处理,将所有的参数一起拼接到url中
                uri = Util.getUri(message);
            }
            //获取 触发方法的url scheme
            //采用iframe跳转scheme的方法
            messagingIframe.src = uri;
        }

        var Util = {
            getCallbackId: function() {
                //如果无法解析端口,可以换为Math.floor(Math.random() * (1 << 30));
                return 'cb_' + (uniqueId++) + '_' + new Date().getTime();
            },
            //获取url scheme
            //第二个参数是兼容android中的做法
            //android中由于原生不能获取JS函数的返回值,所以得通过协议传输
            getUri: function(message) {
                var uri = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
                if(message) {
                    //回调id作为端口存在
                    var callbackId, method, params;
                    if(message.callbackId) {
                        //第一种:h5主动调用原生
                        callbackId = message.callbackId;
                        method = message.handlerName;
                        params = message.data;
                    } else if(message.responseId) {
                        //第二种:原生调用h5后,h5回调
                        //这种情况下需要原生自行分析传过去的port是否是它定义的回调
                        callbackId = message.responseId;
                        method = message.handlerName;
                        params = message.responseData;
                    }
                    //参数转为字符串
                    params = this.getParam(params);
                    //uri 补充
                    uri += ':' + callbackId + '/' + method + '?' + params;
                }

                return uri;
            },
            getParam: function(obj) {
                if(obj && typeof obj === 'object') {
                    return JSON.stringify(obj);
                } else {
                    return obj || '';
                }
            }
        };
        for(var key in Inner) {
            if(!hasOwnProperty.call(JSBridge, key)) {
                JSBridge[key] = Inner[key];
            }
        }

    })();

    //注册一个测试函数
    JSBridge.registerHandler('testH5Func', function(data, callback) {
        alert('测试函数接收到数据:' + JSON.stringify(data));
        callback && callback('测试回传数据...');
    });
    /*
     ***************************API********************************************
     * 开放给外界调用的api
     * */
    window.jsapi = {};
    /**
     ***app 模块 
     * 一些特殊操作
     */
    jsapi.app = {
        /**
         * @description 测试函数
         */
        testNativeFunc: function() {
            //调用一个测试函数
            JSBridge.callHandler('testNativeFunc', {}, function(res) {
                callback && callback(res);
            });
        }
    };
})();               

Android实现部分

说明

这是Android原生中配套的JSBridge实现代码。Android的实现相对比JS复杂,包括多个部分

bb电子糖果派对,JSBridge类实现

实现代码如下

public class JSBridge {
    private static Map<String, HashMap<String, Method>> exposedMethods = new HashMap<>();

    //原生注册API方法
    public static void register(String exposedName, Class<? extends IBridge> clazz) {
        if (!exposedMethods.containsKey(exposedName)) {
            try {
                exposedMethods.put(exposedName, getAllMethod(clazz));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //得到所有的注册方法
    private static HashMap<String, Method> getAllMethod(Class injectedCls) throws Exception {
        HashMap<String, Method> mMethodsMap = new HashMap<>();
        Method[] methods = injectedCls.getDeclaredMethods();
        for (Method method : methods) {
            String name;
            if (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (name = method.getName()) == null) {
                continue;
            }
            Class[] parameters = method.getParameterTypes();
            if (null != parameters && parameters.length == 4) {
                if (parameters[0] == BaseWebLoader.class && parameters[1] == WebView.class && parameters[2] == JSONObject.class && parameters[3] == Callback.class) {
                    mMethodsMap.put(name, method);
                }
            }
        }
        return mMethodsMap;
    }

    //调用Hava中的方法
    //其中BaseWebLoader是JSBridge的webview容器(二次封装)
    //执行完方法后,如果又回到,自动就会调用
    public static String callJava(BaseWebLoader webLoader,WebView webView, String uriString) {
        String methodName = "";
        String className = "";
        String param = "{}";
        String port = "";
        if (!TextUtils.isEmpty(uriString) && uriString.startsWith("EpointJSBridge")) {
            Uri uri = Uri.parse(uriString);
            className = uri.getHost();
            param = uri.getQuery();
            port = uri.getPort() + "";
            String path = uri.getPath();
            if (!TextUtils.isEmpty(path)) {
                methodName = path.replace("/", "");
            }
        }


        if (exposedMethods.containsKey(className)) {
            HashMap<String, Method> methodHashMap = exposedMethods.get(className);

            if (methodHashMap != null && methodHashMap.size() != 0 && methodHashMap.containsKey(methodName)) {
                Method method = methodHashMap.get(methodName);
                if (method != null) {
                    try {
                        method.invoke(null,webLoader, webView, new JSONObject(param), new Callback(webView, port));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }
}   

这个类的作用是原生定义一些暴露的api

Callback类实现

实现代码如下

public class Callback {
    private static Handler mHandler = new Handler(Looper.getMainLooper());
    private static final String CALLBACK_JS_FORMAT = "javascript:JSBridge._handleMessageFromNative(%s);";
    private String mPort;
    private WeakReference<WebView> mWebViewRef;

    public Callback(WebView view, String port) {
        mWebViewRef = new WeakReference<>(view);
        mPort = port;
    }


    public void apply(JSONObject jsonObject) throws JSONException {
        JSONObject object = new JSONObject();
        object.put("responseId", mPort);
        object.putOpt("responseData", jsonObject);
        final String execJs = String.format(CALLBACK_JS_FORMAT, String.valueOf(object));
        //如果activity已经关闭则不回调
        if (mWebViewRef != null && mWebViewRef.get() != null && !((BaseWebLoader) mWebViewRef.get().getContext()).getActivity().isFinishing()) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mWebViewRef.get().loadUrl(execJs);
                }
            });
        }
    }
}

这个类的作用是,定义原生中的回调函数

下一篇:没有了
友情链接: 网站地图
Copyright © 2015-2019 http://www.tk-web.com. bb电子糖果派对有限公司 版权所有