• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { PageLinkedMap } from './map';
26import Page from '../page/index';
27import { destroy } from '../page/api/index';
28import { mockSystemPlugin } from '../extend/systemplugin/index';
29import { compileBundle } from '../page/entry/init';
30import { removePrefix } from '../util/index';
31import { requireModule } from '../page/register';
32
33/**
34 * Device information for mediaQuery.
35 */
36export interface MediaQueryInfo {
37  'orientation': string;
38  'device-type': string;
39  'device-width': string;
40  'device-height': string;
41  'round-screen': boolean;
42  'width': string;
43  'height': string;
44  'isInit': boolean;
45  'resolution': string;
46  'aspect-ratio': string;
47  'dark-mode': string;
48}
49
50/**
51 * Information of App.
52 */
53export interface Options extends MediaQueryInfo {
54  'appInstanceId': string;
55  'packageName': string;
56  'appCreate': boolean;
57  'appCode': string | Function;
58  'pcPreview': string;
59  'resourcesConfiguration': object;
60  'i18n': object;
61  'language': string;
62  'appGlobalData'?: object;
63  'bundleUrl': string;
64}
65
66/**
67 * Framework Services.
68 */
69export interface Services {
70  service: object;
71  I18n?: Function;
72  dpi?: Function;
73}
74
75interface ParseOptions {
76  $app_define$(...args: any[]): void; // eslint-disable-line camelcase
77  $app_bootstrap$(name: string, config: any, _data: any): void; // eslint-disable-line camelcase
78  $app_require$(name: string): void; // eslint-disable-line camelcase
79}
80
81const pageMap: PageLinkedMap = App.pageMap;
82
83/**
84 * Create app page, run jsbundle code.
85 * @param {Page} page
86 * @param {Options} options
87 * @param {Object} data
88 * @param {Services} services
89 */
90export function appCreate(page: Page, options: Options, data: object, services: Services): void {
91  if (!options || !options.appCreate || !options.appCode) {
92    return;
93  }
94  if (options.pcPreview && options.pcPreview === 'enable') {
95    global.pcPreview = true;
96    mockSystemPlugin();
97  }
98  const packageName: string = page.packageName;
99  const appPage: Page = new Page(options.appInstanceId, options, packageName, data);
100  pageMap.unshift(appPage);
101  Log.debug(`Create a page with: ${packageName}.`);
102  appMap[packageName] = new App(packageName, options.appInstanceId);
103  const timerAPIs: object = genTimerAPI(appPage);
104  appMap[packageName].setTimer(timerAPIs);
105  const code = options.appCode;
106  global.__appProto__ = getPageGlobal(packageName);
107
108  // prepare page env methods
109  const appDefine = (...args: any[]): void => defineFn(page, packageName, ...args);
110  const appBootstrap = (name: string, config: any, _data: any): void => {
111    bootstrap(page, packageName, name, config, _data || data);
112    Log.debug(`After create a page(${page.id}).`);
113  };
114
115  const appFunction = () => pageMap.getTop(packageName) || page;
116
117  // require in top app(instance)
118  const appRequireModule = name => requireModule(appFunction, removePrefix(name));
119  const parseOptions: ParseOptions = {
120    $app_define$: appDefine,
121    $app_bootstrap$: appBootstrap,
122    $app_require$: appRequireModule
123  };
124  global.$app_require$ = appRequireModule;
125
126  // Compile js bundle code and get result.
127  if (typeof code === 'function') {
128    Log.info('call Function directly when appCreate');
129    code.call(global, parseOptions);
130  } else {
131    // Function with code and use strict mode.
132    const functionCode: string = `(function(global){\n\n"use strict";\n\n ${code} \n\n})(this.__appProto__)`;
133    compileBundle(functionCode, 'app.js', parseOptions, timerAPIs, services);
134  }
135}
136
137/**
138 * Emit onError event.
139 * @param {string} packageName
140 * @param {*} errors
141 */
142export function appError(packageName: string, errors: any): void {
143  Log.debug(`AppError an app with: ${packageName}.`);
144  const app: App = appMap[packageName];
145  if (!app) {
146    Log.debug(`AppError an app error ${packageName}.`);
147    return;
148  }
149  Log.debug(`AppError an app error ${packageName}.`);
150  app.emitEvent('hook:onError', errors);
151}
152
153/**
154 * Emit onShow event.
155 * @param {string} packageName - Package name.
156 */
157export function appShow(packageName: string): void {
158  Log.debug(`Show an app with: ${packageName}.`);
159  const app: App = appMap[packageName];
160  if (!app) {
161    Log.debug(`Show an app error ${packageName}.`);
162    return;
163  }
164  app.emitEvent('hook:onShow');
165}
166
167/**
168 * Emit onHide event.
169 * @param {string} packageName - Package name.
170 */
171export function appHide(packageName: string): void {
172  Log.debug(`Hide an app with: ${packageName}.`);
173  const app: App = appMap[packageName];
174  if (!app) {
175    Log.debug(`Hide an app error ${packageName}.`);
176    return;
177  }
178  app.emitEvent('hook:onHide');
179}
180
181/**
182 * Emit onDestroy event.
183 * @param {string} packageName - Package name.
184 */
185export function appDestroy(packageName: string): void {
186  Log.debug(`Destroy an app with: ${packageName}.`);
187  const app: App = appMap[packageName];
188  if (!app) {
189    Log.error(`Destroy an app error ${packageName}.`);
190    return;
191  }
192  app.emitEvent('hook:onDestroy');
193  app.deleteGlobalKeys();
194  delete appMap[packageName];
195  const appPage: Page = pageMap[app.appInstanceId];
196  if (appPage) {
197    if (appPage.doc.taskCenter.callbackIsEmpty()) {
198      appPage.callTasks([{
199        module: 'internal.jsResult',
200        method: 'appDestroyFinish',
201        args: []
202      }]);
203      destroy(appPage);
204      pageMap.remove(appPage);
205    } else {
206      appPage.destroyed = true;
207    }
208  }
209}
210
211/**
212 * Init language resource.
213 * @param {*} i18nData
214 */
215export function updateLocale(i18nData: any): void {
216  if (i18nData) {
217    global.aceapp._i18n_data_ = { messages: i18nData.resources };
218  } else {
219    global.aceapp._i18n_data_ = null;
220  }
221}
222
223/**
224 * Init image dpi.
225 * @param {Object} dpiData
226 */
227export function updateDpi(dpiData: object): void {
228  if (dpiData) {
229    global.aceapp._dpi_data_ = { images: dpiData };
230  } else {
231    global.aceapp._dpi_data_ = null;
232  }
233}
234