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