1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdint>
17 #include <memory>
18 #include <string>
19
20 #include "interfaces/napi/kits/utils/napi_utils.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 #include "napi/native_api.h"
24 #include "napi/native_engine/native_value.h"
25 #include "napi/native_node_api.h"
26
27 #include "core/common/ace_engine.h"
28 #include "frameworks/base/log/log.h"
29 #include "frameworks/bridge/common/utils/engine_helper.h"
30 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
31
32 namespace OHOS::Ace::Napi {
33 const char EN_ALERT_APPROVE[] = "enableAlertBeforeBackPage:ok";
34 const char EN_ALERT_REJECT[] = "enableAlertBeforeBackPage:fail cancel";
35 const char DIS_ALERT_SUCCESS[] = "disableAlertBeforeBackPage:ok";
36
37 static constexpr size_t ARGC_WITH_MODE = 2;
38 static constexpr size_t ARGC_WITH_MODE_AND_CALLBACK = 3;
39 static constexpr uint32_t STANDARD = 0;
40 static constexpr uint32_t SINGLE = 1;
41 static constexpr uint32_t INVALID = 2;
42
ParseUri(napi_env env,napi_value uriNApi,std::string & uriString)43 static void ParseUri(napi_env env, napi_value uriNApi, std::string& uriString)
44 {
45 if (uriNApi != nullptr) {
46 size_t uriLen = 0;
47 napi_get_value_string_utf8(env, uriNApi, nullptr, 0, &uriLen);
48 std::unique_ptr<char[]> uri = std::make_unique<char[]>(uriLen + 1);
49 napi_get_value_string_utf8(env, uriNApi, uri.get(), uriLen + 1, &uriLen);
50 uriString = uri.get();
51 }
52 }
53
ParseParams(napi_env env,napi_value params,std::string & paramsString)54 static void ParseParams(napi_env env, napi_value params, std::string& paramsString)
55 {
56 // TODO: Save the original data instead of making the serial number.
57 if (params == nullptr) {
58 return;
59 }
60 napi_value globalValue;
61 napi_get_global(env, &globalValue);
62 napi_value jsonValue;
63 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
64 napi_value stringifyValue;
65 napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
66 napi_value funcArgv[1] = { params };
67 napi_value returnValue;
68 napi_call_function(env, jsonValue, stringifyValue, 1, funcArgv, &returnValue);
69 size_t len = 0;
70 napi_get_value_string_utf8(env, returnValue, nullptr, 0, &len);
71 std::unique_ptr<char[]> paramsChar = std::make_unique<char[]>(len + 1);
72 napi_get_value_string_utf8(env, returnValue, paramsChar.get(), len + 1, &len);
73 paramsString = paramsChar.get();
74 }
75
76 struct RouterAsyncContext {
77 napi_env env = nullptr;
78 napi_ref callbackSuccess = nullptr;
79 napi_ref callbackFail = nullptr;
80 napi_ref callbackComplete = nullptr;
81 int32_t callbackType = 0;
82 std::string keyForUrl;
83 std::string paramsString;
84 std::string uriString;
85 uint32_t mode = STANDARD;
86 napi_deferred deferred = nullptr;
87 napi_ref callbackRef = nullptr;
88 int32_t callbackCode = 0;
89 std::string callbackMsg;
90 int32_t instanceId = -1;
~RouterAsyncContextOHOS::Ace::Napi::RouterAsyncContext91 ~RouterAsyncContext()
92 {
93 if (callbackRef) {
94 napi_delete_reference(env, callbackRef);
95 }
96 if (callbackSuccess) {
97 napi_delete_reference(env, callbackSuccess);
98 }
99 if (callbackFail) {
100 napi_delete_reference(env, callbackFail);
101 }
102 if (callbackComplete) {
103 napi_delete_reference(env, callbackComplete);
104 }
105 }
106 };
107
108 using RouterFunc = std::function<void(const std::string&, const std::string&, int32_t)>;
109
CommonRouterProcess(napi_env env,napi_callback_info info,const RouterFunc & callback)110 static void CommonRouterProcess(napi_env env, napi_callback_info info, const RouterFunc& callback)
111 {
112 size_t requireArgc = 1;
113 size_t argc = ARGC_WITH_MODE;
114 napi_value argv[ARGC_WITH_MODE] = { 0 };
115 napi_value thisVar = nullptr;
116 void* data = nullptr;
117 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
118 if (argc < requireArgc) {
119 LOGE("params number err");
120 return;
121 }
122 napi_value uriNApi = nullptr;
123 napi_value params = nullptr;
124 napi_valuetype valueType = napi_undefined;
125 napi_typeof(env, argv[0], &valueType);
126 if (valueType == napi_object) {
127 napi_get_named_property(env, argv[0], "url", &uriNApi);
128 napi_typeof(env, uriNApi, &valueType);
129 if (valueType != napi_string) {
130 LOGE("url is invalid");
131 return;
132 }
133 napi_get_named_property(env, argv[0], "params", ¶ms);
134 }
135 std::string paramsString;
136 ParseParams(env, params, paramsString);
137 std::string uriString;
138 napi_typeof(env, uriNApi, &valueType);
139 if (valueType == napi_string) {
140 ParseUri(env, uriNApi, uriString);
141 } else {
142 LOGW("The parameter type is incorrect.");
143 }
144
145 uint32_t mode = INVALID;
146 napi_typeof(env, argv[1], &valueType);
147 if (argc == ARGC_WITH_MODE && valueType == napi_number) {
148 LOGI("router mode with single");
149 napi_get_value_uint32(env, argv[1], &mode);
150 }
151 callback(uriString, paramsString, mode);
152 }
153
JSRouterPush(napi_env env,napi_callback_info info)154 static napi_value JSRouterPush(napi_env env, napi_callback_info info)
155 {
156 LOGI("NAPI router push called");
157 auto callback = [](const std::string& uri, const std::string& params, uint32_t mode) {
158 auto delegate = EngineHelper::GetCurrentDelegate();
159 if (!delegate) {
160 LOGE("can not get delegate.");
161 return;
162 }
163 if (mode == INVALID) {
164 delegate->Push(uri, params);
165 } else {
166 delegate->PushWithMode(uri, params, mode);
167 }
168 };
169 CommonRouterProcess(env, info, callback);
170 return nullptr;
171 }
172
JSRouterReplace(napi_env env,napi_callback_info info)173 static napi_value JSRouterReplace(napi_env env, napi_callback_info info)
174 {
175 LOGI("NAPI router replace called");
176 auto callback = [](const std::string& uri, const std::string& params, uint32_t mode) {
177 auto delegate = EngineHelper::GetCurrentDelegate();
178 if (!delegate) {
179 LOGE("can not get delegate.");
180 return;
181 }
182 if (mode == INVALID) {
183 delegate->Replace(uri, params);
184 } else {
185 delegate->ReplaceWithMode(uri, params, mode);
186 }
187 };
188 CommonRouterProcess(env, info, callback);
189 return nullptr;
190 }
191
ParseParamWithCallback(napi_env env,std::shared_ptr<RouterAsyncContext> asyncContext,const size_t argc,napi_value * argv,napi_value * result)192 bool ParseParamWithCallback(napi_env env, std::shared_ptr<RouterAsyncContext> asyncContext, const size_t argc,
193 napi_value* argv, napi_value* result)
194 {
195 asyncContext->env = env;
196 for (size_t i = 0; i < argc; i++) {
197 napi_valuetype valueType = napi_undefined;
198 napi_typeof(env, argv[i], &valueType);
199 if (i == 0) {
200 if (valueType != napi_object) {
201 NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
202 return false;
203 }
204 napi_value uriNApi = nullptr;
205 napi_value params = nullptr;
206 napi_get_named_property(env, argv[i], asyncContext->keyForUrl.c_str(), &uriNApi);
207 napi_typeof(env, uriNApi, &valueType);
208 if (valueType != napi_string) {
209 LOGW("url is invalid");
210 NapiThrow(env, "The type of the url parameter is not string.", Framework::ERROR_CODE_PARAM_INVALID);
211 return false;
212 }
213 ParseUri(env, uriNApi, asyncContext->uriString);
214 napi_get_named_property(env, argv[i], "params", ¶ms);
215 ParseParams(env, params, asyncContext->paramsString);
216 } else if (valueType == napi_number) {
217 LOGI("router mode with single");
218 napi_get_value_uint32(env, argv[i], &asyncContext->mode);
219 } else if (valueType == napi_function) {
220 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
221 } else {
222 NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
223 return false;
224 }
225 }
226
227 if (asyncContext->callbackRef == nullptr) {
228 if (argc > ARGC_WITH_MODE) {
229 NapiThrow(env, "The largest number of parameters is 2 in Promise.", Framework::ERROR_CODE_PARAM_INVALID);
230 return false;
231 }
232 napi_create_promise(env, &asyncContext->deferred, result);
233 }
234 return true;
235 }
236
TriggerCallback(std::shared_ptr<RouterAsyncContext> asyncContext)237 void TriggerCallback(std::shared_ptr<RouterAsyncContext> asyncContext)
238 {
239 LOGI("trigger callback start");
240 napi_handle_scope scope = nullptr;
241 napi_open_handle_scope(asyncContext->env, &scope);
242 if (scope == nullptr) {
243 return;
244 }
245
246 if (asyncContext->callbackCode == Framework::ERROR_CODE_NO_ERROR) {
247 napi_value result = nullptr;
248 napi_get_undefined(asyncContext->env, &result);
249 if (asyncContext->deferred) {
250 napi_resolve_deferred(asyncContext->env, asyncContext->deferred, result);
251 } else {
252 napi_value callback = nullptr;
253 napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
254 napi_value ret;
255 napi_call_function(asyncContext->env, nullptr, callback, 1, &result, &ret);
256 }
257 } else {
258 napi_value code = nullptr;
259 std::string strCode = std::to_string(asyncContext->callbackCode);
260 napi_create_string_utf8(asyncContext->env, strCode.c_str(), strCode.length(), &code);
261
262 napi_value msg = nullptr;
263 std::string strMsg = ErrorToMessage(asyncContext->callbackCode) + asyncContext->callbackMsg;
264 LOGE("napi throw errCode %{public}d strMsg %{public}s", asyncContext->callbackCode, strMsg.c_str());
265 napi_create_string_utf8(asyncContext->env, strMsg.c_str(), strMsg.length(), &msg);
266
267 napi_value error = nullptr;
268 napi_create_error(asyncContext->env, code, msg, &error);
269 if (asyncContext->deferred) {
270 napi_reject_deferred(asyncContext->env, asyncContext->deferred, error);
271 } else {
272 napi_value callback = nullptr;
273 napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
274 napi_value ret;
275 napi_call_function(asyncContext->env, nullptr, callback, 1, &error, &ret);
276 }
277 }
278 napi_close_handle_scope(asyncContext->env, scope);
279 }
280
281 using ErrorCallback = std::function<void(const std::string&, int32_t)>;
282 using RouterWithCallbackFunc = std::function<void(std::shared_ptr<RouterAsyncContext>, const ErrorCallback&)>;
283
CommonRouterWithCallbackProcess(napi_env env,napi_callback_info info,const RouterWithCallbackFunc & callback,const std::string & keyForUrl)284 static napi_value CommonRouterWithCallbackProcess(
285 napi_env env, napi_callback_info info, const RouterWithCallbackFunc& callback, const std::string& keyForUrl)
286 {
287 napi_value result = nullptr;
288 napi_get_undefined(env, &result);
289 size_t requireArgc = 1;
290 size_t argc = ARGC_WITH_MODE_AND_CALLBACK;
291 napi_value argv[ARGC_WITH_MODE_AND_CALLBACK] = { 0 };
292 napi_value thisVar = nullptr;
293 void* data = nullptr;
294 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
295 if (argc < requireArgc) {
296 LOGW("params number err");
297 NapiThrow(
298 env, "The number of parameters must be greater than or equal to 1.", Framework::ERROR_CODE_PARAM_INVALID);
299 return result;
300 } else if (argc > ARGC_WITH_MODE_AND_CALLBACK) {
301 LOGW("params number err");
302 NapiThrow(env, "The largest number of parameters is 3.", Framework::ERROR_CODE_PARAM_INVALID);
303 return result;
304 }
305
306 auto asyncContext = std::make_shared<RouterAsyncContext>();
307 asyncContext->keyForUrl = keyForUrl;
308 if (!ParseParamWithCallback(env, asyncContext, argc, argv, &result)) {
309 LOGW("parse params failed");
310 return result;
311 }
312
313 auto errorCallback = [asyncContext](const std::string& message, int32_t errCode) mutable {
314 if (!asyncContext) {
315 return;
316 }
317 asyncContext->callbackCode = errCode;
318 asyncContext->callbackMsg = message;
319 TriggerCallback(asyncContext);
320 asyncContext = nullptr;
321 };
322 callback(asyncContext, errorCallback);
323 return result;
324 }
325
JSRouterPushWithCallback(napi_env env,napi_callback_info info)326 static napi_value JSRouterPushWithCallback(napi_env env, napi_callback_info info)
327 {
328 LOGI("NAPI router push with callback called");
329 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
330 auto delegate = EngineHelper::GetCurrentDelegate();
331 if (!delegate) {
332 NapiThrow(context->env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
333 return;
334 }
335 delegate->PushWithCallback(context->uriString, context->paramsString, errorCallback, context->mode);
336 };
337 return CommonRouterWithCallbackProcess(env, info, callback, "url");
338 }
339
JSRouterReplaceWithCallback(napi_env env,napi_callback_info info)340 static napi_value JSRouterReplaceWithCallback(napi_env env, napi_callback_info info)
341 {
342 LOGI("NAPI router replace with callback called");
343 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
344 auto delegate = EngineHelper::GetCurrentDelegate();
345 if (!delegate) {
346 NapiThrow(context->env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
347 return;
348 }
349 delegate->ReplaceWithCallback(context->uriString, context->paramsString, errorCallback, context->mode);
350 };
351 return CommonRouterWithCallbackProcess(env, info, callback, "url");
352 }
353
JSPushNamedRoute(napi_env env,napi_callback_info info)354 static napi_value JSPushNamedRoute(napi_env env, napi_callback_info info)
355 {
356 LOGI("NAPI router push named route called");
357 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
358 auto delegate = EngineHelper::GetCurrentDelegate();
359 if (!delegate) {
360 NapiThrow(context->env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
361 return;
362 }
363 delegate->PushNamedRoute(context->uriString, context->paramsString, errorCallback, context->mode);
364 };
365 return CommonRouterWithCallbackProcess(env, info, callback, "name");
366 }
367
JSReplaceNamedRoute(napi_env env,napi_callback_info info)368 static napi_value JSReplaceNamedRoute(napi_env env, napi_callback_info info)
369 {
370 LOGI("NAPI router replace named route called");
371 auto callback = [](std::shared_ptr<RouterAsyncContext> context, const ErrorCallback& errorCallback) {
372 auto delegate = EngineHelper::GetCurrentDelegate();
373 if (!delegate) {
374 NapiThrow(context->env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
375 return;
376 }
377 delegate->ReplaceNamedRoute(context->uriString, context->paramsString, errorCallback, context->mode);
378 };
379 return CommonRouterWithCallbackProcess(env, info, callback, "name");
380 }
381
JSRouterBack(napi_env env,napi_callback_info info)382 static napi_value JSRouterBack(napi_env env, napi_callback_info info)
383 {
384 size_t argc = 1;
385 napi_value argv = nullptr;
386 napi_value thisVar = nullptr;
387 void* data = nullptr;
388 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
389
390 auto delegate = EngineHelper::GetCurrentDelegate();
391 if (!delegate) {
392 LOGE("can not get delegate.");
393 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
394 return nullptr;
395 }
396 std::string uriString = "";
397 std::string paramsString = "";
398 napi_value uriNApi = nullptr;
399 napi_value params = nullptr;
400 napi_valuetype valueType = napi_undefined;
401 napi_typeof(env, argv, &valueType);
402 if (valueType == napi_object) {
403 napi_get_named_property(env, argv, "url", &uriNApi);
404 napi_typeof(env, uriNApi, &valueType);
405 if (valueType == napi_undefined) {
406 napi_get_named_property(env, argv, "path", &uriNApi);
407 napi_typeof(env, uriNApi, &valueType);
408 }
409 if (valueType == napi_string) {
410 ParseUri(env, uriNApi, uriString);
411 } else {
412 LOGW("the url and path is all invalid");
413 }
414
415 napi_get_named_property(env, argv, "params", ¶ms);
416 napi_typeof(env, params, &valueType);
417 if (valueType == napi_object) {
418 ParseParams(env, params, paramsString);
419 } else {
420 LOGW("The parameter type is incorrect.");
421 }
422 }
423 delegate->Back(uriString, paramsString);
424 return nullptr;
425 }
426
JSRouterClear(napi_env env,napi_callback_info info)427 static napi_value JSRouterClear(napi_env env, napi_callback_info info)
428 {
429 auto delegate = EngineHelper::GetCurrentDelegate();
430 if (!delegate) {
431 LOGE("can not get delegate.");
432 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
433 return nullptr;
434 }
435 delegate->Clear();
436 return nullptr;
437 }
438
JSRouterGetLength(napi_env env,napi_callback_info info)439 static napi_value JSRouterGetLength(napi_env env, napi_callback_info info)
440 {
441 auto delegate = EngineHelper::GetCurrentDelegate();
442 if (!delegate) {
443 LOGE("can not get delegate.");
444 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
445 return nullptr;
446 }
447 int32_t routeNumber = delegate->GetStackSize();
448 napi_value routeNApiNum = nullptr;
449 napi_create_int32(env, routeNumber, &routeNApiNum);
450 napi_value result = nullptr;
451 napi_coerce_to_string(env, routeNApiNum, &result);
452 return result;
453 }
454
JSRouterGetState(napi_env env,napi_callback_info info)455 static napi_value JSRouterGetState(napi_env env, napi_callback_info info)
456 {
457 int32_t routeIndex = 0;
458 std::string routeName;
459 std::string routePath;
460 auto delegate = EngineHelper::GetCurrentDelegate();
461 if (!delegate) {
462 LOGE("can not get delegate.");
463 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
464 return nullptr;
465 }
466 delegate->GetState(routeIndex, routeName, routePath);
467 size_t routeNameLen = routeName.length();
468 size_t routePathLen = routePath.length();
469
470 napi_value resultArray[3] = { 0 };
471 napi_create_int32(env, routeIndex, &resultArray[0]);
472 napi_create_string_utf8(env, routeName.c_str(), routeNameLen, &resultArray[1]);
473 napi_create_string_utf8(env, routePath.c_str(), routePathLen, &resultArray[2]);
474
475 napi_value result = nullptr;
476 napi_create_object(env, &result);
477 napi_set_named_property(env, result, "index", resultArray[0]);
478 napi_set_named_property(env, result, "name", resultArray[1]);
479 napi_set_named_property(env, result, "path", resultArray[2]);
480 return result;
481 }
482
CallBackToJSTread(std::shared_ptr<RouterAsyncContext> context)483 void CallBackToJSTread(std::shared_ptr<RouterAsyncContext> context)
484 {
485 auto container = AceEngine::Get().GetContainer(context->instanceId);
486 if (!container) {
487 LOGW("container is null. %{public}d", context->instanceId);
488 return;
489 }
490
491 auto taskExecutor = container->GetTaskExecutor();
492 if (!taskExecutor) {
493 LOGW("taskExecutor is null.");
494 return;
495 }
496 taskExecutor->PostTask(
497 [context]() {
498 napi_handle_scope scope = nullptr;
499 napi_open_handle_scope(context->env, &scope);
500 if (scope == nullptr) {
501 return;
502 }
503
504 napi_value result = nullptr;
505 napi_value callback = nullptr;
506 napi_value ret = nullptr;
507 if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CONFIRM) {
508 if (context->callbackSuccess) {
509 napi_create_string_utf8(context->env, EN_ALERT_APPROVE, NAPI_AUTO_LENGTH, &result);
510 napi_value argv[1] = { result };
511 napi_get_reference_value(context->env, context->callbackSuccess, &callback);
512 napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
513 }
514 if (context->callbackComplete) {
515 napi_get_reference_value(context->env, context->callbackComplete, &callback);
516 napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
517 }
518 }
519 if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CANCEL) {
520 if (context->callbackFail) {
521 napi_create_string_utf8(context->env, EN_ALERT_REJECT, NAPI_AUTO_LENGTH, &result);
522 napi_value argv[1] = { result };
523 napi_get_reference_value(context->env, context->callbackFail, &callback);
524 napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
525 }
526 if (context->callbackComplete) {
527 napi_get_reference_value(context->env, context->callbackComplete, &callback);
528 napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
529 }
530 }
531
532 napi_close_handle_scope(context->env, scope);
533 },
534 TaskExecutor::TaskType::JS);
535 }
536
JSRouterEnableAlertBeforeBackPage(napi_env env,napi_callback_info info)537 static napi_value JSRouterEnableAlertBeforeBackPage(napi_env env, napi_callback_info info)
538 {
539 size_t argc = 1;
540 napi_value argv = nullptr;
541 napi_value thisVar = nullptr;
542 void* data = nullptr;
543 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
544
545 napi_valuetype valueType = napi_undefined;
546 napi_typeof(env, argv, &valueType);
547 if (valueType != napi_object) {
548 LOGW("EnableAlertBeforeBackPage: params is null");
549 NapiThrow(env, "The type of the parameter is not object.", Framework::ERROR_CODE_PARAM_INVALID);
550 return nullptr;
551 }
552
553 napi_value messageNapi = nullptr;
554 std::unique_ptr<char[]> messageChar;
555 napi_get_named_property(env, argv, "message", &messageNapi);
556 napi_typeof(env, messageNapi, &valueType);
557 if (valueType == napi_string) {
558 size_t length = 0;
559 napi_get_value_string_utf8(env, messageNapi, nullptr, 0, &length);
560 messageChar = std::make_unique<char[]>(length + 1);
561 napi_get_value_string_utf8(env, messageNapi, messageChar.get(), length + 1, &length);
562 } else {
563 LOGW("EnableAlertBeforeBackPage: message is null");
564 NapiThrow(env, "The type of the message is not string.", Framework::ERROR_CODE_PARAM_INVALID);
565 return nullptr;
566 }
567
568 auto delegate = EngineHelper::GetCurrentDelegate();
569 if (!delegate) {
570 LOGW("EnableAlertBeforeBackPage: delegate is null");
571 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
572 return nullptr;
573 }
574
575 auto context = std::make_shared<RouterAsyncContext>();
576 context->env = env;
577 context->instanceId = Container::CurrentId();
578 napi_value successFunc = nullptr;
579 napi_value failFunc = nullptr;
580 napi_value completeFunc = nullptr;
581 napi_get_named_property(env, argv, "success", &successFunc);
582 napi_get_named_property(env, argv, "cancel", &failFunc);
583 napi_get_named_property(env, argv, "complete", &completeFunc);
584 bool isNeedCallBack = false;
585 napi_typeof(env, successFunc, &valueType);
586 if (valueType == napi_function) {
587 napi_create_reference(env, successFunc, 1, &context->callbackSuccess);
588 isNeedCallBack = true;
589 }
590
591 napi_typeof(env, failFunc, &valueType);
592 if (valueType == napi_function) {
593 napi_create_reference(env, failFunc, 1, &context->callbackFail);
594 isNeedCallBack = true;
595 }
596 napi_typeof(env, completeFunc, &valueType);
597 if (valueType == napi_function) {
598 napi_create_reference(env, completeFunc, 1, &context->callbackComplete);
599 isNeedCallBack = true;
600 }
601
602 auto dilogCallback = [context, isNeedCallBack](int32_t callbackType) mutable {
603 LOGI("callback after dialog click, callbackType = %{public}d", callbackType);
604 if (context && isNeedCallBack) {
605 if (Framework::AlertState(callbackType) == Framework::AlertState::RECOVERY) {
606 context = nullptr;
607 return;
608 }
609 context->callbackType = callbackType;
610 CallBackToJSTread(context);
611 }
612 };
613 delegate->EnableAlertBeforeBackPage(messageChar.get(), std::move(dilogCallback));
614
615 return nullptr;
616 }
617
JSRouterDisableAlertBeforeBackPage(napi_env env,napi_callback_info info)618 static napi_value JSRouterDisableAlertBeforeBackPage(napi_env env, napi_callback_info info)
619 {
620 auto delegate = EngineHelper::GetCurrentDelegate();
621 if (delegate) {
622 delegate->DisableAlertBeforeBackPage();
623 } else {
624 LOGW("DisableAlertBeforeBackPage: delegate is null");
625 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
626 return nullptr;
627 }
628
629 size_t argc = 1;
630 napi_value argv = nullptr;
631 napi_value thisVar = nullptr;
632 void* data = nullptr;
633 napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
634 napi_valuetype valueType = napi_undefined;
635 napi_typeof(env, argv, &valueType);
636 if (valueType == napi_object) {
637 napi_value successFunc = nullptr;
638 napi_value completeFunc = nullptr;
639 napi_get_named_property(env, argv, "success", &successFunc);
640 napi_get_named_property(env, argv, "complete", &completeFunc);
641
642 napi_value result = nullptr;
643 napi_value ret = nullptr;
644 napi_create_string_utf8(env, DIS_ALERT_SUCCESS, NAPI_AUTO_LENGTH, &result);
645 napi_value argv[1] = { result };
646
647 napi_typeof(env, successFunc, &valueType);
648 if (valueType == napi_function) {
649 napi_call_function(env, nullptr, successFunc, 1, argv, &ret);
650 }
651 napi_typeof(env, completeFunc, &valueType);
652 if (valueType == napi_function) {
653 napi_call_function(env, nullptr, completeFunc, 1, argv, &ret);
654 }
655 }
656 return nullptr;
657 }
658
JSRouterGetParams(napi_env env,napi_callback_info info)659 static napi_value JSRouterGetParams(napi_env env, napi_callback_info info)
660 {
661 auto delegate = EngineHelper::GetCurrentDelegate();
662 if (!delegate) {
663 LOGE("can not get delegate.");
664 NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
665 return nullptr;
666 }
667 std::string paramsStr = delegate->GetParams();
668 if (paramsStr.empty()) {
669 LOGI("PageGetParams params is null");
670 return nullptr;
671 }
672 napi_value globalValue;
673 napi_get_global(env, &globalValue);
674 napi_value jsonValue;
675 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
676 napi_value parseValue;
677 napi_get_named_property(env, jsonValue, "parse", &parseValue);
678 napi_value routerParamsNApi;
679 napi_create_string_utf8(env, paramsStr.c_str(), NAPI_AUTO_LENGTH, &routerParamsNApi);
680 napi_value funcArgv[1] = { routerParamsNApi };
681 napi_value result;
682 napi_call_function(env, jsonValue, parseValue, 1, funcArgv, &result);
683 napi_valuetype valueType = napi_undefined;
684 napi_typeof(env, result, &valueType);
685 if (valueType != napi_object) {
686 LOGE("parse result fail");
687 return nullptr;
688 }
689 return result;
690 }
691
RouterExport(napi_env env,napi_value exports)692 static napi_value RouterExport(napi_env env, napi_value exports)
693 {
694 napi_value routerMode = nullptr;
695 napi_create_object(env, &routerMode);
696 napi_value prop = nullptr;
697 napi_create_uint32(env, STANDARD, &prop);
698 napi_set_named_property(env, routerMode, "Standard", prop);
699 napi_create_uint32(env, SINGLE, &prop);
700 napi_set_named_property(env, routerMode, "Single", prop);
701
702 napi_property_descriptor routerDesc[] = {
703 DECLARE_NAPI_FUNCTION("push", JSRouterPush),
704 DECLARE_NAPI_FUNCTION("pushUrl", JSRouterPushWithCallback),
705 DECLARE_NAPI_FUNCTION("replace", JSRouterReplace),
706 DECLARE_NAPI_FUNCTION("replaceUrl", JSRouterReplaceWithCallback),
707 DECLARE_NAPI_FUNCTION("back", JSRouterBack),
708 DECLARE_NAPI_FUNCTION("clear", JSRouterClear),
709 DECLARE_NAPI_FUNCTION("getLength", JSRouterGetLength),
710 DECLARE_NAPI_FUNCTION("getState", JSRouterGetState),
711 DECLARE_NAPI_FUNCTION("enableAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
712 DECLARE_NAPI_FUNCTION("enableBackPageAlert", JSRouterEnableAlertBeforeBackPage),
713 DECLARE_NAPI_FUNCTION("showAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
714 DECLARE_NAPI_FUNCTION("disableAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
715 DECLARE_NAPI_FUNCTION("hideAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
716 DECLARE_NAPI_FUNCTION("getParams", JSRouterGetParams),
717 DECLARE_NAPI_FUNCTION("pushNamedRoute", JSPushNamedRoute),
718 DECLARE_NAPI_FUNCTION("replaceNamedRoute", JSReplaceNamedRoute),
719 DECLARE_NAPI_PROPERTY("RouterMode", routerMode),
720 };
721 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(routerDesc) / sizeof(routerDesc[0]), routerDesc));
722
723 return exports;
724 }
725
726 static napi_module routerModule = {
727 .nm_version = 1,
728 .nm_flags = 0,
729 .nm_filename = nullptr,
730 .nm_register_func = RouterExport,
731 .nm_modname = "router",
732 .nm_priv = ((void*)0),
733 .reserved = { 0 },
734 };
735
RouterRegister()736 extern "C" __attribute__((constructor)) void RouterRegister()
737 {
738 napi_module_register(&routerModule);
739 }
740
741 } // namespace OHOS::Ace::Napi
742