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