/* * * 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'); var utils = require('cordova/utils'); var 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)); // eslint-disable-line no-undef }; message = base64ToArrayBuffer(message.data); } return message; } function convertMessageToArgsNativeToJs (message) { var args = []; if (!message || !Object.prototype.hasOwnProperty.call(message, '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 () { 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: ' + // eslint-disable-line '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); Promise.resolve().then(function () { cordova.callbackFromNative(callbackId, success, status, args, keepCallback); // eslint-disable-line }); }; // 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;