@hap-toolkit/server
Version:
hap server
1,890 lines (1,688 loc) • 2.08 MB
JavaScript
;(
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