• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, [&param] { 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 }