1 /*
2 * Copyright (c) 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 "webview_javascript_result_callback.h"
17
18 #include "napi_parse_utils.h"
19 #include "nweb_log.h"
20
21 namespace OHOS::NWeb {
22
~WebviewJavaScriptResultCallBack()23 WebviewJavaScriptResultCallBack::~WebviewJavaScriptResultCallBack()
24 {
25 for (auto it1 = objectMap_.begin(); it1 != objectMap_.end(); ++it1) {
26 for (auto it2 = it1->second.methodMap.begin(); it2 != it1->second.methodMap.end(); ++it2) {
27 napi_delete_reference(it1->second.env, it2->second);
28 }
29 }
30 }
31
UvJsCallbackThreadWoker(uv_work_t * work,int status)32 void WebviewJavaScriptResultCallBack::UvJsCallbackThreadWoker(uv_work_t *work, int status)
33 {
34 if (work == nullptr) {
35 WVLOG_E("uv work is null");
36 return;
37 }
38 WebviewJavaScriptResultCallBack::NapiJsCallBackParm *param =
39 reinterpret_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackParm*>(work->data);
40 if (param == nullptr) {
41 WVLOG_E("NapiJsCallBackParm is null");
42 delete work;
43 work = nullptr;
44 return;
45 }
46 napi_handle_scope scope = nullptr;
47 napi_open_handle_scope(param->env_, &scope);
48 if (scope == nullptr) {
49 return;
50 }
51
52 std::vector<napi_value> argv = {};
53 for (std::shared_ptr<NWebValue> input: param->args_) {
54 ParseNwebValue2NapiValue(param->env_, input, argv);
55 }
56
57 napi_value callback = nullptr;
58 napi_value callResult = nullptr;
59 napi_get_reference_value(param->env_, param->callback_, &callback);
60 napi_call_function(param->env_, nullptr, callback, argv.size(), &argv[0], &callResult);
61 // convert to nweb value
62 ParseNapiValue2NwebValue(param->env_, callResult, param->value_);
63
64 std::unique_lock<std::mutex> lock(param->mutex_);
65 param->ready_ = true;
66 param->condition_.notify_all();
67 napi_close_handle_scope(param->env_, scope);
68 }
69
GetJavaScriptResult(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName)70 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResult(
71 std::vector<std::shared_ptr<NWebValue>> args,
72 const std::string& method,
73 const std::string& objName)
74 {
75 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResult method = %{public}s, objName = %{public}s",
76 method.c_str(), objName.c_str());
77 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
78
79 if (objectMap_.find(objName) == objectMap_.end()) {
80 return ret;
81 }
82 JavaScriptObj jsObj = objectMap_[objName];
83 if (jsObj.methodMap.find(method) == jsObj.methodMap.end()) {
84 return ret;
85 }
86
87 uv_loop_s *loop = nullptr;
88 uv_work_t *work = nullptr;
89 napi_get_uv_event_loop(jsObj.env, &loop);
90 if (loop == nullptr) {
91 WVLOG_E("get uv event loop failed");
92 return ret;
93 }
94 work = new (std::nothrow) uv_work_t;
95 if (work == nullptr) {
96 WVLOG_E("new uv work failed");
97 return ret;
98 }
99 WebviewJavaScriptResultCallBack::NapiJsCallBackParm *param =
100 new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackParm();
101 if (param == nullptr) {
102 WVLOG_E("new WebMsgPortParam failed");
103 delete work;
104 return ret;
105 }
106
107 param->env_ = jsObj.env;
108 param->callback_ = jsObj.methodMap[method];
109 param->args_ = args;
110 param->value_ = ret;
111
112 work->data = reinterpret_cast<void*>(param);
113 uv_queue_work(loop, work, [](uv_work_t *work) {}, UvJsCallbackThreadWoker);
114 std::unique_lock<std::mutex> lock(param->mutex_);
115 param->condition_.wait(lock, [¶m] { return param->ready_; });
116 if (param != nullptr) {
117 delete param;
118 param = nullptr;
119 }
120 if (work != nullptr) {
121 delete work;
122 work = nullptr;
123 }
124 return ret;
125 }
126
RegisterJavaScriptProxy(napi_env env,napi_value obj,const std::string & objName,const std::vector<std::string> & methodList)127 void WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy(napi_env env, napi_value obj,
128 const std::string& objName, const std::vector<std::string>& methodList)
129 {
130 if (objectMap_.find(objName) != objectMap_.end()) {
131 WVLOG_I("object already exists, objName = %{public}s", objName.c_str());
132 return;
133 }
134
135 JavaScriptObj jsObj;
136 jsObj.env = env;
137 for (uint32_t i = 0; i < methodList.size(); i++) {
138 std::string methodName = methodList[i];
139 bool hasFunc = false;
140 napi_value result = nullptr;
141 napi_valuetype valueType = napi_undefined;
142 napi_ref callback = nullptr;
143
144 napi_has_named_property(env, obj, methodName.c_str(), &hasFunc);
145 if (!hasFunc) {
146 continue;
147 }
148 napi_get_named_property(env, obj, methodName.c_str(), &result);
149 napi_typeof(env, result, &valueType);
150 if (valueType != napi_function) {
151 continue;
152 }
153 napi_create_reference(env, result, 1, &callback);
154 jsObj.methodMap[methodName] = callback;
155 }
156
157 objectMap_[objName] = jsObj;
158 }
159
DeleteJavaScriptRegister(const std::string & objName)160 bool WebviewJavaScriptResultCallBack::DeleteJavaScriptRegister(const std::string& objName)
161 {
162 if (objectMap_.find(objName) == objectMap_.end()) {
163 return false;
164 }
165
166 for (auto it = objectMap_[objName].methodMap.begin(); it != objectMap_[objName].methodMap.end(); ++it) {
167 napi_delete_reference(objectMap_[objName].env, it->second);
168 }
169 objectMap_.erase(objName);
170 return true;
171 }
172
ParseNwebValue2NapiValue(napi_env env,std::shared_ptr<NWebValue> value,std::vector<napi_value> & argv)173 void WebviewJavaScriptResultCallBack::ParseNwebValue2NapiValue(
174 napi_env env,
175 std::shared_ptr<NWebValue> value,
176 std::vector<napi_value>& argv)
177 {
178 napi_value napiValue = nullptr;
179
180 switch (value->GetType()) {
181 case NWebValue::Type::INTEGER:
182 napi_create_int32(env, value->GetInt(), &napiValue);
183 argv.push_back(napiValue);
184 break;
185 case NWebValue::Type::DOUBLE:
186 napi_create_double(env, value->GetDouble(), &napiValue);
187 argv.push_back(napiValue);
188 break;
189 case NWebValue::Type::BOOLEAN:
190 napi_get_boolean(env, value->GetBoolean(), &napiValue);
191 argv.push_back(napiValue);
192 break;
193 case NWebValue::Type::STRING:
194 napi_create_string_utf8(env, value->GetString().c_str(), NAPI_AUTO_LENGTH, &napiValue);
195 argv.push_back(napiValue);
196 break;
197 case NWebValue::Type::NONE:
198 default:
199 WVLOG_E("ParseNwebValue2NapiValue invalid type");
200 break;
201 }
202 }
203
ParseNapiValue2NwebValue(napi_env env,napi_value value,std::shared_ptr<NWebValue> nwebValue)204 void WebviewJavaScriptResultCallBack::ParseNapiValue2NwebValue(
205 napi_env env, napi_value value,
206 std::shared_ptr<NWebValue> nwebValue)
207 {
208 napi_valuetype valueType = napi_undefined;
209 napi_typeof(env, value, &valueType);
210
211 switch (valueType) {
212 case napi_number: {
213 double douVal = 0.0;
214 napi_get_value_double(env, value, &douVal);
215 nwebValue->SetType(NWebValue::Type::DOUBLE);
216 nwebValue->SetDouble(douVal);
217 break;
218 }
219 case napi_boolean: {
220 bool boolVal;
221 napi_get_value_bool(env, value, &boolVal);
222 nwebValue->SetType(NWebValue::Type::BOOLEAN);
223 nwebValue->SetBoolean(boolVal);
224 break;
225 }
226 case napi_string: {
227 std::string strVal;
228 if (!NapiParseUtils::ParseString(env, value, strVal)) {
229 return;
230 }
231 nwebValue->SetType(NWebValue::Type::STRING);
232 nwebValue->SetString(strVal);
233 break;
234 }
235 default: {
236 WVLOG_E("ParseNapiValue2NwebValue invalid type");
237 break;
238 }
239 }
240 }
241
242 }