1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Log } from '../../utils/index'; 17import { 18 defineFn, 19 bootstrap, 20 genTimerAPI 21} from './bundle'; 22import { appMap } from './map'; 23import { getPageGlobal } from './helper'; 24import { App } from './App'; 25import Page from '../page/index'; 26import { destroy } from '../page/api/index'; 27import { mockSystemPlugin } from '../extend/systemplugin/index'; 28import { compileBundle } from '../page/entry/init'; 29import { removePrefix } from '../util/index'; 30import { requireModule } from '../page/register'; 31 32/** 33 * Device information for mediaQuery. 34 */ 35export interface MediaQueryInfo { 36 'orientation': string; 37 'deviceType': string; 38 'deviceWidth': string; 39 'deviceHeight': string; 40 'roundScreen': boolean; 41 'width': string; 42 'height': string; 43 'isInit': boolean; 44 'resolution': string; 45 'aspectRatio': string; 46 'darkMode': string; 47} 48 49/** 50 * Information of App. 51 */ 52export interface Options extends MediaQueryInfo { 53 'appInstanceId': string; 54 'packageName': string; 55 'appCreate': boolean; 56 'appCode': string | Function; 57 'pcPreview': string; 58 'resourcesConfiguration': object; 59 'i18n': object; 60 'language': string; 61 'appGlobalData'?: object; 62 'bundleUrl': string; 63} 64 65/** 66 * Framework Services. 67 */ 68export interface Services { 69 service: object; 70 I18n?: Function; 71 dpi?: Function; 72} 73 74interface ParseOptions { 75 $app_define$(...args: any[]): void; // eslint-disable-line camelcase 76 $app_bootstrap$(name: string, config: any, _data: any): void; // eslint-disable-line camelcase 77 $app_require$(name: string): void; // eslint-disable-line camelcase 78} 79 80const pageMap: Map<string, Page> = App.pageMap; 81 82/** 83 * Create app page, run jsbundle code. 84 * @param {Page} page 85 * @param {Options} options 86 * @param {Object} data 87 * @param {Services} services 88 */ 89export function appCreate(page: Page, options: Options, data: object, services: Services): void { 90 if (!options || !options.appCreate || !options.appCode) { 91 return; 92 } 93 if (options.pcPreview && options.pcPreview === 'enable') { 94 mockSystemPlugin(); 95 } 96 const packageName: string = page.packageName; 97 const appPage: Page = new Page(options.appInstanceId, options, packageName, data); 98 pageMap.set(appPage.id, appPage); 99 Log.debug(`Create a page with: ${packageName}.`); 100 appMap[packageName] = new App(packageName, options.appInstanceId); 101 const timerAPIs: object = genTimerAPI(appPage); 102 appMap[packageName].setTimer(timerAPIs); 103 const code = options.appCode; 104 global.__appProto__ = getPageGlobal(packageName); 105 106 // prepare page env methods 107 const appDefine = (...args: any[]): void => defineFn(page, packageName, ...args); 108 const appBootstrap = (name: string, config: any, _data: any): void => { 109 bootstrap(page, packageName, name, config, _data || data); 110 Log.debug(`After create a page(${page.id}).`); 111 }; 112 113 // require in top app(instance) 114 const appRequireModule = name => requireModule(page || appPage, removePrefix(name)); 115 const parseOptions: ParseOptions = { 116 $app_define$: appDefine, 117 $app_bootstrap$: appBootstrap, 118 $app_require$: appRequireModule 119 }; 120 121 // Compile js bundle code and get result. 122 if (typeof code === 'function') { 123 Log.info('call Function directly when appCreate'); 124 code.call(global, parseOptions); 125 } else { 126 // Function with code and use strict mode. 127 const functionCode: string = `(function(global){\n\n"use strict";\n\n ${code} \n\n})(this.__appProto__)`; 128 compileBundle(functionCode, 'app.js', parseOptions, timerAPIs, services); 129 } 130} 131 132/** 133 * Emit onError event. 134 * @param {string} packageName 135 * @param {*} errors 136 */ 137export function appError(packageName: string, errors: any): void { 138 Log.debug(`AppError an app with: ${packageName}.`); 139 const app: App = appMap[packageName]; 140 if (!app) { 141 Log.debug(`AppError an app error ${packageName}.`); 142 return; 143 } 144 Log.debug(`AppError an app error ${packageName}.`); 145 app.emitEvent('hook:onError', errors); 146} 147 148/** 149 * Emit onShow event. 150 * @param {string} packageName - Package name. 151 */ 152export function appShow(packageName: string): void { 153 Log.debug(`Show an app with: ${packageName}.`); 154 const app: App = appMap[packageName]; 155 if (!app) { 156 Log.debug(`Show an app error ${packageName}.`); 157 return; 158 } 159 app.emitEvent('hook:onShow'); 160} 161 162/** 163 * Emit onHide event. 164 * @param {string} packageName - Package name. 165 */ 166export function appHide(packageName: string): void { 167 Log.debug(`Hide an app with: ${packageName}.`); 168 const app: App = appMap[packageName]; 169 if (!app) { 170 Log.debug(`Hide an app error ${packageName}.`); 171 return; 172 } 173 app.emitEvent('hook:onHide'); 174} 175 176/** 177 * Emit onDestroy event. 178 * @param {string} packageName - Package name. 179 */ 180export function appDestroy(packageName: string): void { 181 Log.debug(`Destroy an app with: ${packageName}.`); 182 const app: App = appMap[packageName]; 183 if (!app) { 184 Log.error(`Destroy an app error ${packageName}.`); 185 return; 186 } 187 app.emitEvent('hook:onDestroy'); 188 app.deleteGlobalKeys(); 189 delete appMap[packageName]; 190 const appPage: Page = pageMap.get(app.appInstanceId); 191 if (appPage) { 192 if (appPage.doc.taskCenter.callbackIsEmpty()) { 193 appPage.callTasks([{ 194 module: 'internal.jsResult', 195 method: 'appDestroyFinish', 196 args: [] 197 }]); 198 destroy(appPage); 199 pageMap.delete(appPage.id); 200 } else { 201 appPage.destroyed = true; 202 } 203 } 204} 205 206/** 207 * Init language resource. 208 * @param {*} i18nData 209 */ 210export function updateLocale(i18nData: any): void { 211 if (i18nData) { 212 global.aceapp._i18n_data_ = { messages: i18nData.resources }; 213 } else { 214 global.aceapp._i18n_data_ = null; 215 } 216} 217 218/** 219 * Init image dpi. 220 * @param {Object} dpiData 221 */ 222export function updateDpi(dpiData: object): void { 223 if (dpiData) { 224 global.aceapp._dpi_data_ = { images: dpiData }; 225 } else { 226 global.aceapp._dpi_data_ = null; 227 } 228} 229