| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| /** |
| * Creates the exec bridge used to notify the native code of |
| * commands. |
| */ |
| var cordova = require('cordova'), |
| utils = require('cordova/utils'), |
| base64 = require('cordova/base64'); |
| |
| function massageArgsJsToNative(args) { |
| if (!args || utils.typeName(args) != 'Array') { |
| return args; |
| } |
| var ret = []; |
| args.forEach(function(arg, i) { |
| if (utils.typeName(arg) == 'ArrayBuffer') { |
| ret.push({ |
| 'CDVType': 'ArrayBuffer', |
| 'data': base64.fromArrayBuffer(arg) |
| }); |
| } else { |
| ret.push(arg); |
| } |
| }); |
| return ret; |
| } |
| |
| function massageMessageNativeToJs(message) { |
| if (message.CDVType == 'ArrayBuffer') { |
| var stringToArrayBuffer = function(str) { |
| var ret = new Uint8Array(str.length); |
| for (var i = 0; i < str.length; i++) { |
| ret[i] = str.charCodeAt(i); |
| } |
| return ret.buffer; |
| }; |
| var base64ToArrayBuffer = function(b64) { |
| return stringToArrayBuffer(atob(b64)); |
| }; |
| message = base64ToArrayBuffer(message.data); |
| } |
| return message; |
| } |
| |
| function convertMessageToArgsNativeToJs(message) { |
| var args = []; |
| if (!message || !message.hasOwnProperty('CDVType')) { |
| args.push(message); |
| } else if (message.CDVType == 'MultiPart') { |
| message.messages.forEach(function(e) { |
| args.push(massageMessageNativeToJs(e)); |
| }); |
| } else { |
| args.push(massageMessageNativeToJs(message)); |
| } |
| return args; |
| } |
| |
| var iOSExec = function() { |
| |
| // detect change in bridge, if there is a change, we forward to new bridge |
| |
| // if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.cordova && window.webkit.messageHandlers.cordova.postMessage) { |
| // bridgeMode = jsToNativeModes.WK_WEBVIEW_BINDING; |
| // } |
| |
| var successCallback, failCallback, service, action, actionArgs; |
| var callbackId = null; |
| if (typeof arguments[0] !== "string") { |
| // FORMAT ONE |
| successCallback = arguments[0]; |
| failCallback = arguments[1]; |
| service = arguments[2]; |
| action = arguments[3]; |
| actionArgs = arguments[4]; |
| |
| // Since we need to maintain backwards compatibility, we have to pass |
| // an invalid callbackId even if no callback was provided since plugins |
| // will be expecting it. The Cordova.exec() implementation allocates |
| // an invalid callbackId and passes it even if no callbacks were given. |
| callbackId = 'INVALID'; |
| } else { |
| throw new Error('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + |
| 'cordova.exec(null, null, \'Service\', \'action\', [ arg1, arg2 ]);'); |
| } |
| |
| // If actionArgs is not provided, default to an empty array |
| actionArgs = actionArgs || []; |
| |
| // Register the callbacks and add the callbackId to the positional |
| // arguments if given. |
| if (successCallback || failCallback) { |
| callbackId = service + cordova.callbackId++; |
| cordova.callbacks[callbackId] = |
| {success:successCallback, fail:failCallback}; |
| } |
| |
| actionArgs = massageArgsJsToNative(actionArgs); |
| |
| // CB-10133 DataClone DOM Exception 25 guard (fast function remover) |
| var command = [callbackId, service, action, JSON.parse(JSON.stringify(actionArgs))]; |
| window.webkit.messageHandlers.cordova.postMessage(command); |
| |
| }; |
| |
| iOSExec.nativeCallback = function(callbackId, status, message, keepCallback, debug) { |
| |
| var success = status === 0 || status === 1; |
| var args = convertMessageToArgsNativeToJs(message); |
| setTimeout(function(){ |
| cordova.callbackFromNative(callbackId, success, status, args, keepCallback); |
| }, 0); |
| }; |
| |
| // for backwards compatibility |
| iOSExec.nativeEvalAndFetch = function(func) { |
| try { |
| func(); |
| } catch (e) { |
| console.log(e); |
| } |
| }; |
| |
| // Proxy the exec for bridge changes. See CB-10106 |
| |
| function cordovaExec() { |
| var cexec = require('cordova/exec'); |
| var cexec_valid = (typeof cexec.nativeFetchMessages === 'function') && (typeof cexec.nativeEvalAndFetch === 'function') && (typeof cexec.nativeCallback === 'function'); |
| return (cexec_valid && execProxy !== cexec)? cexec : iOSExec; |
| } |
| |
| function execProxy() { |
| cordovaExec().apply(null, arguments); |
| } |
| |
| execProxy.nativeFetchMessages = function() { |
| return cordovaExec().nativeFetchMessages.apply(null, arguments); |
| }; |
| |
| execProxy.nativeEvalAndFetch = function() { |
| return cordovaExec().nativeEvalAndFetch.apply(null, arguments); |
| }; |
| |
| execProxy.nativeCallback = function() { |
| return cordovaExec().nativeCallback.apply(null, arguments); |
| }; |
| |
| module.exports = execProxy; |
| |
| if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.cordova && window.webkit.messageHandlers.cordova.postMessage) { |
| // unregister the old bridge |
| cordova.define.remove('cordova/exec'); |
| // redefine bridge to our new bridge |
| cordova.define("cordova/exec", function(require, exports, module) { |
| module.exports = execProxy; |
| }); |
| } |