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