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, const std::string& method, const std::string& objName)
72 {
73 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResult method = %{public}s, objName = %{public}s",
74 method.c_str(), objName.c_str());
75 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
76
77 if (objectMap_.find(objName) == objectMap_.end()) {
78 return ret;
79 }
80 JavaScriptObj jsObj = objectMap_[objName];
81 if (jsObj.methodMap.find(method) == jsObj.methodMap.end()) {
82 return ret;
83 }
84
85 uv_loop_s* loop = nullptr;
86 uv_work_t* work = nullptr;
87 napi_get_uv_event_loop(jsObj.env, &loop);
88 if (loop == nullptr) {
89 WVLOG_E("get uv event loop failed");
90 return ret;
91 }
92 work = new (std::nothrow) uv_work_t;
93 if (work == nullptr) {
94 WVLOG_E("new uv work failed");
95 return ret;
96 }
97 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param =
98 new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackParm();
99 if (param == nullptr) {
100 WVLOG_E("new WebMsgPortParam failed");
101 delete work;
102 return ret;
103 }
104
105 param->env_ = jsObj.env;
106 param->callback_ = jsObj.methodMap[method];
107 param->args_ = args;
108 param->value_ = ret;
109
110 work->data = reinterpret_cast<void*>(param);
111 uv_queue_work(loop, work, [](uv_work_t* work) {}, UvJsCallbackThreadWoker);
112
113 {
114 std::unique_lock<std::mutex> lock(param->mutex_);
115 param->condition_.wait(lock, [¶m] { return param->ready_; });
116 }
117 if (param != nullptr) {
118 delete param;
119 param = nullptr;
120 }
121 if (work != nullptr) {
122 delete work;
123 work = nullptr;
124 }
125 return ret;
126 }
127
RegisterJavaScriptProxy(napi_env env,napi_value obj,const std::string & objName,const std::vector<std::string> & methodList)128 void WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy(
129 napi_env env, napi_value obj, const std::string& objName, const std::vector<std::string>& methodList)
130 {
131 if (objectMap_.find(objName) != objectMap_.end()) {
132 WVLOG_I("object already exists, objName = %{public}s", objName.c_str());
133 return;
134 }
135
136 JavaScriptObj jsObj;
137 jsObj.env = env;
138 for (uint32_t i = 0; i < methodList.size(); i++) {
139 std::string methodName = methodList[i];
140 bool hasFunc = false;
141 napi_value result = nullptr;
142 napi_valuetype valueType = napi_undefined;
143 napi_ref callback = nullptr;
144
145 napi_has_named_property(env, obj, methodName.c_str(), &hasFunc);
146 if (!hasFunc) {
147 continue;
148 }
149 napi_get_named_property(env, obj, methodName.c_str(), &result);
150 napi_typeof(env, result, &valueType);
151 if (valueType != napi_function) {
152 continue;
153 }
154 napi_create_reference(env, result, 1, &callback);
155 jsObj.methodMap[methodName] = callback;
156 }
157
158 objectMap_[objName] = jsObj;
159 }
160
DeleteJavaScriptRegister(const std::string & objName)161 bool WebviewJavaScriptResultCallBack::DeleteJavaScriptRegister(const std::string& objName)
162 {
163 if (objectMap_.find(objName) == objectMap_.end()) {
164 return false;
165 }
166
167 for (auto it = objectMap_[objName].methodMap.begin(); it != objectMap_[objName].methodMap.end(); ++it) {
168 napi_delete_reference(objectMap_[objName].env, it->second);
169 }
170 objectMap_.erase(objName);
171 return true;
172 }
173
ParseNwebValue2NapiValue(napi_env env,std::shared_ptr<NWebValue> value,std::vector<napi_value> & argv)174 void WebviewJavaScriptResultCallBack::ParseNwebValue2NapiValue(
175 napi_env env, std::shared_ptr<NWebValue> value, std::vector<napi_value>& argv)
176 {
177 napi_value napiValue = nullptr;
178
179 switch (value->GetType()) {
180 case NWebValue::Type::INTEGER:
181 napi_create_int32(env, value->GetInt(), &napiValue);
182 argv.push_back(napiValue);
183 break;
184 case NWebValue::Type::DOUBLE:
185 napi_create_double(env, value->GetDouble(), &napiValue);
186 argv.push_back(napiValue);
187 break;
188 case NWebValue::Type::BOOLEAN:
189 napi_get_boolean(env, value->GetBoolean(), &napiValue);
190 argv.push_back(napiValue);
191 break;
192 case NWebValue::Type::STRING:
193 napi_create_string_utf8(env, value->GetString().c_str(), NAPI_AUTO_LENGTH, &napiValue);
194 argv.push_back(napiValue);
195 break;
196 case NWebValue::Type::NONE:
197 default:
198 std::string msgStr = "notSupportType";
199 napi_create_string_utf8(env, msgStr.c_str(), msgStr.length(), &napiValue);
200 argv.push_back(napiValue);
201 WVLOG_E("ParseNwebValue2NapiValue invalid type");
202 break;
203 }
204 }
205
ParseNapiValue2NwebValue(napi_env env,napi_value value,std::shared_ptr<NWebValue> nwebValue)206 void WebviewJavaScriptResultCallBack::ParseNapiValue2NwebValue(
207 napi_env env, napi_value value, std::shared_ptr<NWebValue> nwebValue)
208 {
209 napi_valuetype valueType = napi_undefined;
210 napi_typeof(env, value, &valueType);
211
212 switch (valueType) {
213 case napi_number: {
214 double douVal = 0.0;
215 napi_get_value_double(env, value, &douVal);
216 nwebValue->SetType(NWebValue::Type::DOUBLE);
217 nwebValue->SetDouble(douVal);
218 break;
219 }
220 case napi_boolean: {
221 bool boolVal;
222 napi_get_value_bool(env, value, &boolVal);
223 nwebValue->SetType(NWebValue::Type::BOOLEAN);
224 nwebValue->SetBoolean(boolVal);
225 break;
226 }
227 case napi_string: {
228 std::string strVal;
229 if (!NapiParseUtils::ParseString(env, value, strVal)) {
230 return;
231 }
232 nwebValue->SetType(NWebValue::Type::STRING);
233 nwebValue->SetString(strVal);
234 break;
235 }
236 default: {
237 WVLOG_E("ParseNapiValue2NwebValue invalid type");
238 break;
239 }
240 }
241 }
242
243 } // namespace OHOS::NWeb