• 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, 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, [&param] { 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