ccos-cli
Version:
This is a command line interface toolkit. It is used for generating and managing example code for CoocaaOS running on Skyworth/Coocaa TV webos API.
1,207 lines (1,150 loc) • 132 kB
JavaScript
; (function (window) {
var _pcMode = true,
debuggee,
debugObj = {
getPCMode: function () {
return _pcMode;
},
setDeviceInfo: function (options) {
this.deviceInfo = assignPolyfill(this.deviceInfo, options || options);
return this;
},
getDeviceInfo: function () {
return this.deviceInfo;
},
setUserInfo: function (options) {
this.userInfo = assignPolyfill(this.userInfo, options || {});
return this;
},
getUserInfo: function () {
return this.userInfo;
},
setAccessToken: function (options) {
this.accessToken = assignPolyfill(this.accessToken, options || {});
return this;
},
getAccessToken: function () {
return this.accessToken;
},
setLoginStatus: function (options) {
this.loginStatus = assignPolyfill(this.loginStatus, options || {});
return this;
},
getLoginStatus: function () {
return this.loginStatus;
}
};
function assignPolyfill() {
// 默认不进行深拷贝
var deep = false;
var name, options, src, copy, clone, copyIsArray;
var length = arguments.length;
// 记录要复制的对象的下标
var i = 1;
// 第一个参数不传布尔值的情况下,target 默认是第一个参数
var target = arguments[0] || {};
// 如果第一个参数是布尔值,第二个参数是 target
if (typeof target == 'boolean') {
deep = target;
target = arguments[i] || {};
i++;
}
// 如果target不是对象,我们是无法进行复制的,所以设为 {}
if (typeof target !== "object" && !isFunction(target)) {
target = {};
}
// 循环遍历要复制的对象们
for (; i < length; i++) {
// 获取当前对象
options = arguments[i];
// 要求不能为空 避免 extend(a,,b) 这种情况
if (options != null) {
for (name in options) {
// 目标属性值
src = target[name];
// 要复制的对象的属性值
copy = options[name];
// 解决循环引用
if (target === copy) {
continue;
}
// 要递归的对象必须是 plainObject 或者数组
if (deep && copy && (isPlainObject(copy) ||
(copyIsArray = Array.isArray(copy)))) {
// 要复制的对象属性值类型需要与目标属性值相同
if (copyIsArray) {
copyIsArray = false;
clone = src && Array.isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
target[name] = extend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
return target;
};
if (/Android/.test(navigator.userAgent)) _pcMode = false;
console.log('_pcMode :' + _pcMode);
function Debugger() {
this.deviceInfo = {
"panel": "50",
"version": "6.20.180226",
"model": "Q4A",
"chipid": "MST-6A838",
"mac": "001a9a000000",
"chip": "9S52",
"androidsdk": 23,
"devid": "83ec547b4ca46a394719bdae81d912e4",
"activeid": "23320005",
"emmcid": "90014a484147346132a559776981c400",
"brand": "Skyworth",
"barcode": "50Q4AXXXXX-XXXXXXX-XXXXXXX",
"sid": "899b8796-6b7f-42d9-b050-7a097d9e357c"
};
this.accessToken = { "accesstoken": "2.0f3674599cca4c9d966842784763adb2" };
this.loginStatus = { "haslogin": "true" };
this.userInfo = {
"account_type": "1",
"avatar": "http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850",
"avatars": "{\"f_200\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_500\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_250\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_370\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_50\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_70\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"f_800\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\"}",
"balance": "0.0000",
"base_status": "1",
"cardNo": "1101415370510",
"check_add_mobile": "1",
"create_date": "1533354421000",
"current": "true",
"email": "",
"external_info": "[{\"unionid\":\"\",\"face\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"externalFlag\":\"qq\",\"vuserid\":\"\",\"refreshToken\":\"BB6C1478C0577EB434232ABB6E2316C7:DC3B76958514E0DA2CF1C33F760EB35C\",\"accessToken\":\"DC3B76958514E0DA2CF1C33F760EB35C\",\"external_avatar\":\"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=gNeKwZiavWw620PSiarYH8YQ&s=100&t=1483281850\",\"timestamp\":1565253070485,\"vusession\":\"\",\"external_flag\":\"qq\",\"bind_time\":1533354144000,\"external_nickname\":\"公仔\",\"external_id\":\"A0D9BF55491D83CE51D6A1B9907B576E\",\"nick\":\"公仔\",\"isExpired\":\"0\",\"login\":true,\"openId\":\"A0D9BF55491D83CE51D6A1B9907B576E\"}]",
"gender": "1",
"grant_users": "[]",
"loginFlag": "qq",
"mobile": "",
"nick_name": "公仔",
"open_id": "0bc9cf8f979911e8a09700505687790a",
"qq": "",
"revenue": "0",
"simplePwd": "0",
"sky_id": "200000004528",
"tel1": "",
"third_account": "1",
"update_image_times": "0",
"visit_num": "9"
};
}
Debugger.prototype = debugObj;
debuggee = new Debugger();
window.ccDebug = debuggee;
var PLATFORM_VERSION_BUILD_LABEL = '5.2.0-dev';
var require,
define;
(function () {
var modules = {},
// 当前正在生成的模块ID堆栈.
requireStack = [],
// 模块ID图 -> 当前正在构建的模块的RequireStack索引.
inProgressModules = {},
SEPARATOR = ".";
function build(module) {
var factory = module.factory,
localRequire = function (id) {
var resultantId = id;
//这是一个相对路径, 所以去掉最后一部分并添加ID (减 "./")
if (id.charAt(0) === ".") {
resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);
}
return require(resultantId);
};
module.exports = {};
delete module.factory;
factory(localRequire, module.exports, module);
return module.exports;
}
require = function (id) {
if (!modules[id]) {
console.log("module " + id + " not found");
throw "module " + id + " not found";
} else if (id in inProgressModules) {
var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
console.log("Cycle in require graph: " + cycle);
throw "Cycle in require graph: " + cycle;
}
if (modules[id].factory) {
try {
inProgressModules[id] = requireStack.length;
requireStack.push(id);
return build(modules[id]);
} finally {
delete inProgressModules[id];
requireStack.pop();
}
}
return modules[id].exports;
};
define = function (id, factory) {
if (modules[id]) {
console.log("module " + id + " already defined");
throw "module " + id + " already defined";
}
modules[id] = {
id: id,
factory: factory
};
};
define.remove = function (id) {
delete modules[id];
};
define.moduleMap = modules;
})();
//导出以在节点中使用
if (typeof module === "object" && typeof require === "function") {
module.exports.require = require;
module.exports.define = define;
}
define("cordova", function (require, exports, module) {
// 托管环境中的Windows 10解决方案案例
// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object
if (window.cordova && !(window.cordova instanceof HTMLElement)) {
throw new Error("cordova already defined");
}
var channel = require('cordova/channel');
var platform = require('cordova/platform');
/**截获对AddEventListener的调用 + 删除事件侦听器(removeEventListener) 和 处理 deviceready,resume,and pause 事件.*/
var m_document_addEventListener = document.addEventListener;
var m_document_removeEventListener = document.removeEventListener;
var m_window_addEventListener = window.addEventListener;
var m_window_removeEventListener = window.removeEventListener;
/**包含要截取文档的自定义事件处理程序 + window event listeners.*/
var documentEventHandlers = {},
windowEventHandlers = {};
document.addEventListener = function (evt, handler, capture) {
var e = evt.toLowerCase();
if (typeof documentEventHandlers[e] != 'undefined') {
documentEventHandlers[e].subscribe(handler);
} else {
m_document_addEventListener.call(document, evt, handler, capture);
}
};
window.addEventListener = function (evt, handler, capture) {
var e = evt.toLowerCase();
if (typeof windowEventHandlers[e] != 'undefined') {
windowEventHandlers[e].subscribe(handler);
} else {
m_window_addEventListener.call(window, evt, handler, capture);
}
};
document.removeEventListener = function (evt, handler, capture) {
var e = evt.toLowerCase();
// If unsubscribing from an event that is handled by a plugin
if (typeof documentEventHandlers[e] != "undefined") {
documentEventHandlers[e].unsubscribe(handler);
} else {
m_document_removeEventListener.call(document, evt, handler, capture);
}
};
window.removeEventListener = function (evt, handler, capture) {
var e = evt.toLowerCase();
// If unsubscribing from an event that is handled by a plugin
if (typeof windowEventHandlers[e] != "undefined") {
windowEventHandlers[e].unsubscribe(handler);
} else {
m_window_removeEventListener.call(window, evt, handler, capture);
}
};
function createEvent(type, data) {
var event = document.createEvent('Events');
event.initEvent(type, false, false);
if (data) {
for (var i in data) {
if (data.hasOwnProperty(i)) {
event[i] = data[i];
}
}
}
return event;
}
var cordova = {
define: define,
require: require,
version: PLATFORM_VERSION_BUILD_LABEL,
platformVersion: PLATFORM_VERSION_BUILD_LABEL,
platformId: platform.id,
/**添加/删除自己的AddEventListener劫持文档或者window的方法*/
addWindowEventHandler: function (event) {
return (windowEventHandlers[event] = channel.create(event));
},
addStickyDocumentEventHandler: function (event) {
return (documentEventHandlers[event] = channel.createSticky(event));
},
addDocumentEventHandler: function (event) {
return (documentEventHandlers[event] = channel.create(event));
},
removeWindowEventHandler: function (event) {
delete windowEventHandlers[event];
},
removeDocumentEventHandler: function (event) {
delete documentEventHandlers[event];
},
/**检索由Cordova替换的原始事件处理程序 返回一个对象*/
getOriginalHandlers: function () {
return {
'document': {
'addEventListener': m_document_addEventListener,
'removeEventListener': m_document_removeEventListener
},
'window': {
'addEventListener': m_window_addEventListener,
'removeEventListener': m_window_removeEventListener
}
};
},
/**
* 从本机代码激发事件的方法
* 对于导致需要在本机代码中捕获的异常的事件,需要bnodetach
*/
fireDocumentEvent: function (type, data, bNoDetach) {
var evt = createEvent(type, data);
if (typeof documentEventHandlers[type] != 'undefined') {
if (bNoDetach) {
documentEventHandlers[type].fire(evt);
} else {
setTimeout(function () {
// 在加载cordova.js之前注册的侦听器上启动deviceready。
if (type == 'deviceready') {
document.dispatchEvent(evt);
}
documentEventHandlers[type].fire(evt);
}, 0);
}
} else {
document.dispatchEvent(evt);
}
},
fireWindowEvent: function (type, data) {
var evt = createEvent(type, data);
if (typeof windowEventHandlers[type] != 'undefined') {
setTimeout(function () {
windowEventHandlers[type].fire(evt);
}, 0);
} else {
window.dispatchEvent(evt);
}
},
/**插件回调机制。*/
// 随机化启动回调ID以避免刷新或导航后发生冲突。
// 这样,任何新回调都不太可能获得与旧回调相同的回调ID。
callbackId: Math.floor(Math.random() * 2000000000),
callbacks: {},
callbackStatus: {
NO_RESULT: 0,
OK: 1,
CLASS_NOT_FOUND_EXCEPTION: 2,
ILLEGAL_ACCESS_EXCEPTION: 3,
INSTANTIATION_EXCEPTION: 4,
MALFORMED_URL_EXCEPTION: 5,
IO_EXCEPTION: 6,
INVALID_ACTION: 7,
JSON_EXCEPTION: 8,
ERROR: 9
},
/**当从操作返回成功结果时由本地代码调用。*/
callbackSuccess: function (callbackId, args) {
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
},
/**当返回操作的错误结果时由本地代码调用。*/
callbackError: function (callbackId, args) {
// 不建议使用callbacksuccess和callbackerror,而赞成callbackFromNative。
// 从状态中获得成功。
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
},
/**当从操作返回结果时由本地代码调用。*/
callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) {
try {
var callback = cordova.callbacks[callbackId];
if (callback) {
if (isSuccess && status == cordova.callbackStatus.OK) {
callback.success && callback.success.apply(null, args);
} else if (!isSuccess) {
callback.fail && callback.fail.apply(null, args);
}
// 如果不期望有更多结果,则清除回调
if (!keepCallback) {
delete cordova.callbacks[callbackId];
}
}
} catch (err) {
var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err;
console && console.log && console.log(msg);
cordova.fireWindowEvent("cordovacallbackerror", {
'message': msg
});
throw err;
}
},
addConstructor: function (func) {
console.log('[DEBUG] 注册onCordovaReady事件监听');
channel.onCordovaReady.subscribe(function () {
try {
func();
} catch (e) {
console.log("未能运行构造函数: " + e);
}
});
}
};
module.exports = cordova;
});
define("cordova/android/nativeapiprovider", function (require, exports, module) {
/**导出ExposedJSAPI.java对象(如果可用),否则导出PromptBasedNativeAPI。*/
var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
var currentApi = nativeApi;
module.exports = {
get: function () {
return currentApi;
},
setPreferPrompt: function (value) {
currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
},
// Used only by tests.
set: function (value) {
currentApi = value;
}
};
});
define("cordova/android/promptbasednativeapi", function (require, exports, module) {
module.exports = {
exec: function (bridgeSecret, service, action, callbackId, argsJson) {
return null;
// return prompt(argsJson, 'gap:' + JSON.stringify([bridgeSecret, service, action, callbackId]));
},
setNativeToJsBridgeMode: function (bridgeSecret, value) {
return null;
// prompt(value, 'gap_bridge_mode:' + bridgeSecret);
},
retrieveJsMessages: function (bridgeSecret, fromOnlineEvent) {
return null;
// return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
}
};
});
define("cordova/argscheck", function (require, exports, module) {
var utils = require('cordova/utils');
var moduleExports = module.exports;
var typeMap = {
'A': 'Array',
'D': 'Date',
'N': 'Number',
'S': 'String',
'F': 'Function',
'O': 'Object'
};
function extractParamName(callee, argIndex) {
return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
}
function checkArgs(spec, functionName, args, opt_callee) {
if (!moduleExports.enableChecks) {
return;
}
var errMsg = null;
var typeName;
for (var i = 0; i < spec.length; ++i) {
var c = spec.charAt(i),
cUpper = c.toUpperCase(),
arg = args[i];
// asterix的意思是允许任何事情发生。
if (c == '*') {
continue;
}
typeName = utils.typeName(arg);
if ((arg === null || arg === undefined) && c == cUpper) {
continue;
}
if (typeName != typeMap[cUpper]) {
errMsg = 'Expected ' + typeMap[cUpper];
break;
}
}
if (errMsg) {
errMsg += ', but got ' + typeName + '.';
errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
// 运行单元测试时不要记录。
if (typeof jasmine == 'undefined') {
console.error(errMsg);
}
throw TypeError(errMsg);
}
}
function getValue(value, defaultValue) {
return value === undefined ? defaultValue : value;
}
moduleExports.checkArgs = checkArgs;
moduleExports.getValue = getValue;
moduleExports.enableChecks = true;
});
define("cordova/base64", function (require, exports, module) {
var base64 = exports;
base64.fromArrayBuffer = function (arrayBuffer) {
var array = new Uint8Array(arrayBuffer);
return uint8ToBase64(array);
};
base64.toArrayBuffer = function (str) {
var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str, 'base64').toString('binary');
var arrayBuffer = new ArrayBuffer(decodedStr.length);
var array = new Uint8Array(arrayBuffer);
for (var i = 0, len = decodedStr.length; i < len; i++) {
array[i] = decodedStr.charCodeAt(i);
}
return arrayBuffer;
};
//------------------------------------------------------------------------------
/* 此代码基于http://jspef.com/b64测试中的性能测试。
* 这个12位一次算法是所有测试平台上性能最好的版本。
*/
var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var b64_12bit;
var b64_12bitTable = function () {
b64_12bit = [];
for (var i = 0; i < 64; i++) {
for (var j = 0; j < 64; j++) {
b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j];
}
}
b64_12bitTable = function () {
return b64_12bit;
};
return b64_12bit;
};
function uint8ToBase64(rawData) {
var numBytes = rawData.byteLength;
var output = "";
var segment;
var table = b64_12bitTable();
for (var i = 0; i < numBytes - 2; i += 3) {
segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2];
output += table[segment >> 12];
output += table[segment & 0xfff];
}
if (numBytes - i == 2) {
segment = (rawData[i] << 16) + (rawData[i + 1] << 8);
output += table[segment >> 12];
output += b64_6bit[(segment & 0xfff) >> 6];
output += '=';
} else if (numBytes - i == 1) {
segment = (rawData[i] << 16);
output += table[segment >> 12];
output += '==';
}
return output;
}
});
define("cordova/builder", function (require, exports, module) {
var utils = require('cordova/utils');
function each(objects, func, context) {
for (var prop in objects) {
if (objects.hasOwnProperty(prop)) {
func.apply(context, [objects[prop], prop]);
}
}
}
function clobber(obj, key, value) {
exports.replaceHookForTesting(obj, key);
var needsProperty = false;
try {
obj[key] = value;
} catch (e) {
needsProperty = true;
}
// getter只能由getter重写。
if (needsProperty || obj[key] !== value) {
utils.defineGetter(obj, key, function () {
return value;
});
}
}
function assignOrWrapInDeprecateGetter(obj, key, value, message) {
if (message) {
utils.defineGetter(obj, key, function () {
console.log(message);
delete obj[key];
clobber(obj, key, value);
return value;
});
} else {
clobber(obj, key, value);
}
}
function include(parent, objects, clobber, merge) {
each(objects, function (obj, key) {
try {
var result = obj.path ? require(obj.path) : {};
if (clobber) {
// 如果它不存在的话,就把它击倒
if (typeof parent[key] === 'undefined') {
assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
} else if (typeof obj.path !== 'undefined') {
// 如果合并,则将属性合并到父级上,否则将关闭。
if (merge) {
recursiveMerge(parent[key], result);
} else {
assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
}
}
result = parent[key];
} else {
// 如果当前未定义,则覆盖。
if (typeof parent[key] == 'undefined') {
assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
} else {
// 将结果设置为已经存在的内容,这样我们就可以在其中构建子元素(如果它们存在的话)。
result = parent[key];
}
}
if (obj.children) {
include(result, obj.children, clobber, merge);
}
} catch (e) {
//utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"');
}
});
}
/**
* 递归地将属性从一个对象合并到另一个对象。 SRC对象的属性将覆盖现有的目标属性。
* @param 要将属性合并到的目标对象。
* @param 从中合并属性的SRC对象。
*/
function recursiveMerge(target, src) {
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
if (target.prototype && target.prototype.constructor === target) {
// 如果目标对象是构造函数,则重写原型。
clobber(target.prototype, prop, src[prop]);
} else {
if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
recursiveMerge(target[prop], src[prop]);
} else {
clobber(target, prop, src[prop]);
}
}
}
}
}
exports.buildIntoButDoNotClobber = function (objects, target) {
include(target, objects, false, false);
};
exports.buildIntoAndClobber = function (objects, target) {
include(target, objects, true, false);
};
exports.buildIntoAndMerge = function (objects, target) {
include(target, objects, true, true);
};
exports.recursiveMerge = recursiveMerge;
exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
exports.replaceHookForTesting = function () { };
});
define("cordova/channel", function (require, exports, module) {
var utils = require('cordova/utils'),
nextGuid = 1;
/**
* 自定义pub子“channel”,可以订阅函数
* 此对象用于为Cordova初始化以及其后的自定义事件定义和控制事件的触发。
* 页面加载和Cordova启动期间的事件顺序如下:
* onDOMContentLoaded* 加载和分析网页时收到的内部事件。
* onNativeReady* 表示Cordova本机端已就绪的内部事件。
* onCordovaReady* 当所有的Cordova Javascript objects都已创立时,内部事件就被烧毁。
* onDeviceReady* 激发的用户事件指示Cordova已就绪
* onResume 激发的用户事件指示启动/恢复生命周期事件
* onPause 激发的用户事件指示暂停生命周期事件
*
* 标有*的事件很粘。一旦他们被激活,他们将保持被激活状态。
* 触发事件后订阅的所有侦听器都将立即执行。
*
* 用户代码应注册的唯一Cordova事件是:
* deviceready Cordova 本地代码被初始化、Cordova APIs 可以被JavaScript调用
* pause 应用程序已移动到后台
* resume 应用程序已返回前台
*
* 侦听器可以注册为:
* document.addEventListener("deviceready", myDeviceReadyListener, false);
* document.addEventListener("resume", myResumeListener, false);
* document.addEventListener("pause", myPauseListener, false);
*
* dom生命周期事件应用于保存和恢复状态
* window.onload
* window.onunload 事件在用户退出页面时发生。
*/
/**频道名称字符串化*/
var Channel = function (type, sticky) {
this.type = type;
// GUID图 -> function.
this.handlers = {};
// 0 = 非粘性, 1 = 粘性非激活状态, 2 = 粘性 激活状态.
this.state = sticky ? 1 : 0;
// 在粘性模式下用于记住传递给fire()的参数。
this.fireArgs = null;
// 用于OnHasSubcribersChange以了解是否有任何侦听器。
this.numHandlers = 0;
// 在订阅第一个侦听器或取消订阅最后一个侦听器时调用的函数。
this.onHasSubscribersChange = null;
},
channel = {
/**仅在激活指定的所有通道后调用提供的函数。所有通道必须是粘性通道。*/
join: function (h, c) {
var len = c.length,
i = len,
f = function () {
if (!(--i)) h();
};
for (var j = 0; j < len; j++) {
if (c[j].state === 0) {
throw Error('Can only use join with sticky channels.');
}
c[j].subscribe(f);
}
if (!len) h();
},
create: function (type) {
return channel[type] = new Channel(type, false);
},
createSticky: function (type) {
return channel[type] = new Channel(type, true);
},
/**在“deviceready”被触发之前必须触发的cordova通道。*/
deviceReadyChannelsArray: [],
deviceReadyChannelsMap: {},
/**
* 指示在准备使用某个功能之前需要对其进行初始化。
* 这将保留Cordova的“deviceReady”事件,直到该功能被初始化并调用cordova.initcomplete(feature)。
* @param feature {String} 独特的特征的名称
*/
waitForInitialization: function (feature) {
if (feature) {
var c = channel[feature] || this.createSticky(feature);
this.deviceReadyChannelsMap[feature] = c;
this.deviceReadyChannelsArray.push(c);
}
},
/**
* 指示初始化代码已完成,该功能已准备好使用。
* @param feature {String} 独特的特征的名称
*/
initializationComplete: function (feature) {
var c = this.deviceReadyChannelsMap[feature];
if (c) {
c.fire();
}
}
};
function forceFunction(f) {
if (typeof f != 'function') throw "Function required as first argument!";
}
/**
* 将给定函数订阅到通道。每当调用channel.fire时,函数也会调用它。
* (可选)指定函数的执行上下文和可用于停止订阅通道的GUID。
* 返回guid。
*/
Channel.prototype.subscribe = function (f, c) {
// 需要一个函数来调用
forceFunction(f);
if (this.state == 2) {
f.apply(c || this, this.fireArgs);
return;
}
var func = f,
guid = f.observer_guid;
if (typeof c == "object") {
func = utils.close(c, f);
}
if (!guid) {
// 任何频道第一次看到此订户
guid = '' + nextGuid++;
}
func.observer_guid = guid;
f.observer_guid = guid;
// 不要多次添加同一处理程序。
if (!this.handlers[guid]) {
this.handlers[guid] = func;
this.numHandlers++;
if (this.numHandlers == 1) {
this.onHasSubscribersChange && this.onHasSubscribersChange();
}
}
};
/**从通道中取消订阅具有给定guid的函数。*/
Channel.prototype.unsubscribe = function (f) {
// 需要一个函数来调用
forceFunction(f);
var guid = f.observer_guid,
handler = this.handlers[guid];
if (handler) {
delete this.handlers[guid];
this.numHandlers--;
if (this.numHandlers === 0) {
this.onHasSubscribersChange && this.onHasSubscribersChange();
}
}
};
/**调用订阅此通道的所有函数。*/
Channel.prototype.fire = function (e) {
var fail = false,
fireArgs = Array.prototype.slice.call(arguments);
// 应用粘性。
if (this.state == 1) {
this.state = 2;
this.fireArgs = fireArgs;
}
if (this.numHandlers) {
// 首先复制值,这样可以安全地从回调中修改它。
var toCall = [];
for (var item in this.handlers) {
toCall.push(this.handlers[item]);
}
for (var i = 0; i < toCall.length; ++i) {
toCall[i].apply(this, fireArgs);
}
if (this.state == 2 && this.numHandlers) {
this.numHandlers = 0;
this.handlers = {};
this.onHasSubscribersChange && this.onHasSubscribersChange();
}
}
};
// 在这里定义它们,让它们准备得非常快!
// 加载和分析网页时接收的DOM事件。
channel.createSticky('onDOMContentLoaded');
// 事件指示Cordova本机端已就绪。
channel.createSticky('onNativeReady');
//事件表明所有的 Cordova JavaScript 对象已经被创建。而且是时候执行plugin构造函数了。
channel.createSticky('onCordovaReady');
// 事件指示已加载并准备好所有自动加载的JS插件。
// 固定器 remove this
channel.createSticky('onPluginsReady');
// 表示Cordova已就绪的事件
channel.createSticky('onDeviceReady');
// 事件,指示恢复生命周期事件
channel.create('onResume');
// 表示暂停生命周期事件的事件
channel.create('onPause');
// “deviceready”被触发之前必须触发的通道。
channel.waitForInitialization('onCordovaReady');
channel.waitForInitialization('onDOMContentLoaded');
module.exports = channel;
});
define("cordova/exec", function (require, exports, module) {
/**
* 执行cordova命令。 这个操作是同步的还是异步的取决于本机端。
* 本机端可以返回:
* 同步的: PluginResult对象作为JSON字符串
* 异步的: 空字符串 ""
* 如果是异步的,则本机端将根据操作的结果选择cordova.callbackuccess或cordova.callbackError。
* @param {Function} success The success callback
* @param {Function} fail The fail callback
* @param {String} service 要使用的服务的名称
* @param {String} action 要运行的操作 in cordova
* @param {String[]} [args] 要传递给方法的参数为零个或多个
*/
var cordova = require('cordova'),
nativeApiProvider = require('cordova/android/nativeapiprovider'),
utils = require('cordova/utils'),
base64 = require('cordova/base64'),
channel = require('cordova/channel'),
jsToNativeModes = {
PROMPT: 0,
JS_OBJECT: 1
},
nativeToJsModes = {
// 使用JS->Native Bridge对消息进行轮询。
POLLING: 0,
// 为了使加载URL可行,它需要有一个解决bug的方法,在发送消息时,软键盘会被忽略。
LOAD_URL: 1,
// 要使联机_事件可行,它需要截获所有事件侦听器(通过addEventListener和window.ononline),并设置navigator属性本身。
ONLINE_EVENT: 2
},
jsToNativeBridgeMode, // Set lazily.
nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
pollEnabled = false,
bridgeSecret = -1;
var messagesFromNative = [];
var isProcessing = false;
var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
var nextTick = resolvedPromise ? function (fn) {
resolvedPromise.then(fn);
} : function (fn) {
setTimeout(fn);
};
function androidExec(success, fail, service, action, args) {
if (bridgeSecret < 0) {
// 如果我们捕捉到这种攻击,就需要将exec()排队,并在获得机密后将其触发。
// 现在,我认为调用exec()是不可能的,因为插件是经过解析的,但直到OnActiveReady之后才运行。
throw new Error('exec() called without bridgeSecret');
}
// 如果尚未设置默认桥接模式,请设置它们。
// 默认情况下,我们使用故障保护,因为addjavascriptinterface经常中断
if (jsToNativeBridgeMode === undefined) {
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
}
// 将arrayBuffers中的所有arrayBuffers处理为字符串。
for (var i = 0; i < args.length; i++) {
if (utils.typeName(args[i]) == 'ArrayBuffer') {
args[i] = base64.fromArrayBuffer(args[i]);
}
}
var callbackId = service + cordova.callbackId++,
argsJson = JSON.stringify(args);
if (success || fail) {
cordova.callbacks[callbackId] = {
success: success,
fail: fail
};
}
var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
console.log('[DEBUG] exec msgs:' + msgs);
// 如果Java接收到AgsJSON为NULL,请使用提示桥模式再次尝试。
// 这种情况很少发生,例如某些Unicode字符通过星系s2上的桥时。见CB-2666。
if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
androidExec(success, fail, service, action, args);
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
} else if (msgs) {
messagesFromNative.push(msgs);
// 始终处理异步以避免异常导致堆栈混乱。
nextTick(processMessages);
}
}
androidExec.init = function () {
bridgeSecret = _pcMode ? 20190620 : +prompt('', 'gap_init:' + nativeToJsBridgeMode);
// bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
console.log('[DEBUG] 触发onNativeReady事件 bridgeSecret = ' + bridgeSecret);
channel.onNativeReady.fire();
};
function pollOnceFromOnlineEvent() {
pollOnce(true);
}
function pollOnce(opt_fromOnlineEvent) {
if (bridgeSecret < 0) {
// 当NativeToJSmessageQueue重置页面上的联机状态转换时,可能会发生这种情况。
// 我们知道没有东西可以取回,所以不需要测验。
return;
}
var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
console.log('[DEBUG] retrieveJsMessages msgs:' + msgs);
if (msgs) {
messagesFromNative.push(msgs);
// 处理同步,因为我们知道我们已经是栈顶了。
processMessages();
}
}
function pollingTimerFunc() {
if (pollEnabled) {
pollOnce();
setTimeout(pollingTimerFunc, 50);
}
}
function hookOnlineApis() {
function proxyEvent(e) {
cordova.fireWindowEvent(e.type);
}
// 网络模块负责触发在线和离线事件。
// 它目前只在文档上触发它们,所以我们将它们桥接到这里的窗口(在第一次监听exec()相关的在线/离线事件时)。
window.addEventListener('online', pollOnceFromOnlineEvent, false);
window.addEventListener('offline', pollOnceFromOnlineEvent, false);
cordova.addWindowEventHandler('online');
cordova.addWindowEventHandler('offline');
document.addEventListener('online', proxyEvent, false);
document.addEventListener('offline', proxyEvent, false);
}
hookOnlineApis();
androidExec.jsToNativeModes = jsToNativeModes;
androidExec.nativeToJsModes = nativeToJsModes;
androidExec.setJsToNativeBridgeMode = function (mode) {
if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
mode = jsToNativeModes.PROMPT;
}
nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
jsToNativeBridgeMode = mode;
};
androidExec.setNativeToJsBridgeMode = function (mode) {
if (mode == nativeToJsBridgeMode) {
return;
}
if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
pollEnabled = false;
}
nativeToJsBridgeMode = mode;
// 告诉本机端切换模式。否则,它将由androidexec.init()设置
if (bridgeSecret >= 0) {
nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
}
if (mode == nativeToJsModes.POLLING) {
pollEnabled = true;
setTimeout(pollingTimerFunc, 1);
}
};
function buildPayload(payload, message) {
var payloadKind = message.charAt(0);
if (payloadKind == 's') {
payload.push(message.slice(1));
} else if (payloadKind == 't') {
payload.push(true);
} else if (payloadKind == 'f') {
payload.push(false);
} else if (payloadKind == 'N') {
payload.push(null);
} else if (payloadKind == 'n') {
payload.push(+message.slice(1));
} else if (payloadKind == 'A') {
var data = message.slice(1);
payload.push(base64.toArrayBuffer(data));
} else if (payloadKind == 'S') {
payload.push(window.atob(message.slice(1)));
} else if (payloadKind == 'M') {
var multipartMessages = message.slice(1);
while (multipartMessages !== "") {
var spaceIdx = multipartMessages.indexOf(' ');
var msgLen = +multipartMessages.slice(0, spaceIdx);
var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
buildPayload(payload, multipartMessage);
}
} else {
payload.push(JSON.parse(message));
}
}
// 处理由NativeToJSmessageQueue.java编码的单个消息。
function processMessage(message) {
var firstChar = message.charAt(0);
if (firstChar == 'J') {
// 这在Java方面被贬低。它不能在启用了CSP的情况下工作。
eval(message.slice(1));
} else if (firstChar == 'S' || firstChar == 'F') {
var success = firstChar == 'S';
var keepCallback = message.charAt(1) == '1';
var spaceIdx = message.indexOf(' ', 2);
var status = +message.slice(2, spaceIdx);
var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
var payloadMessage = message.slice(nextSpaceIdx + 1);
var payload = [];
buildPayload(payload, payloadMessage);
cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
} else {
console.log("processMessage failed: invalid message: " + JSON.stringify(message));
}
}
function processMessages() {
// 检查是否存在可重入情况。
if (isProcessing) {
return;
}
if (messagesFromNative.length === 0) {
return;
}
isProcessing = true;
try {
var msg = popMessageFromQueue();
// console.log('[DEBUG] popMessageFromQueue msg: ' + msg);
// Java端可以发送一条*消息来指示它仍然有消息等待被检索。
if (msg == '*' && messagesFromNative.length === 0) {
nextTick(pollOnce);
return;
}
processMessage(msg);
} finally {
isProcessing = false;
if (messagesFromNative.length > 0) {
nextTick(processMessages);
}
}
}
function popMessageFromQueue() {
var messageBatch = messagesFromNative.shift();
if (messageBatch == '*') {
return '*';
}
var spaceIdx = messageBatch.indexOf(' ');
var msgLen = +messageBatch.slice(0, spaceIdx);
var message = messageBatch.substr(spaceIdx + 1, msgLen);
messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
if (messageBatch) {
messagesFromNative.unshift(messageBatch);
}
return message;
}
module.exports = androidExec;
});
define("cordova/init", function (require, exports, module) {
var channel = require('cordova/channel');
var cordova = require('cordova');
var modulemapper = require('cordova/modulemapper');
var platform = require('cordova/platform');
var pluginloader = require('cordova/pluginloader');
var utils = require('cordova/utils');
broadcaster = require('com.broadcaster');
var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
function logUnfiredChannels(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i].state != 2) {
console.log('Channel not fired: ' + arr[i].type);
}
}
}
window.setTimeout(function () {
if (channel.onDeviceReady.state != 2) {
console.log('deviceready has not fired after 50 seconds.');
logUnfiredChannels(platformInitChannelsArray);
logUnfiredChannels(channel.deviceReadyChannelsArray);
}
}, 50000);
// 在需要任何模块之前替换navigator(),以确保它尽快发生。
// 我们替换它,这样就可以重写不能被删除的属性。
function replaceNavigator(origNavigator) {
var CordovaNavigator = function () { };
CordovaNavigator.prototype = origNavigator;
var newNavigator = new CordovaNavigator();
// 这种解决方法实际上只适用于比function.bind更新的新API。
// 没有它,API(如getgamepads()中断)。
if (CordovaNavigator.bind) {
for (var key in origNavigator) {
if (typeof origNavigator[key] == 'function') {
newNavigator[key] = origNavigator[key].bind(origNavigator);
} else {
(function (k) {
utils.defineGetterSetter(newNavigator, key, function () {
return origNavigator[k];
});
})(key);
}
}
}
return newNavigator;
}
if (window.navigator) {
window.navigator = replaceNavigator(window.navigator);
}
if (!window.console) {
window.console = {
log: function () { }
};
}
if (!window.console.warn) {
window.console.warn = function (msg) {
this.log("warn: " + msg);
};
}
// 将暂停、恢复和设备附加频道注册为文档上的事件。
channel.onPause = cordova.addDocumentEventHandler('pause');
channel.onResume = cordova.addDocumentEventHandler('resume');
channel.onActivated = cordova.addDocumentEventHandler('activated');
channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
// 监听domcontentloaded并通知我们的频道订户。
if (document.readyState == 'complete' || document.readyState == 'interactive') {
channel.onDOMContentLoaded.fire();
} else {
document.addEventListener('DOMContentLoaded', function () {
console.log('[DEBUG] 触发onDOMContentLoaded事件');
channel.onDOMContentLoaded.fire();
}, false);
}
// _ native