1 /*
2 * Copyright (c) 2021-2022 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
16 #include <cstdint>
17 #include <memory>
18 #include <string>
19
20 #include "interfaces/napi/kits/utils/napi_utils.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 #include "napi/native_api.h"
24 #include "napi/native_engine/native_value.h"
25 #include "napi/native_node_api.h"
26
27 #include "core/common/ace_engine.h"
28 #include "frameworks/base/log/log.h"
29 #include "frameworks/bridge/common/utils/engine_helper.h"
30 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
31
32 namespace OHOS::Ace::Napi {
33 const char EN_ALERT_APPROVE[] = "enableAlertBeforeBackPage:ok";
34 const char EN_ALERT_REJECT[] = "enableAlertBeforeBackPage:fail cancel";
35 const char DIS_ALERT_SUCCESS[] = "disableAlertBeforeBackPage:ok";
36
37 static constexpr size_t ARGC_WITH_MODE = 2;
38 static constexpr size_t ARGC_WITH_ROUTER_PARAMTER = 2;
39 static constexpr size_t ARGC_WITH_MODE_AND_CALLBACK = 3;
40 static constexpr uint32_t STANDARD = 0;
41 static constexpr uint32_t SINGLE = 1;
42 static constexpr uint32_t INVALID = 2;
43 static constexpr uint32_t RESULT_ARRAY_INDEX_INDEX = 0;
44 static constexpr uint32_t RESULT_ARRAY_NAME_INDEX = 1;
45 static constexpr uint32_t RESULT_ARRAY_PATH_INDEX = 2;
46 static constexpr uint32_t RESULT_ARRAY_LENGTH = 3;
47
ParseUri(napi_env env,napi_value uriNApi,std::string & uriString)48 static void ParseUri(napi_env env, napi_value uriNApi, std::string& uriString)
49 {
50 if (uriNApi != nullptr) {
51 size_t uriLen = 0;
52 napi_get_value_string_utf8(env, uriNApi, nullptr, 0, &uriLen);
53 std::unique_ptr<char[]> uri = std::make_unique<char[]>(uriLen + 1);
54 napi_get_value_string_utf8(env, uriNApi, uri.get(), uriLen + 1, &uriLen);
55 uriString = uri.get();
56 }
57 }
58
ParseParams(napi_env env,napi_value params,std::string & paramsString)59 static void ParseParams(napi_env env, napi_value params, std::string& paramsString)
60 {
61 if (params == nullptr) {
62 return;
63 }
64 napi_value globalValue;
65 napi_get_global(env, &globalValue);
66 napi_value jsonValue;
67 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
68 napi_value stringifyValue;
69 napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
70 napi_value funcArgv[1] = { params };
71 napi_value returnValue;
72 if (napi_call_function(env, jsonValue, stringifyValue, 1, funcArgv, &returnValue) != napi_ok) {
73 TAG_LOGE(AceLogTag::ACE_ROUTER,
74 "Router parse param failed, probably caused by invalid format of JSON object 'params'");
75 }
76 size_t len = 0;
77 napi_get_value_string_utf8(env, returnValue, nullptr, 0, &len);
78 std::unique_ptr<char[]> paramsChar = std::make_unique<char[]>(len + 1);
79 napi_get_value_string_utf8(env, returnValue, paramsChar.get(), len + 1, &len);
80 paramsString = paramsChar.get();
81 }
82
ParseJSONParams(napi_env env,const std::string & paramsStr)83 static napi_value ParseJSONParams(napi_env env, const std::string& paramsStr)
84 {
85 napi_value globalValue;
86 napi_get_global(env, &globalValue);
87 napi_value jsonValue;
88 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
89 napi_value parseValue;
90 napi_get_named_property(env, jsonValue, "parse", &parseValue);
91
92 napi_value paramsNApi;
93 napi_create_string_utf8(env, paramsStr.c_str(), NAPI_AUTO_LENGTH, ¶msNApi);
94 napi_value funcArgv[1] = { paramsNApi };
95 napi_value result;
96 napi_call_function(env, jsonValue, parseValue, 1, funcArgv, &result);
97
98 napi_valuetype valueType = napi_undefined;
99 napi_typeof(env, result, &valueType);
100 if (valueType != napi_object) {
101 return nullptr;
102 }
103
104 return result;
105 }
106
ParseRecoverable(napi_env env,napi_value recoverableNApi,bool & recoverable)107 static void ParseRecoverable(napi_env env, napi_value recoverableNApi, bool& recoverable)
108 {
109 if (recoverableNApi == nullptr) {
110 return;
111 }
112 napi_get_value_bool(env, recoverableNApi, &recoverable);
113 }
114
115 struct RouterAsyncContext {
116 napi_env env = nullptr;
117 napi_ref callbackSuccess = nullptr;
118 napi_ref callbackFail = nullptr;
119 napi_ref callbackComplete = nullptr;
120 int32_t callbackType = 0;
121 std::string keyForUrl;
122 std::string paramsString;
123 std::string uriString;
124 bool recoverable = true;
125 uint32_t mode = STANDARD;
126 napi_deferred deferred = nullptr;
127 napi_ref callbackRef = nullptr;
128 int32_t callbackCode = 0;
129 std::string callbackMsg;
130 int32_t instanceId = -1;
~RouterAsyncContextOHOS::Ace::Napi::RouterAsyncContext131 ~RouterAsyncContext()
132 {
133 if (callbackRef) {
134 napi_delete_reference(env, callbackRef);
135 }
136 if (callbackSuccess) {
137 napi_delete_reference(env, callbackSuccess);
138 }
139 if (callbackFail) {
140 napi_delete_reference(env, callbackFail);
141 }
142 if (callbackComplete) {
143 napi_delete_reference(env, callbackComplete);
144 }
145 }
146 };
147
148 using RouterFunc = std::function<void(const std::string&, const std::string&, int32_t)>;
149
CommonRouterProcess(napi_env env,napi_callback_info info,const RouterFunc & callback)150 static void CommonRouterProcess(napi_env env, napi_callback_info info, const RouterFunc& callback)
151 {
152 size_t requireArgc = 1;
153 size_t argc = ARGC_WITH_MODE;
154 napi_value argv[ARGC_WITH_MODE] = { 0 };
155 napi_value thisVar = nullptr;
156 void* data = nullptr;
157 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
158 if (argc < requireArgc) {
159 return;
160 }
161 napi_value uriNApi = nullptr;
162 napi_value params = nullptr;
163 napi_valuetype valueType = napi_undefined;
164 napi_typeof(env, argv[0], &valueType);
165 if (valueType == napi_object) {
166 napi_get_named_property(env, argv[0], "url", &uriNApi);
167 napi_typeof(env, uriNApi, &valueType);
168 if (valueType != napi_string) {
169 return;
170 }
171 napi_get_named_property(env, argv[0], "params", ¶ms);
172 }
173 std::string paramsString;
174 ParseParams(env, params, paramsString);
175 std::string uriString;
176 napi_typeof(env, uriNApi, &valueType);
177 if (valueType == napi_string) {
178 ParseUri(env, uriNApi, uriString);
179 }
180
181 uint32_t mode = INVALID;
182 napi_typeof(env, argv[1], &valueType);
183 if (argc == ARGC_WITH_MODE && valueType == napi_number) {
184 napi_get_value_uint32(env, argv[1], &mode);
185 }
186 callback(uriString, paramsString, mode);
187 }
188
JSRouterPush(napi_env env,napi_callback_info info)189 static napi_value JSRouterPush(napi_env env, napi_callback_info info)
190 {
191 auto callback = [](const std::string& uri, const std::string& params, uint32_t mode) {
192 auto delegate = EngineHelper::GetCurrentDelegateSafely();
193 if (!delegate) {
194 return;
195 }
196 if (mode == INVALID) {
197 delegate->Push(uri, params);
198 } else {
199 delegate->PushWithMode(uri, params, mode);
200 }
201 };
202 CommonRouterProcess(env, info, callback);
203 return nullptr;
204 }
205
JSRouterReplace(napi_env env,napi_callback_info info)206 static napi_value JSRouterReplace(napi_env env, napi_callback_info info)
207 {
208 auto callback = [](const std::string& uri, const std::string& params, uint32_t mode) {
209 auto delegate = EngineHelper::GetCurrentDelegateSafely();
210 if (!delegate) {
211 return;
212 }
213 if (mode == INVALID) {
214 delegate->Replace(uri, params);
215 } else {
216 delegate->ReplaceWithMode(uri, params, mode);
217 }
218 };
219 CommonRouterProcess(env, info, callback);
220 return nullptr;
221 }
222
ParseParamWithCallback(napi_env env,std::shared_ptr<RouterAsyncContext> asyncContext,const size_t argc,napi_value * argv,napi_value * result)223 bool ParseParamWithCallback(napi_env env, std::shared_ptr<RouterAsyncContext> asyncContext, const size_t argc,
224 napi_value* argv, napi_value* result)
225 {
226 asyncContext->env = env;
227 for (size_t i = 0; i < argc; i++) {
228 napi_valuetype valueType = napi_undefined;
229 napi_typeof(env, argv[i], &valueType);
230 if (i == 0) {
231 if (valueType != napi_object) {
232 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
233 return false;
234 }
235 napi_value uriNApi = nullptr;
236 napi_value params = nullptr;
237 napi_value recoverable = nullptr;
238 napi_get_named_property(env, argv[i], asyncContext->keyForUrl.c_str(), &uriNApi);
239 napi_typeof(env, uriNApi, &valueType);
240 if (valueType != napi_string) {
241 NapiThrow(env, "The type of the url parameter is not string.", ERROR_CODE_PARAM_INVALID);
242 return false;
243 }
244 ParseUri(env, uriNApi, asyncContext->uriString);
245 napi_get_named_property(env, argv[i], "params", ¶ms);
246 ParseParams(env, params, asyncContext->paramsString);
247 napi_get_named_property(env, argv[i], "recoverable", &recoverable);
248 ParseRecoverable(env, recoverable, asyncContext->recoverable);
249 } else if (valueType == napi_number) {
250 napi_get_value_uint32(env, argv[i], &asyncContext->mode);
251 } else if (valueType == napi_function) {
252 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
253 } else {
254 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
255 return false;
256 }
257 }
258
259 if (asyncContext->callbackRef == nullptr) {
260 if (argc > ARGC_WITH_MODE) {
261 NapiThrow(env, "The largest number of parameters is 2 in Promise.", ERROR_CODE_PARAM_INVALID);
262 return false;
263 }
264 napi_create_promise(env, &asyncContext->deferred, result);
265 }
266 return true;
267 }
268
TriggerCallback(std::shared_ptr<RouterAsyncContext> asyncContext)269 void TriggerCallback(std::shared_ptr<RouterAsyncContext> asyncContext)
270 {
271 napi_handle_scope scope = nullptr;
272 napi_open_handle_scope(asyncContext->env, &scope);
273 if (scope == nullptr) {
274 return;
275 }
276
277 if (asyncContext->callbackCode == ERROR_CODE_NO_ERROR) {
278 napi_value result = nullptr;
279 napi_get_undefined(asyncContext->env, &result);
280 if (asyncContext->deferred) {
281 napi_resolve_deferred(asyncContext->env, asyncContext->deferred, result);
282 } else {
283 napi_value callback = nullptr;
284 napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
285 napi_value ret;
286 napi_call_function(asyncContext->env, nullptr, callback, 1, &result, &ret);
287 }
288 } else {
289 napi_value code = nullptr;
290 std::string strCode = std::to_string(asyncContext->callbackCode);
291 napi_create_string_utf8(asyncContext->env, strCode.c_str(), strCode.length(), &code);
292
293 napi_value msg = nullptr;
294 std::string strMsg = ErrorToMessage(asyncContext->callbackCode) + asyncContext->callbackMsg;
295 napi_create_string_utf8(asyncContext->env, strMsg.c_str(), strMsg.length(), &msg);
296
297 napi_value error = nullptr;
298 napi_create_error(asyncContext->env, code, msg, &error);
299 if (asyncContext->deferred) {
300 napi_reject_deferred(asyncContext->env, asyncContext->deferred, error);
301 } else {
302 napi_value callback = nullptr;
303 napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
304 napi_value ret;
305 napi_call_function(asyncContext->env, nullptr, callback, 1, &error, &ret);
306 }
307 }
308 napi_close_handle_scope(asyncContext->env, scope);
309 }
310
311 using ErrorCallback = std::function<void(const std::string&, int32_t)>;
312 using RouterWithCallbackFunc = std::function<void(std::shared_ptr<RouterAsyncContext>, const ErrorCallback&)>;
313
CommonRouterWithCallbackProcess(napi_env env,napi_callback_info info,const RouterWithCallbackFunc & callback,const std::string & keyForUrl)314 static napi_value CommonRouterWithCallbackProcess(
315 napi_env env, napi_callback_info info, const RouterWithCallbackFunc& callback, const std::string& keyForUrl)
316 {
317 napi_value result = nullptr;
318 napi_get_undefined(env, &result);
319 size_t requireArgc = 1;
320 size_t argc = ARGC_WITH_MODE_AND_CALLBACK;
321 napi_value argv[ARGC_WITH_MODE_AND_CALLBACK] = { 0 };
322 napi_value thisVar = nullptr;
323 void* data = nullptr;
324 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
325 if (argc < requireArgc) {
326 NapiThrow(
327 env, "The number of parameters must be greater than or equal to 1.", ERROR_CODE_PARAM_INVALID);
328 return result;
329 } else if (argc > ARGC_WITH_MODE_AND_CALLBACK) {
330 NapiThrow(env, "The largest number of parameters is 3.", ERROR_CODE_PARAM_INVALID);
331 return result;
332 }
333
334 auto asyncContext = std::make_shared<RouterAsyncContext>();
335 asyncContext->keyForUrl = keyForUrl;
336 if (!ParseParamWithCallback(env, asyncContext, argc, argv, &result)) {
337 return result;
338 }
339
340 auto errorCallback = [asyncContext](const std::string& message, int32_t errCode) mutable {
341 if (!asyncContext) {
342 return;
343 }
344 asyncContext->callbackCode = errCode;
345 asyncContext->callbackMsg = message;
346 TriggerCallback(asyncContext);
347 asyncContext = nullptr;
348 };
349 callback(asyncContext, errorCallback);
350 return result;
351 }
352
JSRouterPushWithCallback(napi_env env,napi_callback_info info)353 static napi_value JSRouterPushWithCallback(napi_env env, napi_callback_info info)
354 {
355 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
356 auto delegate = EngineHelper::GetCurrentDelegateSafely();
357 auto defaultDelegate = EngineHelper::GetDefaultDelegate();
358 if (!delegate && !defaultDelegate) {
359 NapiThrow(context->env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
360 return;
361 }
362 if (delegate) {
363 delegate->PushWithCallback(context->uriString, context->paramsString,
364 context->recoverable, errorCallback, context->mode);
365 } else {
366 defaultDelegate->PushWithCallback(context->uriString, context->paramsString,
367 context->recoverable, errorCallback, context->mode);
368 }
369 };
370 return CommonRouterWithCallbackProcess(env, info, callback, "url");
371 }
372
JSRouterReplaceWithCallback(napi_env env,napi_callback_info info)373 static napi_value JSRouterReplaceWithCallback(napi_env env, napi_callback_info info)
374 {
375 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
376 auto delegate = EngineHelper::GetCurrentDelegateSafely();
377 auto defaultDelegate = EngineHelper::GetDefaultDelegate();
378 if (!delegate && !defaultDelegate) {
379 NapiThrow(context->env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
380 return;
381 }
382 if (delegate) {
383 delegate->ReplaceWithCallback(context->uriString, context->paramsString,
384 context->recoverable, errorCallback, context->mode);
385 } else {
386 defaultDelegate->ReplaceWithCallback(context->uriString, context->paramsString,
387 context->recoverable, errorCallback, context->mode);
388 }
389 };
390 return CommonRouterWithCallbackProcess(env, info, callback, "url");
391 }
392
JSPushNamedRoute(napi_env env,napi_callback_info info)393 static napi_value JSPushNamedRoute(napi_env env, napi_callback_info info)
394 {
395 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
396 auto delegate = EngineHelper::GetCurrentDelegateSafely();
397 if (!delegate) {
398 NapiThrow(context->env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
399 return;
400 }
401 delegate->PushNamedRoute(context->uriString, context->paramsString,
402 context->recoverable, errorCallback, context->mode);
403 };
404 return CommonRouterWithCallbackProcess(env, info, callback, "name");
405 }
406
JSReplaceNamedRoute(napi_env env,napi_callback_info info)407 static napi_value JSReplaceNamedRoute(napi_env env, napi_callback_info info)
408 {
409 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
410 auto delegate = EngineHelper::GetCurrentDelegateSafely();
411 if (!delegate) {
412 NapiThrow(context->env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
413 return;
414 }
415 delegate->ReplaceNamedRoute(context->uriString, context->paramsString,
416 context->recoverable, errorCallback, context->mode);
417 };
418 return CommonRouterWithCallbackProcess(env, info, callback, "name");
419 }
420
JsBackToIndex(napi_env env,napi_callback_info info)421 static napi_value JsBackToIndex(napi_env env, napi_callback_info info)
422 {
423 size_t argc = ARGC_WITH_ROUTER_PARAMTER;
424 napi_value argv[ARGC_WITH_ROUTER_PARAMTER] = { nullptr };
425 napi_value thisVar = nullptr;
426 void* data = nullptr;
427 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
428
429 auto delegate = EngineHelper::GetCurrentDelegateSafely();
430 if (!delegate) {
431 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
432 return nullptr;
433 }
434 std::string paramsString;
435 int32_t routeIndex = 0;
436 napi_valuetype valueType = napi_undefined;
437 napi_typeof(env, argv[0], &valueType);
438 if (valueType == napi_number) {
439 napi_get_value_int32(env, argv[0], &routeIndex);
440 } else {
441 TAG_LOGE(AceLogTag::ACE_ROUTER, "Index is not of type number");
442 return nullptr;
443 }
444 napi_typeof(env, argv[1], &valueType);
445 if (valueType == napi_object) {
446 ParseParams(env, argv[1], paramsString);
447 }
448 delegate->BackToIndex(routeIndex, paramsString);
449 return nullptr;
450 }
451
JSRouterBack(napi_env env,napi_callback_info info)452 static napi_value JSRouterBack(napi_env env, napi_callback_info info)
453 {
454 size_t argc = ARGC_WITH_ROUTER_PARAMTER;
455 napi_value argv[ARGC_WITH_ROUTER_PARAMTER] = { nullptr };
456 napi_value thisVar = nullptr;
457 void* data = nullptr;
458 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
459
460 napi_valuetype valueType = napi_undefined;
461 napi_typeof(env, argv[0], &valueType);
462 if (argc == ARGC_WITH_ROUTER_PARAMTER || valueType == napi_number) {
463 return JsBackToIndex(env, info);
464 }
465 auto delegate = EngineHelper::GetCurrentDelegateSafely();
466 if (!delegate) {
467 NapiThrow(env, "UI execution context not found.", ERROR_CODE_PARAM_INVALID);
468 return nullptr;
469 }
470 std::string uriString = "";
471 std::string paramsString = "";
472 napi_value uriNApi = nullptr;
473 napi_value params = nullptr;
474 if (valueType == napi_object) {
475 napi_get_named_property(env, argv[0], "url", &uriNApi);
476 napi_typeof(env, uriNApi, &valueType);
477 if (valueType == napi_undefined) {
478 napi_get_named_property(env, argv[0], "path", &uriNApi);
479 napi_typeof(env, uriNApi, &valueType);
480 }
481 if (valueType == napi_string) {
482 ParseUri(env, uriNApi, uriString);
483 }
484
485 napi_get_named_property(env, argv[0], "params", ¶ms);
486 napi_typeof(env, params, &valueType);
487 if (valueType == napi_object) {
488 ParseParams(env, params, paramsString);
489 }
490 }
491 delegate->Back(uriString, paramsString);
492 return nullptr;
493 }
494
JSRouterClear(napi_env env,napi_callback_info info)495 static napi_value JSRouterClear(napi_env env, napi_callback_info info)
496 {
497 auto delegate = EngineHelper::GetCurrentDelegateSafely();
498 if (!delegate) {
499 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
500 return nullptr;
501 }
502 delegate->Clear();
503 return nullptr;
504 }
505
JSRouterGetLength(napi_env env,napi_callback_info info)506 static napi_value JSRouterGetLength(napi_env env, napi_callback_info info)
507 {
508 auto delegate = EngineHelper::GetCurrentDelegateSafely();
509 if (!delegate) {
510 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
511 return nullptr;
512 }
513 int32_t routeNumber = delegate->GetStackSize();
514 napi_value routeNApiNum = nullptr;
515 napi_create_int32(env, routeNumber, &routeNApiNum);
516 napi_value result = nullptr;
517 napi_coerce_to_string(env, routeNApiNum, &result);
518 return result;
519 }
520
JSRouterGetState(napi_env env,napi_callback_info info)521 static napi_value JSRouterGetState(napi_env env, napi_callback_info info)
522 {
523 int32_t routeIndex = 0;
524 std::string routeName;
525 std::string routePath;
526 auto delegate = EngineHelper::GetCurrentDelegateSafely();
527 if (!delegate) {
528 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
529 return nullptr;
530 }
531 delegate->GetState(routeIndex, routeName, routePath);
532 size_t routeNameLen = routeName.length();
533 size_t routePathLen = routePath.length();
534
535 std::string paramsStr = delegate->GetParams();
536 napi_value params = paramsStr.empty() ? nullptr : ParseJSONParams(env, paramsStr);
537 napi_value resultArray[RESULT_ARRAY_LENGTH] = { 0 };
538 napi_create_int32(env, routeIndex, &resultArray[RESULT_ARRAY_INDEX_INDEX]);
539 napi_create_string_utf8(env, routeName.c_str(), routeNameLen, &resultArray[RESULT_ARRAY_NAME_INDEX]);
540 napi_create_string_utf8(env, routePath.c_str(), routePathLen, &resultArray[RESULT_ARRAY_PATH_INDEX]);
541
542 napi_value result = nullptr;
543 napi_create_object(env, &result);
544 napi_set_named_property(env, result, "index", resultArray[RESULT_ARRAY_INDEX_INDEX]);
545 napi_set_named_property(env, result, "name", resultArray[RESULT_ARRAY_NAME_INDEX]);
546 napi_set_named_property(env, result, "path", resultArray[RESULT_ARRAY_PATH_INDEX]);
547 napi_set_named_property(env, result, "params", params);
548 return result;
549 }
550
JSGetStateByIndex(napi_env env,napi_callback_info info)551 static napi_value JSGetStateByIndex(napi_env env, napi_callback_info info)
552 {
553 size_t argc = 1;
554 napi_value argv = nullptr;
555 napi_value thisVar = nullptr;
556 void* data = nullptr;
557 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
558
559 int32_t routeIndex = 0;
560 std::string routeName;
561 std::string routePath;
562 std::string routeParams;
563 napi_valuetype valueType = napi_undefined;
564 napi_typeof(env, argv, &valueType);
565 if (valueType == napi_number) {
566 napi_get_value_int32(env, argv, &routeIndex);
567 }
568 auto delegate = EngineHelper::GetCurrentDelegateSafely();
569 if (!delegate) {
570 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
571 return nullptr;
572 }
573
574 delegate->GetRouterStateByIndex(routeIndex, routeName, routePath, routeParams);
575 if (routeName.empty()) {
576 napi_value undefined;
577 napi_get_undefined(env, &undefined);
578 return undefined;
579 }
580 size_t routeNameLen = routeName.length();
581 size_t routePathLen = routePath.length();
582
583 napi_value resultArray[RESULT_ARRAY_LENGTH] = { 0 };
584 napi_create_int32(env, routeIndex, &resultArray[RESULT_ARRAY_INDEX_INDEX]);
585 napi_create_string_utf8(env, routeName.c_str(), routeNameLen, &resultArray[RESULT_ARRAY_NAME_INDEX]);
586 napi_create_string_utf8(env, routePath.c_str(), routePathLen, &resultArray[RESULT_ARRAY_PATH_INDEX]);
587
588 napi_value parsedParams = nullptr;
589 if (!routeParams.empty()) {
590 parsedParams = ParseJSONParams(env, routeParams);
591 } else {
592 napi_create_object(env, &parsedParams);
593 }
594
595 napi_value result = nullptr;
596 napi_create_object(env, &result);
597 napi_set_named_property(env, result, "index", resultArray[RESULT_ARRAY_INDEX_INDEX]);
598 napi_set_named_property(env, result, "name", resultArray[RESULT_ARRAY_NAME_INDEX]);
599 napi_set_named_property(env, result, "path", resultArray[RESULT_ARRAY_PATH_INDEX]);
600 napi_set_named_property(env, result, "params", parsedParams);
601 return result;
602 }
603
JSGetStateByUrl(napi_env env,napi_callback_info info)604 static napi_value JSGetStateByUrl(napi_env env, napi_callback_info info)
605 {
606 size_t argc = 1;
607 napi_value argv = nullptr;
608 napi_value thisVar = nullptr;
609 void* data = nullptr;
610 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
611
612 auto delegate = EngineHelper::GetCurrentDelegateSafely();
613 if (!delegate) {
614 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
615 return nullptr;
616 }
617 std::string uriString;
618 napi_valuetype valueType = napi_undefined;
619 napi_typeof(env, argv, &valueType);
620 if (valueType == napi_string) {
621 ParseUri(env, argv, uriString);
622 }
623 std::vector<Framework::StateInfo> stateArray;
624 delegate->GetRouterStateByUrl(uriString, stateArray);
625
626 napi_value result = nullptr;
627 napi_create_array(env, &result);
628 int32_t index = 0;
629 for (const auto& info : stateArray) {
630 napi_value pageObj = nullptr;
631 napi_create_object(env, &pageObj);
632 int32_t routeIndex = info.index;
633 std::string routeName = info.name;
634 std::string routePath = info.path;
635 std::string routeParams = info.params;
636 napi_value indexValue = nullptr;
637 napi_value nameValue = nullptr;
638 napi_value pathValue = nullptr;
639
640 napi_create_int32(env, routeIndex, &indexValue);
641 napi_create_string_utf8(env, routeName.c_str(), NAPI_AUTO_LENGTH, &nameValue);
642 napi_create_string_utf8(env, routePath.c_str(), NAPI_AUTO_LENGTH, &pathValue);
643 napi_value parsedParams = nullptr;
644 if (!routeParams.empty()) {
645 parsedParams = ParseJSONParams(env, routeParams);
646 } else {
647 napi_create_object(env, &parsedParams);
648 }
649 napi_set_named_property(env, pageObj, "index", indexValue);
650 napi_set_named_property(env, pageObj, "name", nameValue);
651 napi_set_named_property(env, pageObj, "path", pathValue);
652 napi_set_named_property(env, pageObj, "params", parsedParams);
653 napi_set_element(env, result, index++, pageObj);
654 }
655 return result;
656 }
657
CallBackToJSTread(std::shared_ptr<RouterAsyncContext> context)658 void CallBackToJSTread(std::shared_ptr<RouterAsyncContext> context)
659 {
660 auto container = AceEngine::Get().GetContainer(context->instanceId);
661 if (!container) {
662 return;
663 }
664
665 auto taskExecutor = container->GetTaskExecutor();
666 if (!taskExecutor) {
667 return;
668 }
669 taskExecutor->PostTask(
670 [context]() {
671 napi_handle_scope scope = nullptr;
672 napi_open_handle_scope(context->env, &scope);
673 if (scope == nullptr) {
674 return;
675 }
676
677 napi_value result = nullptr;
678 napi_value callback = nullptr;
679 napi_value ret = nullptr;
680 if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CONFIRM) {
681 if (context->callbackSuccess) {
682 napi_create_string_utf8(context->env, EN_ALERT_APPROVE, NAPI_AUTO_LENGTH, &result);
683 napi_value argv[1] = { result };
684 napi_get_reference_value(context->env, context->callbackSuccess, &callback);
685 napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
686 }
687 if (context->callbackComplete) {
688 napi_get_reference_value(context->env, context->callbackComplete, &callback);
689 napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
690 }
691 }
692 if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CANCEL) {
693 if (context->callbackFail) {
694 napi_create_string_utf8(context->env, EN_ALERT_REJECT, NAPI_AUTO_LENGTH, &result);
695 napi_value argv[1] = { result };
696 napi_get_reference_value(context->env, context->callbackFail, &callback);
697 napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
698 }
699 if (context->callbackComplete) {
700 napi_get_reference_value(context->env, context->callbackComplete, &callback);
701 napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
702 }
703 }
704
705 napi_close_handle_scope(context->env, scope);
706 },
707 TaskExecutor::TaskType::JS, "ArkUIRouterAlertCallback");
708 }
709
JSRouterEnableAlertBeforeBackPage(napi_env env,napi_callback_info info)710 static napi_value JSRouterEnableAlertBeforeBackPage(napi_env env, napi_callback_info info)
711 {
712 size_t argc = 1;
713 napi_value argv = nullptr;
714 napi_value thisVar = nullptr;
715 void* data = nullptr;
716 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
717
718 napi_valuetype valueType = napi_undefined;
719 napi_typeof(env, argv, &valueType);
720 if (valueType != napi_object) {
721 NapiThrow(env, "The type of the parameter is not object.", ERROR_CODE_PARAM_INVALID);
722 return nullptr;
723 }
724
725 napi_value messageNapi = nullptr;
726 std::unique_ptr<char[]> messageChar;
727 napi_get_named_property(env, argv, "message", &messageNapi);
728 napi_typeof(env, messageNapi, &valueType);
729 if (valueType == napi_string) {
730 size_t length = 0;
731 napi_get_value_string_utf8(env, messageNapi, nullptr, 0, &length);
732 messageChar = std::make_unique<char[]>(length + 1);
733 napi_get_value_string_utf8(env, messageNapi, messageChar.get(), length + 1, &length);
734 } else {
735 NapiThrow(env, "The type of the message is not string.", ERROR_CODE_PARAM_INVALID);
736 return nullptr;
737 }
738
739 auto delegate = EngineHelper::GetCurrentDelegateSafely();
740 if (!delegate) {
741 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
742 return nullptr;
743 }
744
745 auto context = std::make_shared<RouterAsyncContext>();
746 context->env = env;
747 context->instanceId = Container::CurrentIdSafely();
748 napi_value successFunc = nullptr;
749 napi_value failFunc = nullptr;
750 napi_value completeFunc = nullptr;
751 napi_get_named_property(env, argv, "success", &successFunc);
752 napi_get_named_property(env, argv, "cancel", &failFunc);
753 napi_get_named_property(env, argv, "complete", &completeFunc);
754 bool isNeedCallBack = false;
755 napi_typeof(env, successFunc, &valueType);
756 if (valueType == napi_function) {
757 napi_create_reference(env, successFunc, 1, &context->callbackSuccess);
758 isNeedCallBack = true;
759 }
760
761 napi_typeof(env, failFunc, &valueType);
762 if (valueType == napi_function) {
763 napi_create_reference(env, failFunc, 1, &context->callbackFail);
764 isNeedCallBack = true;
765 }
766 napi_typeof(env, completeFunc, &valueType);
767 if (valueType == napi_function) {
768 napi_create_reference(env, completeFunc, 1, &context->callbackComplete);
769 isNeedCallBack = true;
770 }
771
772 auto dilogCallback = [context, isNeedCallBack](int32_t callbackType) mutable {
773 if (context && isNeedCallBack) {
774 if (Framework::AlertState(callbackType) == Framework::AlertState::RECOVERY) {
775 context = nullptr;
776 return;
777 }
778 context->callbackType = callbackType;
779 CallBackToJSTread(context);
780 }
781 };
782 delegate->EnableAlertBeforeBackPage(messageChar.get(), std::move(dilogCallback));
783
784 return nullptr;
785 }
786
JSRouterDisableAlertBeforeBackPage(napi_env env,napi_callback_info info)787 static napi_value JSRouterDisableAlertBeforeBackPage(napi_env env, napi_callback_info info)
788 {
789 auto delegate = EngineHelper::GetCurrentDelegateSafely();
790 if (delegate) {
791 delegate->DisableAlertBeforeBackPage();
792 } else {
793 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
794 return nullptr;
795 }
796
797 size_t argc = 1;
798 napi_value argv = nullptr;
799 napi_value thisVar = nullptr;
800 void* data = nullptr;
801 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
802 napi_valuetype valueType = napi_undefined;
803 napi_typeof(env, argv, &valueType);
804 if (valueType == napi_object) {
805 napi_value successFunc = nullptr;
806 napi_value completeFunc = nullptr;
807 napi_get_named_property(env, argv, "success", &successFunc);
808 napi_get_named_property(env, argv, "complete", &completeFunc);
809
810 napi_value result = nullptr;
811 napi_value ret = nullptr;
812 napi_create_string_utf8(env, DIS_ALERT_SUCCESS, NAPI_AUTO_LENGTH, &result);
813 napi_value argv[1] = { result };
814
815 napi_typeof(env, successFunc, &valueType);
816 if (valueType == napi_function) {
817 napi_call_function(env, nullptr, successFunc, 1, argv, &ret);
818 }
819 napi_typeof(env, completeFunc, &valueType);
820 if (valueType == napi_function) {
821 napi_call_function(env, nullptr, completeFunc, 1, argv, &ret);
822 }
823 }
824 return nullptr;
825 }
826
JSRouterGetParams(napi_env env,napi_callback_info info)827 static napi_value JSRouterGetParams(napi_env env, napi_callback_info info)
828 {
829 auto delegate = EngineHelper::GetCurrentDelegateSafely();
830 if (!delegate) {
831 NapiThrow(env, "UI execution context not found.", ERROR_CODE_INTERNAL_ERROR);
832 return nullptr;
833 }
834
835 std::string paramsStr = delegate->GetParams();
836 if (paramsStr.empty()) {
837 return nullptr;
838 }
839
840 napi_value result = ParseJSONParams(env, paramsStr);
841 return result;
842 }
843
RouterExport(napi_env env,napi_value exports)844 static napi_value RouterExport(napi_env env, napi_value exports)
845 {
846 napi_value routerMode = nullptr;
847 napi_create_object(env, &routerMode);
848 napi_value prop = nullptr;
849 napi_create_uint32(env, STANDARD, &prop);
850 napi_set_named_property(env, routerMode, "Standard", prop);
851 napi_create_uint32(env, SINGLE, &prop);
852 napi_set_named_property(env, routerMode, "Single", prop);
853
854 napi_property_descriptor routerDesc[] = {
855 DECLARE_NAPI_FUNCTION("push", JSRouterPush),
856 DECLARE_NAPI_FUNCTION("pushUrl", JSRouterPushWithCallback),
857 DECLARE_NAPI_FUNCTION("replace", JSRouterReplace),
858 DECLARE_NAPI_FUNCTION("replaceUrl", JSRouterReplaceWithCallback),
859 DECLARE_NAPI_FUNCTION("back", JSRouterBack),
860 DECLARE_NAPI_FUNCTION("clear", JSRouterClear),
861 DECLARE_NAPI_FUNCTION("getLength", JSRouterGetLength),
862 DECLARE_NAPI_FUNCTION("getState", JSRouterGetState),
863 DECLARE_NAPI_FUNCTION("getStateByIndex", JSGetStateByIndex),
864 DECLARE_NAPI_FUNCTION("getStateByUrl", JSGetStateByUrl),
865 DECLARE_NAPI_FUNCTION("enableAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
866 DECLARE_NAPI_FUNCTION("enableBackPageAlert", JSRouterEnableAlertBeforeBackPage),
867 DECLARE_NAPI_FUNCTION("showAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
868 DECLARE_NAPI_FUNCTION("disableAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
869 DECLARE_NAPI_FUNCTION("hideAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
870 DECLARE_NAPI_FUNCTION("getParams", JSRouterGetParams),
871 DECLARE_NAPI_FUNCTION("pushNamedRoute", JSPushNamedRoute),
872 DECLARE_NAPI_FUNCTION("replaceNamedRoute", JSReplaceNamedRoute),
873 DECLARE_NAPI_PROPERTY("RouterMode", routerMode),
874 };
875 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(routerDesc) / sizeof(routerDesc[0]), routerDesc));
876
877 return exports;
878 }
879
880 static napi_module routerModule = {
881 .nm_version = 1,
882 .nm_flags = 0,
883 .nm_filename = nullptr,
884 .nm_register_func = RouterExport,
885 .nm_modname = "router",
886 .nm_priv = ((void*)0),
887 .reserved = { 0 },
888 };
889
RouterRegister()890 extern "C" __attribute__((constructor)) void RouterRegister()
891 {
892 napi_module_register(&routerModule);
893 }
894
895 } // namespace OHOS::Ace::Napi
896