UNPKG

@hap-toolkit/server

Version:

hap server

1,890 lines (1,688 loc) 2.08 MB
;( this.nativeLog || function(s) { console.log(s) } )('### App framework ### Start: 0.0.6 Build 20210906 HEAD^ 39a30d6c') var framework_VERSION = '0.0.7' var global = this, process = { env: {} } var setTimeout = global.setTimeout ;(function(factory) { typeof define === 'function' && define.amd ? define(['deep-diff'], factory) : factory() })(function() { 'use strict' var subversion = { framework: '0.0.6', packager: '0.0.5' } /* * Copyright (c) 2021-present, the hapjs-platform Project Contributors * SPDX-License-Identifier: Apache-2.0 */ // 缓存原始控制台 let _oriConsole = null // 日志等级 const _logLevels = ['off', 'error', 'warn', 'info', 'log', 'debug', 'trace'] // 日志等级检索 let _levelMap = {} /** * 生成日志等级的矩阵表,用于迅速判断日志消息是否处理 */ function _makeLevelMap() { _logLevels.forEach(level => { const levelIndex = _logLevels.indexOf(level) _levelMap[level] = {} _logLevels.forEach(type => { const typeIndex = _logLevels.indexOf(type) if (typeIndex <= levelIndex) { _levelMap[level][type] = true } }) }) } /** * 判断日志消息是否被处理 * @param {string} type * @return {boolean} */ function _checkLevel(type) { // 获取当前log等级 const logLevel = (global.Env && global.Env.logLevel) || 'log' return _levelMap[logLevel] && _levelMap[logLevel][type] } /** * 根据运行环境设置控制台 */ function setNativeConsole() { _oriConsole = global.console _makeLevelMap() const { trace, debug, log, info, warn, error, time, timeEnd, record } = console const globalConsole = console console._ori = { trace, debug, log, info, warn, error, time, timeEnd, record } if (!console._ori.record) { console._ori.record = console._ori.info } globalConsole.trace = (...args) => { if (_checkLevel('trace')) { console._ori.debug.apply(console, args) } } globalConsole.debug = (...args) => { if (_checkLevel('debug')) { ;(console._ori.debug || console._ori.trace).apply(console, args) } } globalConsole.log = (...args) => { if (_checkLevel('log')) { console._ori.log.apply(console, args) } } globalConsole.info = (...args) => { if (_checkLevel('info')) { console._ori.info.apply(console, args) } } globalConsole.warn = (...args) => { if (_checkLevel('warn')) { console._ori.warn.apply(console, args) } } globalConsole.error = (...args) => { if (_checkLevel('error')) { console._ori.error.apply(console, args) } } globalConsole.time = (...args) => { if (global.Env && global.Env.logPerf && _checkLevel('info')) { console._ori.time.apply(console, args) } } globalConsole.timeEnd = (...args) => { if (global.Env && global.Env.logPerf && _checkLevel('info')) { console._ori.timeEnd.apply(console, args) } } globalConsole.record = (...args) => { if (global.Env && global.Env.logPerf && _checkLevel('info')) { console._ori.record.apply(console, args) } } } /** * 恢复原始控制台 */ function resetNativeConsole() { _levelMap = {} global.console = _oriConsole } var _console = { setNativeConsole, resetNativeConsole } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ // 缓存原始控制台 let _oriHistory = null /** * 设置原生路由 */ function setNativeRouter() { _oriHistory = global.history } /** * 恢复原始控制台 */ function resetNativeRouter() { global.history = _oriHistory } var _router = { setNativeRouter, resetNativeRouter } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ let _oriSetTimeout = null let _oriSetInterval = null let _oriRequestAnimationFrame = null let _oriClearTimeout = null let _setTimeoutNative = null let _oriClearInterval = null let _setIntervalNative = null let _oriCancelAnimationFrame = null let _requestAnimationFrameNative = null function setNativeProfiler() { if (!global.profiler) { global.profiler = { // 是否启用 isEnabled() { return false }, saveProfilerData: () => {}, record: global.console.record, time: global.console.time, timeEnd: global.console.timeEnd } } // 属性形式,底层方法只调用一次,避免性能干扰 global.profiler._isEnabled = global.profiler.isEnabled() } /** * 设置原生定时器 */ function setNativeTimer() { { // H5环境下:重新封装,在setTimeout环境下保证updateFinish事件的产生 global.setTimeoutNative = function(iid, timerId, time) { _oriSetTimeout(function() { global.setTimeoutCallback(timerId) }, time) } global.setIntervalNative = function(iid, timerId, time) { _oriSetInterval(function() { global.setIntervalCallback(timerId) }, time) } global.requestAnimationFrameNative = function(iid, timerId, time) { _oriRequestAnimationFrame(function() { global.requestAnimationFrameCallback(timerId) }, time) } } // 缓存原有 _oriSetTimeout = global.setTimeout _oriSetInterval = global.setInterval _oriRequestAnimationFrame = global.requestAnimationFrame _oriClearTimeout = global.clearTimeoutNative _setTimeoutNative = global.setTimeoutNative _oriClearInterval = global.clearIntervalNative _setIntervalNative = global.setIntervalNative _oriCancelAnimationFrame = global.cancelAnimationFrameNative _requestAnimationFrameNative = global.requestAnimationFrameNative // 缓存计时器 const timerMap = {} let timerId = 0 // Timer回调句柄 if (typeof _setTimeoutNative === 'function') { global.setTimeoutWrap = function(iid, cb, time) { timerMap[++timerId] = cb global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### setTimeoutWrap ${timerId}----`) _setTimeoutNative(iid, timerId, time || 4) return timerId } global.setTimeout = function(cb, time) { return global.setTimeoutWrap(-1, cb, time) } global.setTimeoutCallback = function(id) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### setTimeout 执行回调 ${id}----`) // 执行定时器回调,并删除记录 if (typeof timerMap[id] === 'function') { timerMap[id]() delete timerMap[id] } } global.clearTimeout = global.clearTimeoutWrap = function(id) { if (typeof _oriClearTimeout === 'function') { const idInt = parseInt(id) !isNaN(idInt) && _oriClearTimeout(idInt) } if (typeof timerMap[id] === 'function') { delete timerMap[id] } else { timerMap[id] = undefined } } } if (typeof _setIntervalNative === 'function') { global.setIntervalWrap = function(iid, cb, time) { timerMap[++timerId] = cb global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### setIntervalWrap ${timerId}----`) _setIntervalNative(iid, timerId, time || 4) return timerId } global.setInterval = function(cb, time) { return global.setIntervalWrap(-1, cb, time) } global.setIntervalCallback = function(id) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### setInterval 执行回调 ${id}----`) // 执行定时器回调 if (typeof timerMap[id] === 'function') { timerMap[id]() } } global.clearInterval = global.clearIntervalWrap = function(id) { if (typeof _oriClearInterval === 'function') { const idInt = parseInt(id) !isNaN(idInt) && _oriClearInterval(idInt) } if (typeof timerMap[id] === 'function') { delete timerMap[id] } else { timerMap[id] = undefined } } } if (typeof _requestAnimationFrameNative === 'function') { global.requestAnimationFrameWrap = function(iid, cb) { timerMap[++timerId] = cb global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### requestAnimationFrame ${timerId}----`) _requestAnimationFrameNative(iid, timerId) return timerId } global.requestAnimationFrame = function(cb) { return global.requestAnimationFrameWrap(-1, cb) } global.requestAnimationFrameCallback = function(id) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### requestAnimationFrame 执行回调 ${timerId}----`) // 执行定时器回调 if (typeof timerMap[id] === 'function') { timerMap[id]() } } global.cancelAnimationFrame = global.cancelAnimationFrameWrap = function(id) { if (typeof _oriCancelAnimationFrame === 'function') { const idInt = parseInt(id) !isNaN(idInt) && _oriCancelAnimationFrame(idInt) } if (typeof timerMap[id] === 'function') { delete timerMap[id] } else { timerMap[id] = undefined } } } } /** * 恢复原始定时器 */ function resetNativeTimer() { global.setTimeout = _oriSetTimeout global.clearTimeout = _oriClearTimeout global.clearTimeoutWrap = null global.setTimeoutCallback = null global.setTimeoutWrap = null global.setInterval = _oriSetInterval global.clearInterval = _oriClearInterval global.clearIntervalWrap = null global.setIntervalCallback = null global.setIntervalWrap = null global.requestAnimationFrame = _oriRequestAnimationFrame global.cancelAnimationFrame = _oriCancelAnimationFrame global.cancelAnimationFrameWrap = null global.requestAnimationFrameCallback = null global.requestAnimationFrameWrap = null } function freezePrototype() { Object.freeze(Object) Object.freeze(Array) Object.freeze(Object.prototype) Object.freeze(Array.prototype) Object.freeze(String.prototype) Object.freeze(Number.prototype) Object.freeze(Boolean.prototype) Object.freeze(Error.prototype) Object.freeze(Date.prototype) Object.freeze(RegExp.prototype) } var common = { setNativeConsole: _console.setNativeConsole, resetNativeConsole: _console.resetNativeConsole, setNativeProfiler, setNativeTimer, resetNativeTimer, setNativeRouter: _router.setNativeRouter, resetNativeRouter: _router.resetNativeRouter, freezePrototype } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ /** * 使用Function构造函数创建函数并执行 * @param {object} globalObjects - 参数组成的对象 * @param {string} body - 函数体 * @return {any} */ function callFunction(globalObjects, body) { const globalKeys = [] const globalValues = [] for (const key in globalObjects) { globalKeys.push(key) globalValues.push(globalObjects[key]) } globalKeys.push(body) profiler.record(`### App Performance ### 编译JS[PERF:compileJS]开始:${new Date().toJSON()}`) profiler.time(`PERF:compileJS`) const fn = new Function(...globalKeys) profiler.timeEnd(`PERF:compileJS`) profiler.record(`### App Performance ### 编译JS[PERF:compileJS]结束:${new Date().toJSON()}`) profiler.record(`### App Performance ### 执行JS[PERF:executeJS]开始:${new Date().toJSON()}`) profiler.time(`PERF:executeJS`) const ret = fn(...globalValues) profiler.timeEnd(`PERF:executeJS`) profiler.record(`### App Performance ### 执行JS[PERF:executeJS]结束:${new Date().toJSON()}`) return ret } // global.__dateCompileCost = global.__dateCompileCost || 0 // global.__timeInvokeCount = global.__timeInvokeCount || 1 /** * 使用V8原生方法创建函数并执行 * @param {object} globalObjects - 参数组成的对象 * @param {string} body - 函数体 * @param {string} bundleUrl - 关联文件来源 * @return {any} */ function callFunctionNative(globalObjects, body, bundleUrl) { let script = '(function (' const globalKeys = [] const globalValues = [] for (const key in globalObjects) { globalKeys.push(key) globalValues.push(globalObjects[key]) } for (let i = 0; i < globalKeys.length - 1; ++i) { script += globalKeys[i] script += ',' } script += globalKeys[globalKeys.length - 1] script += ') {' script += body script += ` })` // const timeInvokeIndex = global.__timeInvokeCount++ // const dateCompileS = new Date() // profiler.record(`### App Performance ### 编译JS[PERF:compileJS]开始:${new Date().toJSON()}`) // profiler.time(`PERF:compileJS:${timeInvokeIndex}`) let ret = global.compileAndRunScript(script, bundleUrl) // profiler.timeEnd(`PERF:compileJS:${timeInvokeIndex}`) // profiler.record(`### App Performance ### 编译JS[PERF:compileJS]结束:${new Date().toJSON()}`) // const dateCompileE = new Date() // global.__dateCompileCost += dateCompileE - dateCompileS // profiler.record( // `### App Performance ### 编译JS[PERF:compileJS]累积耗时:${global.__dateCompileCost}ms` // ) // profiler.record(`### App Performance ### 执行JS[PERF:executeJS]开始:${new Date().toJSON()}`) // profiler.time(`PERF:executeJS:${timeInvokeIndex}`) if (ret && typeof ret === 'function') { ret = ret(...globalValues) } // profiler.timeEnd(`PERF:executeJS:${timeInvokeIndex}`) // profiler.record(`### App Performance ### 执行JS[PERF:executeJS]结束:${new Date().toJSON()}`) return ret } /** * 使用脚本创建函数并执行 * @param {object} globalObjects - 参数组成的对象 * @param {string} body - 函数体 * @param {string} bundleUrl - 关联文件来源 * @return {any} */ function invokeScript(globalObjects, body, bundleUrl) { if (typeof global.compileAndRunScript === 'function') { return callFunctionNative(globalObjects, body, bundleUrl) } return callFunction(globalObjects, body) } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ /** * 获取对象类型,从[Object object]中提取object部分 * @param v * @returns {string} */ function $typeof(v) { const s = Object.prototype.toString.call(v) return s.substring(8, s.length - 1).toLowerCase() } /** * 创建缓存版本的函数(函数值被缓存起来,下次调用时先从缓存中查找) * @param fn * @returns {cachedFn} */ function $cached(fn) { const cache = Object.create(null) return function cachedFn(str) { const hit = cache[str] return hit || (cache[str] = fn(str)) } } /** * -xxx转换为Xxx * @type {RegExp} */ const camelizeReg = /-(\w)/g const $camelize = $cached(str => { return str.replace(camelizeReg, toUpper) }) function toUpper(_, c) { return c ? c.toUpperCase() : '' } /** * Xxx转换为-xxx * @type {RegExp} */ const hyphenateReg = /([a-z\d])([A-Z])/g const $hyphenate = $cached(str => { return str.replace(hyphenateReg, '$1-$2').toLowerCase() }) /** * 合并对象 * @param {Object} target * @param {Object} src * @returns {*} */ function $extend(target, ...src) { if (typeof Object.assign === 'function') { Object.assign(target, ...src) } else { const first = src.shift() // 覆盖旧值 for (const key in first) { target[key] = first[key] } if (src.length) { $extend(target, ...src) } } return target } /** * 是否为字符串 * @param {*} n * @returns {boolean} */ function isString(n) { return Object.prototype.toString.call(n) === '[object String]' } /** * 是否为函数 * @param {*} n * @returns {boolean} */ function isFunction(n) { return typeof n === 'function' } /** * 是否为对象 * @param {*} obj * @returns {boolean} */ function isObject(obj) { return obj !== null && typeof obj === 'object' } /** * 是否为空对象 * @param {*} obj * @returns {boolean} */ function isEmptyObject(obj) { for (const key in obj) { return false } return true } const toString = Object.prototype.toString const OBJECT_STRING = '[object Object]' /** * 对象是否为纯字典对象(仅有key,value) * @param {*} obj * @return {boolean} */ function isPlainObject(obj) { return toString.call(obj) === OBJECT_STRING } /** * 字符串是否以‘$’或‘_’开头(系统保留变量名) * @param {string} str * @returns {boolean} */ function isReserved(str) { const c = (str + '').charCodeAt(0) return c === 0x24 || c === 0x5f } const REGEXP_APPLICATION = /^@(app)-application\// const REGEXP_COMPONENT = /^@(app)-component\// const REGEXP_MODULE = /^@(app)-module\// const isApplication = name => !!name.match(REGEXP_APPLICATION) const isComponent = name => !!name.match(REGEXP_COMPONENT) /** * 删除其中约定的前缀 * @param {string} str * @return {string} */ function removeAppPrefix(str) { const result = str .replace(REGEXP_APPLICATION, '') .replace(REGEXP_COMPONENT, '') .replace(REGEXP_MODULE, '') return result } // 全局唯一回调Id let invokeCallbackId = 0 function uniqueCallbackId() { return ++invokeCallbackId } // 全局唯一session,用于Framework性能火焰图统计 let _session function getSessionInstance() { return _session } let _isFirstOnShow = true function changeIsFirstOnShowToFalse() { _isFirstOnShow = false } function getIsFirstOnShow() { return _isFirstOnShow } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ // 回调上下文映射 const _callbackSourceMap = {} // 模块宿主的映射 const _moduleHostMap = {} // 原生模块定义表 let _nativeModuleMap = {} // 原生模块常量 const MODULES = { // 同步,回调,订阅 MODE: { SYNC: 0, CALLBACK: 1, SUBSCRIBE: 2 }, // 方法,属性,事件 TYPE: { METHOD: 0, ATTRIBUTE: 1, EVENT: 2 }, // 传递参数的类型 NORMALIZE: { RAW: 0, JSON: 1 }, // 方法返回的数据类型 RESULT: { MODULE_INST: 0 }, // 是否支持多回调 MULTIPLE: { SINGLE: 0, MULTI: 1 } } /** * 初始化原生模块配置信息对象 * @param modulesDef * @param ifReplace 是否覆盖原来的实现 */ function initModulesDef(modulesDef, ifReplace = true) { // 转换为数组 let arr = [] if (Array.isArray(modulesDef)) { arr = modulesDef } else { arr.push(modulesDef) } arr.forEach(item => { const name = item.name global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### 注册模块---- ${name} <${item.__type__}>`) // 初始化`modulesDef[moduleName]` let nativeModuleDef = _nativeModuleMap[name] if (!nativeModuleDef) { nativeModuleDef = { type: item.__type__, name: item.name, methods: {}, attributes: {}, events: {}, // 是否可实例化,可实例化为类,否则为普通模块 instantiable: item.instantiable } _nativeModuleMap[name] = nativeModuleDef } if (!nativeModuleDef.methods) { nativeModuleDef.methods = {} } const methods = nativeModuleDef.methods // 记录模块的所有方法名 if (item.methods && item.methods.length) { item.methods.forEach(method => { const methodName = method.name // 默认:同步 if (method.mode === undefined) { method.mode = MODULES.MODE.SYNC } // 默认:方法 if (method.type === undefined) { method.type = MODULES.TYPE.METHOD } // 默认:调底层时的类型 if (method.normalize === undefined) { method.normalize = MODULES.NORMALIZE.JSON } // 默认:模块的方法 if (method.instanceMethod === undefined) { method.instanceMethod = false } // 不允许以下情况存在 if (!nativeModuleDef.instantiable && method.instanceMethod) { throw new Error(`模块 ${nativeModuleDef.name} 配置定义错误`) } if (method.type === MODULES.TYPE.ATTRIBUTE) { const alias = method.alias const access = method.access nativeModuleDef.attributes[alias] = nativeModuleDef.attributes[alias] || {} nativeModuleDef.attributes[alias][access] = method nativeModuleDef.attributes[alias].instanceMethod = method.instanceMethod } else if (method.type === MODULES.TYPE.EVENT) { const alias = method.alias nativeModuleDef.events[alias] = method } if (!methodName) { console.warn(`### App Framework ### 模块 ${name} 的接口没有name属性`) } else { // 覆盖旧方法 if (!methods[methodName] || ifReplace) { methods[methodName] = method global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### 注册模块 ${name} 接口---- ${methodName}`) } } }) } }) } /** * 创建模块对象(loader中声明) * @param inst * @param name * @param moduleInstId */ function requireModule(inst, name, moduleInstId) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### require模块:${name}`) const matchedModuleNames = [name] // 模块对象 let moduleObj = {} // 模块,可能为模块对象,也可能处于模块对象的某一层级 let moduleItem // 如果没有定义子模块,则遍历查找所有匹配的模块 if (name.indexOf('.') < 0) { const prefix = name + '.' for (const moduleName in getNativeModuleMap()) { if (moduleName.startsWith(prefix)) { matchedModuleNames.push(moduleName) } } } // 初始化模块名对应的模块 matchedModuleNames.forEach(fullName => { const nativeModuleDef = getNativeModuleMap()[fullName] // 如果找不到定义, 则跳过 if (!nativeModuleDef) { return } // 子模块名 let subName = fullName.replace(name, '') if (subName.substr(0, 1) === '.') { subName = subName.substr(1) } // 模块为类,特殊处理 if (nativeModuleDef.instantiable) { const classDef = function(...args) { const retObj = classDef.__init__(...args) Object.defineProperty(this, '_instId', { enumerable: false, configurable: false, writable: false, value: retObj && retObj.instId }) } if (subName.length === 0) { // 模块对象仅包含一个模块,直接覆盖模块对象 moduleObj = classDef } else { // 模块对象包含多个模块,写模块对象的对应位置 const subPath = subName.split('.') if (subPath.length > 0) { const lastKey = subPath.pop() createObjByPath(moduleObj, subPath)[lastKey] = classDef } } } // 获取模块对象中模块的指针 if (fullName === name) { moduleItem = moduleObj } else { if (subName.length > 0) { const subPath = subName.split('.') if (subPath.length > 0) { moduleItem = createObjByPath(moduleObj, subPath) } } } // 初始化模块 initModule(inst, moduleItem, nativeModuleDef, moduleInstId) }) if (Object.keys(moduleObj).length === 0) { throw new Error(`请确认引入的模块[${name}]:名称正确并且在manifest.json的features中声明`) } return moduleObj } /** * 创建层级对象 * @param obj * @param pathList */ function createObjByPath(obj, pathList) { if (!obj) { return } let cur = obj pathList.forEach(p => { if (!(p in cur)) { cur[p] = {} } cur = cur[p] }) return cur } /** * 初始化模块 * @param inst * @param module * @param moduleDef * @param moduleInstId */ function initModule(inst, module, moduleDef, moduleInstId) { // 初始化模块方法 const methods = moduleDef.methods for (const methodName in methods) { const method = methods[methodName] // 原型:承载方法的定义 const obj = method.instanceMethod ? module.prototype : module // 将原生模块的函数定义通过invoke函数封装为Action函数 if (methodName in obj) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口函数${methodName}---- 重复定义` ) } const modMethod = function(...args) { if (inst && inst._isApp && !inst._defined) { throw new Error( `请确认Native方法调用[${moduleDef.name}.${methodName}()]发生在应用app的生命周期的创建['onCreate()']之后` ) } const instId = Object.prototype.hasOwnProperty.call(this, '_instId') ? this._instId : moduleInstId return invokeNative(inst, moduleDef, method, args, instId) } Object.defineProperty(obj, methodName, { configurable: false, enumerable: true, get() { return modMethod.bind(this) }, set(val) { console.warn( `### App Framework ### 接口${moduleDef.name}的方法(${methodName})为可读,不可覆盖` ) } }) global.Env && global.Env.logLevel === 'trace' && console.trace( `### App Framework ### require---- 模块${moduleDef.name}接口函数${methodName}` ) } // 初始化模块属性 const attributes = moduleDef.attributes for (const attributeName in attributes) { const attributeItem = attributes[attributeName] // 原型:承载方法的定义 const obj = attributeItem.instanceMethod ? module.prototype : module Object.defineProperty(obj, attributeName, { configurable: false, enumerable: true, get() { if (!attributeItem[1]) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口属性(${attributeName})不可读` ) } else { let result = this[attributeItem[1].name]() // 处理子属性 if ( (attributeItem[1] && attributeItem[1].subAttrs) || (attributeItem[2] && attributeItem[2].subAttrs) ) { const _this = this if (!result) { result = {} } let allAttrs = [] if (attributeItem[1] && attributeItem[1].subAttrs) { allAttrs = allAttrs.concat(attributeItem[1].subAttrs) } if (attributeItem[2] && attributeItem[2].subAttrs) { allAttrs = allAttrs.concat(attributeItem[1].subAttrs) } const attrSet = new Set(allAttrs) allAttrs = Array.from(attrSet) for (const subIndex in allAttrs) { const subAttr = allAttrs[subIndex] Object.defineProperty(result, subAttr, { configurable: true, enumerable: true, get() { if ( !attributeItem[1] || !attributeItem[1].subAttrs || attributeItem[1].subAttrs.indexOf(subAttr) < 0 ) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口属性(${attributeName})的子属性(${subAttr})不可读` ) } else { return _this[attributeItem[1].name]()[subAttr] } }, set(val) { if ( !attributeItem[2] || !attributeItem[2].subAttrs || attributeItem[2].subAttrs.indexOf(subAttr) < 0 ) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口属性(${attributeName})的子属性(${subAttr})不可写` ) } else { const valObj = {} valObj[subAttr] = val _this[attributeItem[2].name]({ value: valObj }) } } }) } } return result } }, set(val) { if (!attributeItem[2]) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口属性(${attributeName})不可写` ) } else { this[attributeItem[2].name]({ value: val }) } } }) } // 初始化模块事件 const events = moduleDef.events for (const eventName in events) { const eventItem = events[eventName] eventItem.cache = eventItem.cache || {} // 原型:承载方法的定义 const obj = eventItem.instanceMethod ? module.prototype : module Object.defineProperty(obj, eventName, { configurable: false, enumerable: true, get() { const instId = this._instId === undefined ? -1 : this._instId return eventItem.cache[instId] }, set(val) { if (typeof val !== 'function' && [null, undefined].indexOf(val) === -1) { console.warn( `### App Framework ### 模块${moduleDef.name}的接口事件(${eventName})值类型必须是函数或null` ) } else { const instId = this._instId === undefined ? -1 : this._instId const cb = typeof val === 'function' ? val.bind(this) : val this[eventItem.name]({ success: cb }) eventItem.cache[instId] = val } } }) } } /** * 调用接口方法的函数 * @param inst * @param module * @param method * @param args * @param moduleInstId 对象实例id */ const _callbackArgs = ['success', 'cancel', 'fail', 'complete'] function invokeNative(inst, module, method, args, moduleInstId) { const { name: modName, type: modType } = module const { name: mthName, mode: mthMode, type: mthType, normalize: mthNmlz, multiple: mthMultiple } = method if (!inst || !inst._callbacks) { console.warn(`### App Framework ### 容器已销毁,接口调用(${modName}.${mthName}())无效`) return new Error(`invokeNative: 容器已销毁`) } if (modType === 'feature' && !global.JsBridge) { return new Error(`invokeNative: JsBridge没有初始化`) } else if (modType === 'module' && !global.ModuleManager) { return new Error(`invokeNative: ModuleManager没有初始化`) } profiler.time(`PERF:invokeMod:${modName}.${mthName}()`) const bridge = modType === 'feature' ? global.JsBridge : global.ModuleManager // args仅有一个参数,传参且参数为undefined值时,warn if (args.length > 0 && args[0] === undefined) { console.warn(`### App Framework ### 接口调用${modName}.${mthName}的参数为 undefined`) } const arg0 = args.length > 0 ? args[0] : {} if (arg0 && arg0.callback) { if (arg0.success) { console.warn(`### App Framework ### invoke函数不能同时出现'success'和'callback'参数`) } arg0.success = arg0.callback } // 提取目标参数 let newArgs = {} const cbs = {} if (isObject(arg0)) { for (const arg in arg0) { const value = arg0[arg] if (_callbackArgs.indexOf(arg) >= 0) { if (typeof value === 'function') { cbs[arg] = value } else { console.warn(`### App Framework ### invoke函数的回调参数${arg}类型不是function`) } } else if (arg !== 'callback') { if (mthNmlz === MODULES.NORMALIZE.JSON) { newArgs[arg] = normalize(value, inst) } else { if (typeof arg === 'function') { newArgs[arg] = normalize(value, inst) } else { newArgs[arg] = value } } } } } else if (isFunction(arg0)) { cbs.success = arg0 } else { newArgs = arg0 } if (mthNmlz === MODULES.NORMALIZE.JSON) { newArgs = JSON.stringify(newArgs) } // 调用原生模块函数 if (mthMode === MODULES.MODE.SYNC) { let cbId = '-1' if (mthMultiple === MODULES.MULTIPLE.MULTI && isFunction(arg0)) { cbId = mapInvokeCallbackId(arg0).toString() global.Env && global.Env.logLevel === 'trace' && console.trace(`${mthName} 方法的回调函数参数id:${cbId}`) // 找不到对应的回调,则不执行 if (cbId === '-1') { return } } const ret = bridge.invoke(modName, mthName, newArgs, cbId, moduleInstId) if (ret == null) { console.warn(`### App Framework ### invoke函数 '${modName}.${mthName}' 返回值为null`) return undefined } global.Env && global.Env.logLevel === 'trace' && console.trace( `### App Framework ### invoke函数 '${modName}.${mthName}' 调用成功,返回值为: ${ret}` ) const result = transformModuleResult(inst, ret, module, mthName) return result.data } else { // 异步方法:不传递回调函数时要返回Promsie if (mthType === MODULES.TYPE.METHOD && mthMode === MODULES.MODE.CALLBACK) { cbs.flagCallback = true } let pInst, pRes, pRej const argList = [] if (Object.keys(cbs).length) { // this指向:1040起更新为undefined const thisContext = global.isRpkMinPlatformVersionGEQ(1040) ? undefined : cbs // 需要回调 let cbId = -1 // 多监听场景,避免同一回调指针,重复监听 if (mthMultiple === MODULES.MULTIPLE.MULTI) { cbId = mapInvokeCallbackId(cbs.success) if (cbId === -1) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### 新增监听实例,id:${cbId}`) cbId = uniqueCallbackId() } } else { cbId = uniqueCallbackId() } inst._callbacks[cbId] = ret => { const callbacks = cbs const result = transformModuleResult(inst, ret, module, mthName) const code = result.code const data = result.data if (code === 0 && callbacks.success) { callbacks.success.call(thisContext, data) } else if (code === 100 && callbacks.cancel) { callbacks.cancel.call(thisContext) } else if (code >= 200 && callbacks.fail) { callbacks.fail.call(thisContext, data, code) } if (callbacks.complete) { callbacks.complete.call(thisContext, data) } if (pInst) { code === 0 ? pRes({ data }) : pRej({ data, code }) } } _callbackSourceMap[cbId] = { instance: inst.id.toString(), preserved: mthMode === MODULES.MODE.SUBSCRIBE, cbFunc: cbs.success } argList.push(newArgs) argList.push(cbId.toString()) } else { // 无需回调 argList.push(newArgs) argList.push('-1') } // 调用原生模块函数 bridge.invoke(modName, mthName, ...argList, moduleInstId) profiler.timeEnd(`PERF:invokeMod:${modName}.${mthName}()`) // 是否要返回Promise if ( mthType === MODULES.TYPE.METHOD && mthMode === MODULES.MODE.CALLBACK && Object.keys(cbs).length === 1 ) { return (pInst = new Promise((res, rej) => { pRes = res pRej = rej })) } } } /** * 分情况返回不同模块 * @param inst * @param result * @param module * @param mthName */ function transformModuleResult(inst, result, module, mthName) { const retObj = typeof result === 'string' ? JSON.parse(result) : result || {} const retCnt = retObj.content if (retCnt && retCnt._nativeType === MODULES.RESULT.MODULE_INST) { // 模块实例 if (module.instantiable && mthName === '__init__') { retObj.data = retCnt } else { retObj.data = requireModule(inst, retCnt.name, retCnt.instId) } inst._nativeInstList && inst._nativeInstList.push(result) // 保持对句柄的引用 retObj.data.instHandler = retCnt.instHandler } else { // 普通模块 retObj.data = retCnt } return retObj } /** * 参数转换,全部转为基础类型 * @param v * @param inst * @returns {*} */ function normalize(v, inst) { const type = $typeof(v) switch (type) { case 'undefined': case 'null': return '' // 空字符串 case 'regexp': return v.toString() // 正则表达式 case 'date': return v.toISOString() // 日期 case 'number': case 'string': case 'boolean': case 'array': case 'object': return v // 其余一律返回原始对象 case 'function': const cbId = uniqueCallbackId() if (!inst._callbacks) { global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### normalize() inst实例已经销毁,不再注册回调`) } else { inst._callbacks[cbId] = v } _callbackSourceMap[cbId] = { instance: inst.id.toString(), preserved: false, cbFunc: v } return cbId.toString() default: return JSON.stringify(v) // 其余一律转换为字符串 } } /** * 映射回调id到对象实例Id * @param id * @returns {*} */ function mapInvokeCallback(id) { const info = _callbackSourceMap[id] if (info && info.preserved === true); else { _callbackSourceMap[id] = undefined } return info } /** * 映射回调对象到回调id * @param cb * @returns {cbId} */ function mapInvokeCallbackId(cb) { let cbId = -1 for (const id in _callbackSourceMap) { if ( _callbackSourceMap[id] && _callbackSourceMap[id].cbFunc && _callbackSourceMap[id].cbFunc === cb ) { cbId = id break } } return cbId } function getModuleHostMap(id) { return _moduleHostMap[id] } function setModuleHostMap(id, value) { _moduleHostMap[id] = value } function getNativeModuleMap() { return _nativeModuleMap } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ class ModuleHost { constructor(id) { this.id = id // 唯一id, 由原生端生成 this._callbacks = {} this._nativeInstList = [] setModuleHostMap(id, this) } /** * 接收接口回调的函数 * @param inst * @param callbackId * @param data * @param ifKeepAlive * @return {Error} */ invoke(inst, callbackId, data, ifKeepAlive) { global.Env && global.Env.logLevel === 'trace' && console.trace( `### App Framework ### 调用对象(${inst.id})的回调(${callbackId}) 参数:`, JSON.stringify(data) ) const callback = inst._callbacks[callbackId] if (typeof callback === 'function') { // 必须是函数 // 执行回调 const ret = callback(data) // 如果是定时器函数,则保留;否则清除(只使用一次) if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) { inst._callbacks[callbackId] = undefined } return ret } else { return new Error(`invoke: 无效invoke回调函数Id "${callbackId}"`) } } destroy() { this._callbacks = null this._nativeInstList = null setModuleHostMap(this.id, null) } } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ /** * 注册Api模块 * @param modulesConf * @param type feature | module 默认为feature */ function registerModules(modulesConf, type = 'feature') { profiler.record( `### App Performance ### 注册模块[PERF:registerMod]开始:${new Date().toJSON()}` ) // 解析字符串 if (typeof modulesConf === 'string') { modulesConf = JSON.parse(modulesConf) } global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### registerModules---- `, JSON.stringify(modulesConf)) modulesConf = modulesConf.map(function(module) { module.__type__ = type return module }) if (typeof modulesConf === 'object') { initModulesDef(modulesConf) } profiler.record( `### App Performance ### 注册模块[PERF:registerMod]结束:${new Date().toJSON()}` ) } /** * 接受来自原生的事件或回调 * @param event 返回结果 * @returns {*} 结果数组,无返回值, 'invalid'表示无效事件 */ function execInvokeCallback(event) { if (typeof event === 'string') { event = JSON.parse(event) } // 根据回调Id找到对应的实例映射 const id = mapInvokeCallback(event.callback) global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### 处理invoke回调----`, JSON.stringify(id)) if (id) { // 判断回调来源 const instance = getModuleHostMap(id.instance) if (instance) { const args = [instance, event.callback, event.data, id.preserved] if (!instance._callbacks) { return new Error(`execInvokeCallback: 回调函数所属对象已经无效 "${instance.id}"`) } return instance.invoke(...args) } } return new Error(`execInvokeCallback: 无效invoke回调Id "${id && id.instance}"`) } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ /** * 提供Publish-Subscribe模型,作为dock与dsl的中间通讯层 */ class Pubsub { constructor() { this.eventMap = {} } /** * 订阅事件 * @param type {string} 事件名称 * @param fn {function} 响应函数 * @param options {object} 暂时保留 * @return {*} */ subscribe(type, fn, options) { if (options && options.once) { const fnOnce = args => { fn(args) this.remove(type, fnOnce) } return this.subscribe(type, fnOnce) } this.eventMap[type] = this.eventMap[type] || [] if (typeof fn === 'function') { const list = this.eventMap[type] if (list.indexOf(fn) === -1) { list.push(fn) } } } /** * 发布事件 * @param type {string} 事件名称 * @param args {array} 事件触发时的参数 * @param options {object} 暂时保留 * @return {*} */ publish(type, args, options) { let lastRet = null const list = this.eventMap[type] || [] for (let i = 0, len = list.length; i < len; i++) { lastRet = list[i](args, lastRet) } return lastRet } /** * 删除事件订阅 * @param type {string} 事件名称 * @param fn {function} 响应函数 */ remove(type, fn) { if (!this.eventMap[type]) { return } const list = this.eventMap[type] const index = list.indexOf(fn) if (index > -1) { list.splice(index, 1) } } } // An adoption from https://github.com/nodejs/node/blob/f70261fb3089b8acf5f68584ef0285a1c11f54fd/lib/inspector.js#L35 const connectionSymbol = Symbol('connectionProperty') const messageCallbacksSymbol = Symbol('messageCallbacks') const nextIdSymbol = Symbol('nextId') const onMessageSymbol = Symbol('onMessage') class Session extends Pubsub { constructor() { super() this[connectionSymbol] = null this[nextIdSymbol] = 1 this[messageCallbacksSymbol] = new Map() } connect() { if (this[connectionSymbol]) { throw new Error('The inspector session has already connected') } this[connectionSymbol] = // Connection is global Variable in JsEnv // eslint-disable-next-line no-undef new global.Connection(message => this[onMessageSymbol](message)) } [onMessageSymbol](message) { const parsed = JSON.parse(message) try { if (parsed.id) { const callback = this[messageCallbacksSymbol].get(parsed.id) this[messageCallbacksSymbol].delete(parsed.id) if (callback) { if (parsed.error) { return callback(new Error(parsed.error.code, parsed.error.message)) } callback(null, parsed.result) } } else { this.publish(parsed.method, parsed, null) this.publish('inspectorNotification', parsed, null) } } catch (error) { console.log(error) } } post(method, params, callback) { if (!isString(method)) { throw new Error('method must be a string') } if (!callback && isFunction(params)) { callback = params params = null } if (params && typeof params !== 'object') { throw new Error('params not object') } if (callback && typeof callback !== 'function') { throw new Error('callback is not valid') } if (!this[connectionSymbol]) { throw new Error('ERR_INSPECTOR_NOT_CONNECTED') } const id = this[nextIdSymbol]++ const message = { id, method } if (params) { message.params = params } if (callback) { this[messageCallbacksSymbol].set(id, callback) } this[connectionSymbol].dispatch(JSON.stringify(message)) } disconnect() { if (!this[connectionSymbol]) { return } this[connectionSymbol].disconnect() this[connectionSymbol] = null const remainingCallbacks = this[messageCallbacksSymbol].values() if (remainingCallbacks.length > 0) { console.warn('remainingCallbacks will not executed due to inspector closed') } this[messageCallbacksSymbol].clear() this[nextIdSymbol] = 1 } } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ // 依赖的JS模块映射缓存 const _chunkHashCache = new Map() /** * 注册bundle依赖的JS模块映射 * @param chunkHash */ function registerBundleChunks(chunkHash) { if (typeof chunkHash === 'string') { chunkHash = JSON.parse(chunkHash) } for (const path in chunkHash) { const cont = chunkHash[path] _chunkHashCache.set(path, cont) } profiler.record( `### App Performance ### 注册chunks[PERF:registerBundleChunks]开始:${new Date().toJSON()}` ) global.Env && global.Env.logLevel === 'trace' && console.trace( `### App Performance ### 注册chunks[PERF:registerBundleChunks]开始:${new Date().toJSON()}` ) } function requireBundleChunk(filePath) { const cont = _chunkHashCache.get(filePath) if (!cont) { console.warn(`### App Framework ### 加载依赖的JS模块:路径不存在:${filePath}`) } return cont } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ /** * 应用的配置信息 * @property {integer} minPlatformVersion 默认为1 * @property {string} package * @property {string} name * @property {string} versionName * @property {integer} versionCode * @property {object} config */ let manifestJSON = {} /** * 注册RPK中的应用配置 * @param {string} manifest 开发者包中的manifest对象 */ function registerManifest(manifest) { profiler.record( `### App Performance ### 注册manifest[PERF:registerManifest]开始:${new Date().toJSON()}` ) global.Env && global.Env.logLevel === 'trace' && console.trace(`### App Framework ### 注册manifest:${JSON.stringify(manifest)}`) if (typeof manifest === 'string') { manifest = JSON.parse(manifest) } manifestJSON = manifest || {} } /** * 获取Manifest中的字段值 * @param {string} keypath 通过"."分割获取进一步的值 */ function getManifestField(keypath) { const path = keypath.split('.') let result = manifestJSON for (let i = 0, len = path.length; i < len; i++) { result = result[path[i]] if (result === null || result === undefined) { break } } return result } /** * 开发者包是否满足指定值 * @param val {Integer} * @return {boolean} */ function isRpkMinPlatformVersionGEQ(val) { return manifestJSON.minPlatformVersion >= val } let mode = null function isRpkDebugMode() { if (mode !== null) { return mode } mode = false if (manifestJSON.config && manifestJSON.config.debug === true) { mode = true } return mode } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ function initInterface(app) {} /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ const channels = {} class MessageEvent { constructor(type = 'message', dict = {}) { this.type = type this.data = dict.data || null this.timeStamp = Date.now() } } /** * 对外提供一种消息通讯的机制 */ class BroadcastChannel { constructor(name) { if (global.Env.engine === global.ENGINE_TYPE.CARD) { throw new Error(`BroadcastChannel is not supported.`) } // name readOnly Object.defineProperty(this, 'name', { configurable: false, enumerable: true, writable: false, value: String(name) }) this._closed = false this.onmessage = null if (!channels[this.name]) { channels[this.name] = [] } channels[this.name].push(this) } postMessage(message) { if (this._closed) { throw new Error(`BroadcastChannel "${this.name}" is closed.`) } const subscribers = channels[this.name] if (subscribers && subscribers.length) { for (let i = 0; i < subscribers.length; ++i) { const member = subscribers[i] if (member._closed || member === this) { continue } if (typeof member.onmessage === 'function') { member.onmessage(new MessageEvent('message', { data: message })) } } } } close() { if (this._closed) { return } this._closed = true // remove itself from channels. if (channels[this.name]) { const index = channels[this.name].indexOf(this) if (index > -1) { channels[this.name].splice(index, 1) } else { delete channels[this.name] } } } } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ function setUpPromiseRejectionHook() { global.QuickApp = {} // todo expose to user later global.QuickApp.unhandledrejection = (type, promise, reason) => { if (reason.stack) { console.warn(`Unhandled promise rejection: ${reason.stack}`) } } } /* * Copyright (C) 2017, hapjs.org. All rights reserved. */ // 宿主环境类型 const ENGINE_TYPE = { PAGE: 'page', CARD: 'card' } function init() { // [ISSUE-989] setPromiseRejectionCallback setUpPromiseRejectionHook() common.setNativeConsole() common.setNativeProfiler() common.setNativeTimer() com