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 22namespace OHOS::Ace::Napi { 23const char EN_ALERT_APPROVE[] = "enableAlertBeforeBackPage:ok"; 24const char EN_ALERT_REJECT[] = "enableAlertBeforeBackPage:fail cancel"; 25const char DIS_ALERT_SUCCESS[] = "disableAlertBeforeBackPage:ok"; 26 27static constexpr size_t ARGC_WITH_MODE = 2; 28static constexpr size_t ARGC_WITH_ROUTER_PARAMTER = 2; 29static constexpr size_t ARGC_WITH_MODE_AND_CALLBACK = 3; 30static constexpr uint32_t STANDARD = 0; 31static constexpr uint32_t SINGLE = 1; 32static constexpr uint32_t INVALID = 2; 33static constexpr uint32_t RESULT_ARRAY_INDEX_INDEX = 0; 34static constexpr uint32_t RESULT_ARRAY_NAME_INDEX = 1; 35static constexpr uint32_t RESULT_ARRAY_PATH_INDEX = 2; 36static constexpr uint32_t RESULT_ARRAY_LENGTH = 3; 37 38static 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 49static 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 73static 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 97static 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 105struct 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; 121 ~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 138using RouterFunc = std::function<void(const std::string&, const std::string&, int32_t)>; 139 140static 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 179static 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 196static 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 213bool 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 259void 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 301using ErrorCallback = std::function<void(const std::string&, int32_t)>; 302using RouterWithCallbackFunc = std::function<void(std::shared_ptr<RouterAsyncContext>, const ErrorCallback&)>; 303 304static 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 343static 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 363static 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 383static 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 397static 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 411static 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 442static 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 485static 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 496static 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 511static 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 541static 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 594static 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 648void 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 700static 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 777static 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 817static 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 832static 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 868static 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 878extern "C" __attribute__((constructor)) void RouterRegister() 879{ 880 napi_module_register(&routerModule); 881} 882 883} // namespace OHOS::Ace::Napi 884