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