已关闭
【ArkWeb】WebviewController API接口适配 Web组件属性和事件接口适配 #282
quguiren创建于 2025年10月13日关闭于 2025年10月16日
【ArkWeb】WebviewController API接口适配 Web组件属性和事件接口适配 #282
已关闭
quguiren创建于 2025年10月13日关闭于 2025年10月16日
22 个文件变更+3392-11
MOAT.xml+1-0
@@ -59,6 +59,7 @@ Note:If the text contains special characters, please escape them according to th
59 <policyitem type="license" name="BSD-3-Clause" path=".*" desc="不影响兼容性"/>59 <policyitem type="license" name="BSD-3-Clause" path=".*" desc="不影响兼容性"/>
60 <policyitem type="license" name="curl" path="net/http/ios/curl_slist.cpp" desc="不影响兼容性"/>60 <policyitem type="license" name="curl" path="net/http/ios/curl_slist.cpp" desc="不影响兼容性"/>
61 <policyitem type="license" name="curl" path="net/http/ios/curl_slist.h" desc="不影响兼容性"/>61 <policyitem type="license" name="curl" path="net/http/ios/curl_slist.h" desc="不影响兼容性"/>
62+ <policyitem type="copyright" name="Huawei Technologies Co., Ltd." path=".*" desc="copyright"/>
62 </policy>63 </policy>
63 </policylist>64 </policylist>
64 <filefilterlist>65 <filefilterlist>
@@ -28,6 +28,8 @@ template("plugin_web_webview_static") {
28 "//commomlibrary/c_utils/base/include",28 "//commomlibrary/c_utils/base/include",
29 "//plugins/interfaces/native",29 "//plugins/interfaces/native",
30 ]30 ]
31+ include_dirs +=
32+ [ "//foundation/arkui/ace_engine/adapter/ios/capability/web/" ]
31 33 
32 sources = web_source34 sources = web_source
33 sources += [35 sources += [
@@ -36,12 +38,14 @@ template("plugin_web_webview_static") {
36 "js_web_webview.cpp",38 "js_web_webview.cpp",
37 "napi_parse_utils.cpp",39 "napi_parse_utils.cpp",
38 "napi_web_message_ext.cpp",40 "napi_web_message_ext.cpp",
41+ "napi_web_scheme_handler_request.cpp",
39 "web_cookie_manager.cpp",42 "web_cookie_manager.cpp",
40 "web_cookie_manager_callback.cpp",43 "web_cookie_manager_callback.cpp",
41 "web_download_delegate.cpp",44 "web_download_delegate.cpp",
42 "web_download_item.cpp",45 "web_download_item.cpp",
43 "web_download_manager.cpp",46 "web_download_manager.cpp",
44 "web_message_port.cpp",47 "web_message_port.cpp",
48+ "web_scheme_handler_request.cpp",
45 "web_storage.cpp",49 "web_storage.cpp",
46 "web_storage_callback.cpp",50 "web_storage_callback.cpp",
47 "webview_async_work_callback.cpp",51 "webview_async_work_callback.cpp",
@@ -14,6 +14,14 @@
14import("//build/ohos.gni")14import("//build/ohos.gni")
15import("//plugins/web/webview/web_webview.gni")15import("//plugins/web/webview/web_webview.gni")
16 16 
17+java_library("android_asset_android_java") {
18+ java_files = [
19+ "src/ohos/ace/plugin/webviewplugin/androidasset/AndroidAssetPlugin.java",
20+ ]
21+ subsystem_name = "plugins"
22+ part_name = "web_webview"
23+}
24+ 
17java_library("cookie_manager_android_java") {25java_library("cookie_manager_android_java") {
18 java_files =26 java_files =
19 [ "src/ohos/ace/plugin/webviewplugin/webcookie/WebCookiePlugin.java" ]27 [ "src/ohos/ace/plugin/webviewplugin/webcookie/WebCookiePlugin.java" ]
@@ -30,6 +38,7 @@ java_library("web_storage_android_java") {
30 38 
31ohos_combine_jars("web_webview_java") {39ohos_combine_jars("web_webview_java") {
32 deps = [40 deps = [
41+ ":android_asset_android_java",
33 ":cookie_manager_android_java",42 ":cookie_manager_android_java",
34 ":web_storage_android_java",43 ":web_storage_android_java",
35 ]44 ]
@@ -40,6 +49,7 @@ ohos_combine_jars("web_webview_java") {
40 49 
41ohos_source_set("web_webview_android_jni") {50ohos_source_set("web_webview_android_jni") {
42 sources = [51 sources = [
52+ "jni/android_asset_helper_jni.cpp",
43 "jni/geolocation_permissions_android.cpp",53 "jni/geolocation_permissions_android.cpp",
44 "jni/geolocation_permissions_jni.cpp",54 "jni/geolocation_permissions_jni.cpp",
45 "jni/web_cookie_manager_android.cpp",55 "jni/web_cookie_manager_android.cpp",
@@ -50,6 +60,7 @@ ohos_source_set("web_webview_android_jni") {
50 "jni/web_download_item_jni.cpp",60 "jni/web_download_item_jni.cpp",
51 "jni/web_download_manager_android.cpp",61 "jni/web_download_manager_android.cpp",
52 "jni/web_message_port_android.cpp",62 "jni/web_message_port_android.cpp",
63+ "jni/web_scheme_handler_jni.cpp",
53 "jni/web_storage_android.cpp",64 "jni/web_storage_android.cpp",
54 "jni/web_storage_jni.cpp",65 "jni/web_storage_jni.cpp",
55 "jni/webview_controller_android.cpp",66 "jni/webview_controller_android.cpp",
@@ -0,0 +1,85 @@
1+/*
2+ * Copyright (c) 2025 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 "plugins/web/webview/android/java/jni/android_asset_helper_jni.h"
17+ 
18+#include <jni.h>
19+ 
20+#include "inner_api/plugin_utils_inner.h"
21+#include "log.h"
22+#include "plugin_utils.h"
23+ 
24+namespace OHOS::Plugin {
25+namespace {
26+const char WEB_WEBVIEW_CLASS_NAME[] = "ohos/ace/plugin/webviewplugin/androidasset/AndroidAssetPlugin";
27+ 
28+static const JNINativeMethod METHODS[] = {
29+ { "nativeInit", "()V", reinterpret_cast<void*>(AndroidAssetHelperJni::NativeInit) },
30+};
31+static const char METHOD_EXISTS_VIRTUAL_ASSET[] = "existsVirtualAsset";
32+ 
33+static const char SIGNATURE_EXISTS_VIRTUAL_ASSET[] = "(Ljava/lang/String;)Z";
34+struct {
35+ jmethodID existsVirtualAsset;
36+ jobject globalRef;
37+} g_webWebviewClass;
liulong
liulongliulong2025年10月15日
  当前建议代码无改动

g_webViewClass

likedislike
38+} // namespace
39+ 
40+bool AndroidAssetHelperJni::Register(void* env)
41+{
42+ auto* jniEnv = static_cast<JNIEnv*>(env);
43+ CHECK_NULL_RETURN(jniEnv, false);
44+ jclass cls = jniEnv->FindClass(WEB_WEBVIEW_CLASS_NAME);
45+ CHECK_NULL_RETURN(cls, false);
46+ bool ret = jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0])) == 0;
47+ jniEnv->DeleteLocalRef(cls);
48+ if (!ret) {
49+ LOGE("AndroidAssetHelperJni JNI: RegisterNatives fail.");
50+ }
51+ return ret;
52+}
53+ 
54+void AndroidAssetHelperJni::NativeInit(JNIEnv* env, jobject jobj)
55+{
56+ CHECK_NULL_VOID(env);
57+ g_webWebviewClass.globalRef = env->NewGlobalRef(jobj);
58+ CHECK_NULL_VOID(g_webWebviewClass.globalRef);
59+ jclass cls = env->GetObjectClass(jobj);
liulong
liulongliulong2025年10月15日

需要调用DeleteLocalRef接口释放?

likedislike
quguiren
2025年10月15日 评论:
60+ CHECK_NULL_VOID(cls);
61+ g_webWebviewClass.existsVirtualAsset = env->GetMethodID(cls, METHOD_EXISTS_VIRTUAL_ASSET,
62+ SIGNATURE_EXISTS_VIRTUAL_ASSET);
63+ env->DeleteLocalRef(cls);
64+}
65+ 
66+bool AndroidAssetHelperJni::ExistsVirtualAsset(const std::string& url)
67+{
68+ auto env = ARKUI_X_Plugin_GetJniEnv();
69+ if (!(env) || !(g_webWebviewClass.globalRef) || !(g_webWebviewClass.existsVirtualAsset)) {
70+ LOGE("AndroidAssetHelperJni JNI: call ExistsVirtualAsset env fail");
71+ return false;
liulong
liulongliulong2025年10月15日

异常场景,增加日志,方便问题定位。

likedislike
quguiren
2025年10月15日 评论:
72+ }
73+ jstring jUrl = env->NewStringUTF(url.c_str());
74+ CHECK_NULL_RETURN(jUrl, false);
75+ jboolean isExists = env->CallBooleanMethod(g_webWebviewClass.globalRef, g_webWebviewClass.existsVirtualAsset,
76+ jUrl);
77+ if (env->ExceptionCheck()) {
78+ LOGE("AndroidAssetHelperJni JNI: call ExistsVirtualAsset has exception");
79+ env->ExceptionDescribe();
80+ env->ExceptionClear();
81+ }
82+ env->DeleteLocalRef(jUrl);
83+ return isExists;
84+}
85+} // namespace OHOS::Plugin
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (c) 2025 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+#ifndef PLUGINS_WEB_WEBVIEW_ANDROID_JAVA_JNI_ANDROID_ASSET_HELPER_JNI_H
17+#define PLUGINS_WEB_WEBVIEW_ANDROID_JAVA_JNI_ANDROID_ASSET_HELPER_JNI_H
18+ 
19+#include <jni.h>
20+#include <string>
21+ 
22+namespace OHOS::Plugin {
23+class AndroidAssetHelperJni final {
24+public:
25+ AndroidAssetHelperJni() = delete;
26+ ~AndroidAssetHelperJni() = delete;
27+ static bool Register(void* env);
28+ static void NativeInit(JNIEnv* env, jobject jobj);
29+ static bool ExistsVirtualAsset(const std::string& url);
30+};
31+} // namespace OHOS::Plugin
32+ 
33+#endif
@@ -0,0 +1,596 @@
1+/*
2+ * Copyright (c) 2025 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 "plugins/web/webview/android/java/jni/web_scheme_handler_jni.h"
17+ 
18+#include <jni.h>
19+#include <unordered_map>
20+ 
21+#include "inner_api/plugin_utils_inner.h"
22+#include "log.h"
23+#include "plugin_utils.h"
24+ 
25+namespace OHOS::Plugin {
26+static constexpr const int PARAM_COUNT_ZERO = 0;
27+static constexpr const int PARAM_COUNT_ONE = 1;
28+static constexpr const int PARAM_COUNT_TWO = 2;
29+static constexpr const int PARAM_COUNT_THREE = 3;
30+static constexpr const int PARAM_COUNT_FOUR = 4;
31+std::map<std::string, ArkWeb_SchemeHandler*> WebSchemeHandlerJni::g_schemeRequestHandlerMap_;
32+ArkWeb_SchemeHandler* WebSchemeHandlerJni::handler_ = nullptr;
33+ArkWeb_ResourceRequest* WebSchemeHandlerJni::resourceRequest_ = nullptr;
34+bool WebSchemeHandlerJni::isIntercept_ = false;
35+namespace {
36+const char WEB_WEBVIEW_CLASS_NAME[] = "ohos/ace/adapter/capability/web/AceWebPluginBase";
37+static const JNINativeMethod METHODS[] = {
38+ { "nativeInitSchemeHandler", "()V", reinterpret_cast<void*>(WebSchemeHandlerJni::NativeInit) },
39+ { "onSchemeHandlerRequestStart", "(Ljava/lang/String;Ljava/lang/Object;)Z",
40+ reinterpret_cast<void*>(WebSchemeHandlerJni::OnSchemeHandlerRequestStart) },
41+ { "onSchemeHandlerRequestStop", "(Ljava/lang/String;Ljava/lang/Object;)V",
42+ reinterpret_cast<void*>(WebSchemeHandlerJni::OnSchemeHandlerRequestStop) },
43+};
44+ 
45+struct {
46+ jobject globalRef;
47+} g_webWebviewClass;
liulong
liulongliulong2025年10月15日

g_webWebviewClass这个类需要么?

likedislike
quguiren
2025年10月15日 评论:
48+} // namespace
49+ 
50+bool WebSchemeHandlerJni::Register(void* env)
51+{
52+ auto* jniEnv = static_cast<JNIEnv*>(env);
53+ CHECK_NULL_RETURN(jniEnv, false);
54+ jclass cls = jniEnv->FindClass(WEB_WEBVIEW_CLASS_NAME);
55+ CHECK_NULL_RETURN(cls, false);
56+ bool ret = jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0])) == 0;
57+ jniEnv->DeleteLocalRef(cls);
58+ if (!ret) {
59+ LOGE("WebSchemeHandlerJni JNI: RegisterNatives fail.");
60+ return false;
61+ }
62+ return true;
63+}
64+ 
65+void WebSchemeHandlerJni::NativeInit(JNIEnv* env, jobject jobj)
66+{
67+ CHECK_NULL_VOID(env);
68+}
69+ 
70+std::string WebSchemeHandlerJni::GetUTFString(JNIEnv* env, jstring jstr)
71+{
72+ CHECK_NULL_RETURN(env, "");
73+ CHECK_NULL_RETURN(jstr, "");
74+ const char* pString = env->GetStringUTFChars(jstr, nullptr);
75+ CHECK_NULL_RETURN(pString, "");
76+ std::string str(pString);
77+ env->ReleaseStringUTFChars(jstr, pString);
78+ return str;
79+}
80+ 
81+bool WebSchemeHandlerJni::OnSchemeHandlerRequestStart(
82+ JNIEnv* env, jclass jcls, jstring scheme, jobject schemeRequestHandler)
83+{
84+ CHECK_NULL_RETURN(env, false);
85+ CHECK_NULL_RETURN(scheme, false);
86+ std::string strScheme = WebSchemeHandlerJni::GetUTFString(env, scheme);
87+ auto it = g_schemeRequestHandlerMap_.find(strScheme);
88+ if (it == g_schemeRequestHandlerMap_.end()) {
89+ LOGE("WebSchemeHandlerJni::OnSchemeHandlerRequestStart: No handler found for scheme %{public}s",
90+ strScheme.c_str());
91+ return false;
92+ }
93+ 
94+ handler_ = it->second;
95+ CHECK_NULL_RETURN(handler_, false);
96+ bool intercept = false;
97+ if (handler_->on_request_start != nullptr) {
98+ resourceRequest_ = CreateArkResourceRequest(env, schemeRequestHandler);
99+ CHECK_NULL_RETURN(resourceRequest_, false);
100+ ArkWeb_ResourceHandler* resourceHandler = new (std::nothrow) ArkWeb_ResourceHandler(env, schemeRequestHandler);
101+ CHECK_NULL_RETURN(resourceHandler, false);
102+ handler_->on_request_start(handler_, resourceRequest_, resourceHandler, &intercept);
103+ SetIsIntercept(intercept);
104+ DestroyArkResourceRequest(resourceRequest_);
105+ delete resourceHandler;
106+ resourceHandler = nullptr;
107+ }
108+ return intercept;
109+}
110+ 
111+void WebSchemeHandlerJni::OnSchemeHandlerRequestStop(
112+ JNIEnv* env, jclass jcls, jstring scheme, jobject schemeRequestHandler)
113+{
114+ CHECK_NULL_VOID(env);
115+ CHECK_NULL_VOID(scheme);
116+ std::string strScheme = WebSchemeHandlerJni::GetUTFString(env, scheme);
117+ auto it = g_schemeRequestHandlerMap_.find(strScheme);
118+ if (it == g_schemeRequestHandlerMap_.end()) {
119+ LOGE("WebSchemeHandlerJni::OnSchemeHandlerRequestStop: No handler found for scheme %{public}s",
120+ strScheme.c_str());
121+ return;
122+ }
123+ 
124+ handler_ = it->second;
125+ CHECK_NULL_VOID(handler_);
126+ if (handler_->on_request_stop != nullptr) {
127+ resourceRequest_ = CreateArkResourceRequest(env, schemeRequestHandler);
128+ CHECK_NULL_VOID(resourceRequest_);
129+ handler_->on_request_stop(handler_, resourceRequest_);
130+ DestroyArkResourceRequest(resourceRequest_);
131+ }
132+}
133+ 
134+template<typename T>
135+static bool IsNullAndRelease(T obj, ArkWeb_ResourceRequest*& request)
136+{
137+ if (obj == nullptr) {
138+ if (request != nullptr) {
139+ delete request;
140+ request = nullptr;
141+ }
142+ return true;
143+ }
144+ return false;
145+}
146+ 
147+bool WebSchemeHandlerJni::GetStringFromJava(JNIEnv* env, jclass clazz, jobject jobj, ArkWeb_ResourceRequest*& request,
148+ const char* methodName, std::string& outStr)
149+{
150+ jmethodID methodId = env->GetMethodID(clazz, methodName, "()Ljava/lang/String;");
151+ if (IsNullAndRelease(methodId, request)) {
152+ return false;
153+ }
154+ jstring jstr = static_cast<jstring>(env->CallObjectMethod(jobj, methodId));
155+ if (IsNullAndRelease(jstr, request)) {
156+ return false;
157+ }
158+ outStr = WebSchemeHandlerJni::GetUTFString(env, jstr);
159+ env->DeleteLocalRef(jstr);
160+ return true;
161+}
162+ 
163+bool WebSchemeHandlerJni::GetBooleanFromJava(JNIEnv* env, jclass clazz, jobject jobj, ArkWeb_ResourceRequest*& request,
164+ const char* methodName, bool& outBool)
165+{
166+ jmethodID methodId = env->GetMethodID(clazz, methodName, "()Z");
167+ if (IsNullAndRelease(methodId, request)) {
168+ return false;
169+ }
170+ outBool = static_cast<bool>(env->CallBooleanMethod(jobj, methodId));
171+ return true;
172+}
173+ 
174+ArkWeb_ResourceRequest* WebSchemeHandlerJni::CreateArkResourceRequest(JNIEnv* env, jobject jRequest)
175+{
176+ CHECK_NULL_RETURN(env, nullptr);
177+ ArkWeb_ResourceRequest* request = new (std::nothrow) ArkWeb_ResourceRequest();
178+ CHECK_NULL_RETURN(request, nullptr);
179+ jclass schemeRequestClass = env->GetObjectClass(jRequest);
180+ if (IsNullAndRelease(schemeRequestClass, request)) {
181+ return nullptr;
L
Lliuxiao_3102025年10月13日

return 前要释放request,不然泄漏

likedislike
liuxiao_310
2025年10月13日 评论:
quguiren
2025年10月14日 评论:
182+ }
183+ if (!GetStringFromJava(env, schemeRequestClass, jRequest, request, "getRequestUrl", request->url_)) {
184+ return nullptr;
185+ }
186+ if (!GetStringFromJava(env, schemeRequestClass, jRequest, request, "getMethod", request->method_)) {
187+ return nullptr;
188+ }
189+ if (!GetBooleanFromJava(env, schemeRequestClass, jRequest, request, "isRequestGesture", request->hasGesture_)) {
190+ return nullptr;
191+ }
192+ if (!GetBooleanFromJava(env, schemeRequestClass, jRequest, request, "isMainFrame", request->isMainFrame_)) {
193+ return nullptr;
194+ }
195+ if (!GetBooleanFromJava(env, schemeRequestClass, jRequest, request, "isRedirect", request->isRedirect_)) {
196+ return nullptr;
197+ }
198+ jmethodID getRequestHeaderId = env->GetMethodID(schemeRequestClass, "getRequestHeader", "()Ljava/util/Map;");
199+ if (IsNullAndRelease(getRequestHeaderId, request)) {
200+ return nullptr;
201+ }
202+ jobject jHeadersMap = env->CallObjectMethod(jRequest, getRequestHeaderId);
203+ if (IsNullAndRelease(jHeadersMap, request)) {
204+ return nullptr;
205+ }
206+ std::map<std::string, std::string> headers = GetRequestHeader(env, jHeadersMap);
207+ request->headerList_ = WebHeaderList(headers.begin(), headers.end());
208+ if (env->ExceptionCheck()) {
209+ env->ExceptionDescribe();
210+ env->ExceptionClear();
211+ }
212+ return request;
213+}
214+ 
215+void WebSchemeHandlerJni::DestroyArkResourceRequest(ArkWeb_ResourceRequest* request)
216+{
217+ if (request != nullptr) {
218+ delete request;
219+ request = nullptr;
220+ }
221+}
222+ 
223+void WebSchemeHandlerJni::IterateAndFillHeaders(JNIEnv* env, jobject iterator, const jmethodID* methodIds,
224+ std::map<std::string, std::string>& headers)
225+{
226+ while (env->CallBooleanMethod(iterator, methodIds[PARAM_COUNT_ZERO])) {
227+ jobject entry = env->CallObjectMethod(iterator, methodIds[PARAM_COUNT_ONE]);
228+ jobject key = env->CallObjectMethod(entry, methodIds[PARAM_COUNT_TWO]);
229+ jobject value = env->CallObjectMethod(entry, methodIds[PARAM_COUNT_THREE]);
230+ if (key != nullptr && value != nullptr) {
231+ const char* keyStr = env->GetStringUTFChars(static_cast<jstring>(key), nullptr);
jinpeng0804
jinpeng0804jinpeng08042025年10月13日

建议在转换前使用使用 env->IsInstanceOf等方式检查对象类型,避免导致GetStringUTFChars调用时崩溃

likedislike
quguiren
2025年10月14日 评论:
232+ const char* valueStr = env->GetStringUTFChars(static_cast<jstring>(value), nullptr);
233+ if (keyStr != nullptr && valueStr != nullptr) {
234+ headers[keyStr] = valueStr;
235+ }
236+ if (keyStr != nullptr) {
237+ env->ReleaseStringUTFChars(static_cast<jstring>(key), keyStr);
238+ }
239+ if (valueStr != nullptr) {
240+ env->ReleaseStringUTFChars(static_cast<jstring>(value), valueStr);
241+ }
242+ }
243+ env->DeleteLocalRef(key);
244+ env->DeleteLocalRef(value);
245+ env->DeleteLocalRef(entry);
246+ }
247+}
248+ 
249+bool WebSchemeHandlerJni::GetIteratorAndEntryMethodIds(
250+ JNIEnv* env, jclass iteratorClass, jclass entryClass, jmethodID* methodIds)
251+{
252+ if (methodIds == nullptr) {
253+ return false;
254+ }
255+ methodIds[PARAM_COUNT_ZERO] = env->GetMethodID(iteratorClass, "hasNext", "()Z");
liulong
liulongliulong2025年10月15日

数组下标访问前,先进行数组大小判断。

likedislike
quguiren
2025年10月15日 评论:
256+ methodIds[PARAM_COUNT_ONE] = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
257+ methodIds[PARAM_COUNT_TWO] = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
258+ methodIds[PARAM_COUNT_THREE] = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
259+ return (methodIds[PARAM_COUNT_ZERO] != nullptr) && (methodIds[PARAM_COUNT_ONE] != nullptr) &&
260+ (methodIds[PARAM_COUNT_TWO] != nullptr) && (methodIds[PARAM_COUNT_THREE] != nullptr);
261+}
262+ 
263+std::map<std::string, std::string> WebSchemeHandlerJni::GetRequestHeader(JNIEnv* env, jobject jHeadersMap)
264+{
265+ std::map<std::string, std::string> headers;
266+ CHECK_NULL_RETURN(env, headers);
267+ CHECK_NULL_RETURN(jHeadersMap, headers);
268+ jobject iterator = WebSchemeHandlerJni::GetHeaderIterator(env, jHeadersMap);
269+ CHECK_NULL_RETURN(iterator, headers);
270+ 
271+ jclass iteratorClass = env->FindClass("java/util/Iterator");
272+ jclass entryClass = env->FindClass("java/util/Map$Entry");
273+ if (iteratorClass == nullptr || entryClass == nullptr) {
274+ env->DeleteLocalRef(iterator);
275+ env->DeleteLocalRef(iteratorClass);
276+ env->DeleteLocalRef(entryClass);
277+ return headers;
278+ }
279+ 
280+ jmethodID methodIds[PARAM_COUNT_FOUR] = { nullptr };
281+ if (GetIteratorAndEntryMethodIds(env, iteratorClass, entryClass, methodIds)) {
282+ IterateAndFillHeaders(env, iterator, methodIds, headers);
283+ }
284+ 
285+ if (env->ExceptionCheck()) {
286+ env->ExceptionDescribe();
287+ env->ExceptionClear();
288+ }
289+ env->DeleteLocalRef(iterator);
290+ env->DeleteLocalRef(iteratorClass);
291+ env->DeleteLocalRef(entryClass);
292+ return headers;
293+}
294+ 
295+jobject WebSchemeHandlerJni::GetHeaderIterator(JNIEnv* env, jobject jHeadersMap)
296+{
297+ CHECK_NULL_RETURN(env, nullptr);
298+ CHECK_NULL_RETURN(jHeadersMap, nullptr);
299+ jclass mapClass = env->FindClass("java/util/Map");
300+ CHECK_NULL_RETURN(mapClass, nullptr);
301+ jmethodID entrySetId = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
302+ if (entrySetId == nullptr) {
303+ env->DeleteLocalRef(mapClass);
304+ return nullptr;
305+ }
306+ jobject entrySet = env->CallObjectMethod(jHeadersMap, entrySetId);
307+ if (entrySet == nullptr) {
308+ env->DeleteLocalRef(mapClass);
309+ return nullptr;
310+ }
311+ 
312+ jclass setClass = env->FindClass("java/util/Set");
313+ if (setClass == nullptr) {
314+ env->DeleteLocalRef(entrySet);
315+ env->DeleteLocalRef(mapClass);
316+ return nullptr;
317+ }
318+ jmethodID iteratorId = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
319+ if (iteratorId == nullptr) {
320+ env->DeleteLocalRef(entrySet);
321+ env->DeleteLocalRef(mapClass);
322+ env->DeleteLocalRef(setClass);
323+ return nullptr;
324+ }
325+ jobject iterator = env->CallObjectMethod(entrySet, iteratorId);
326+ env->DeleteLocalRef(entrySet);
327+ env->DeleteLocalRef(mapClass);
328+ env->DeleteLocalRef(setClass);
329+ return iterator;
330+}
331+ 
332+ArkWeb_SchemeHandler* WebSchemeHandlerJni::CreateArkSchemeHandler()
333+{
334+ ArkWeb_SchemeHandler* handler = new (std::nothrow) ArkWeb_SchemeHandler();
335+ return handler;
336+}
337+ 
338+void WebSchemeHandlerJni::DeleteArkSchemeHandler(ArkWeb_SchemeHandler* handler)
339+{
340+ if (handler != nullptr) {
341+ delete handler;
342+ handler = nullptr;
343+ }
344+}
345+ 
346+void WebSchemeHandlerJni::SetOnRequestStart(ArkWeb_SchemeHandler* handler, ArkWeb_OnRequestStart callback)
347+{
348+ if (handler != nullptr) {
349+ handler->on_request_start = callback;
350+ }
351+}
352+ 
353+void WebSchemeHandlerJni::SetOnRequestStop(ArkWeb_SchemeHandler* handler, ArkWeb_OnRequestStop callback)
354+{
355+ if (handler != nullptr) {
356+ handler->on_request_stop = callback;
357+ }
358+}
359+ 
360+void WebSchemeHandlerJni::InsertSchemeRequestHandler(std::string& scheme, ArkWeb_SchemeHandler* handler)
361+{
362+ if (!scheme.empty() && handler != nullptr) {
363+ g_schemeRequestHandlerMap_[scheme] = handler;
364+ }
365+}
366+ 
367+void WebSchemeHandlerJni::ClearSchemeRequestHandler()
368+{
369+ g_schemeRequestHandlerMap_.clear();
370+}
371+ 
372+bool WebSchemeHandlerJni::GetIsIntercept()
373+{
374+ return isIntercept_;
375+}
376+ 
377+void WebSchemeHandlerJni::SetIsIntercept(bool intercept)
378+{
379+ isIntercept_ = intercept;
380+}
381+ 
382+ErrCode ArkWeb_ResourceHandler::SetResponseUrl(const std::string& url)
383+{
384+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
385+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
386+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
387+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
388+ jmethodID setResponseUrlMethod = env_->GetMethodID(schemeRequestClass, "setResponseUrl", "(Ljava/lang/String;)V");
389+ CHECK_NULL_RETURN(setResponseUrlMethod, NWebError::PARAM_CHECK_ERROR);
390+ jstring jsUrl = env_->NewStringUTF(url.c_str());
391+ CHECK_NULL_RETURN(jsUrl, NWebError::PARAM_CHECK_ERROR);
392+ env_->CallVoidMethod(schemeRequestHandler_, setResponseUrlMethod, jsUrl);
393+ ErrCode ret = NWebError::NO_ERROR;
394+ if (env_->ExceptionCheck()) {
395+ env_->ExceptionDescribe();
396+ env_->ExceptionClear();
397+ ret = NWebError::PARAM_CHECK_ERROR;
398+ }
399+ env_->DeleteLocalRef(jsUrl);
400+ return ret;
401+}
402+ 
403+ErrCode ArkWeb_ResourceHandler::SetResponseErrcode(ArkWeb_NetError errorCode, const std::string& errorDescription)
404+{
405+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
406+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
407+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
408+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
409+ jmethodID setResponseErrorMethod =
410+ env_->GetMethodID(schemeRequestClass, "setResponseFail", "(ILjava/lang/String;)V");
411+ CHECK_NULL_RETURN(setResponseErrorMethod, NWebError::PARAM_CHECK_ERROR);
412+ jstring jsErrorDescription = env_->NewStringUTF(errorDescription.c_str());
413+ CHECK_NULL_RETURN(jsErrorDescription, NWebError::PARAM_CHECK_ERROR);
414+ env_->CallVoidMethod(
415+ schemeRequestHandler_, setResponseErrorMethod, static_cast<jint>(errorCode), jsErrorDescription);
416+ ErrCode ret = NWebError::NO_ERROR;
417+ if (env_->ExceptionCheck()) {
418+ env_->ExceptionDescribe();
419+ env_->ExceptionClear();
420+ ret = NWebError::PARAM_CHECK_ERROR;
421+ }
422+ env_->DeleteLocalRef(jsErrorDescription);
423+ return ret;
424+}
425+ 
426+ErrCode ArkWeb_ResourceHandler::DidReceiveResponse(const ArkWeb_Response* response)
427+{
428+ CHECK_NULL_RETURN(response, NWebError::PARAM_CHECK_ERROR);
429+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
430+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
431+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
432+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
433+ if (SetResponseUrl(response->url_) != NWebError::NO_ERROR) {
434+ return NWebError::PARAM_CHECK_ERROR;
435+ }
436+ 
437+ if (SetResponseErrcode(static_cast<ArkWeb_NetError>(response->errorCode_), response->errorDescription_) !=
438+ NWebError::NO_ERROR) {
439+ return NWebError::PARAM_CHECK_ERROR;
440+ }
441+ jmethodID setResponseMethod = env_->GetMethodID(schemeRequestClass, "setResponse",
442+ "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/HashMap;Ljava/lang/String;)V");
443+ CHECK_NULL_RETURN(setResponseMethod, NWebError::PARAM_CHECK_ERROR);
444+ jstring jsMimeType = env_->NewStringUTF(response->mimeType_.c_str());
445+ CHECK_NULL_RETURN(jsMimeType, NWebError::PARAM_CHECK_ERROR);
446+ jstring jsEncoding = env_->NewStringUTF(response->encoding_.c_str());
447+ if (jsEncoding == nullptr) {
448+ env_->DeleteLocalRef(jsMimeType);
449+ return NWebError::PARAM_CHECK_ERROR;
450+ }
451+ jstring jsReasonPhrase = env_->NewStringUTF(response->statusText_.c_str());
452+ jstring jsData = env_->NewStringUTF(response->data_.c_str());
453+ if (jsReasonPhrase == nullptr || jsData == nullptr) {
454+ env_->DeleteLocalRef(jsMimeType);
455+ env_->DeleteLocalRef(jsEncoding);
456+ if (jsReasonPhrase != nullptr) {
457+ env_->DeleteLocalRef(jsReasonPhrase);
458+ }
459+ return NWebError::PARAM_CHECK_ERROR;
460+ }
461+ jobject headers = ConvertMapToJavaMap(env_, response->headers_);
liulong
liulongliulong2025年10月15日

headers 也需要通过DeleteLocalRef释放,否则有内存泄漏

likedislike
quguiren
2025年10月15日 评论:
462+ env_->CallVoidMethod(schemeRequestHandler_, setResponseMethod, jsMimeType, jsEncoding, response->status_,
463+ jsReasonPhrase, headers, jsData);
464+ env_->DeleteLocalRef(jsMimeType);
465+ env_->DeleteLocalRef(jsEncoding);
466+ env_->DeleteLocalRef(jsReasonPhrase);
467+ env_->DeleteLocalRef(jsData);
468+ env_->DeleteLocalRef(headers);
469+ if (env_->ExceptionCheck()) {
470+ env_->ExceptionDescribe();
471+ env_->ExceptionClear();
472+ }
473+ return NWebError::NO_ERROR;
474+}
475+ 
476+jobject ArkWeb_ResourceHandler::ConvertMapToJavaMap(
477+ JNIEnv* env, const std::unordered_map<std::string, std::string>& headersMap)
478+{
479+ CHECK_NULL_RETURN(env, nullptr);
480+ jclass hashMapClass = env->FindClass("java/util/HashMap");
481+ CHECK_NULL_RETURN(hashMapClass, nullptr);
482+ jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
483+ jmethodID hashMapPut =
484+ env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
485+ if (hashMapConstructor == nullptr || hashMapPut == nullptr) {
486+ env->DeleteLocalRef(hashMapClass);
487+ return nullptr;
488+ }
489+ jobject hashMap = env->NewObject(hashMapClass, hashMapConstructor);
490+ for (const auto& entry : headersMap) {
491+ jstring key = env->NewStringUTF(entry.first.c_str());
492+ jstring value = env->NewStringUTF(entry.second.c_str());
493+ env->CallObjectMethod(hashMap, hashMapPut, key, value);
494+ env->DeleteLocalRef(key);
495+ env->DeleteLocalRef(value);
496+ }
497+ env->DeleteLocalRef(hashMapClass);
498+ return hashMap;
499+}
500+ 
501+ErrCode ArkWeb_ResourceHandler::DidReceiveData(const uint8_t* buffer, int64_t buflen)
502+{
503+ CHECK_NULL_RETURN(buffer, NWebError::PARAM_CHECK_ERROR);
504+ CHECK_NULL_RETURN(buflen > 0, NWebError::PARAM_CHECK_ERROR);
505+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
506+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
507+ std::string data(reinterpret_cast<const char*>(buffer), static_cast<size_t>(buflen));
508+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
509+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
510+ 
511+ jmethodID setResponseDataMethod = env_->GetMethodID(schemeRequestClass, "setResponseData", "(Ljava/lang/String;)V");
512+ CHECK_NULL_RETURN(setResponseDataMethod, NWebError::PARAM_CHECK_ERROR);
513+ jstring jsResponseData = env_->NewStringUTF(data.c_str());
514+ CHECK_NULL_RETURN(jsResponseData, NWebError::PARAM_CHECK_ERROR);
515+ env_->CallVoidMethod(schemeRequestHandler_, setResponseDataMethod, jsResponseData);
516+ ErrCode ret = NWebError::NO_ERROR;
517+ if (env_->ExceptionCheck()) {
518+ env_->ExceptionDescribe();
519+ env_->ExceptionClear();
520+ ret = NWebError::PARAM_CHECK_ERROR;
521+ }
522+ env_->DeleteLocalRef(jsResponseData);
523+ return ret;
524+}
525+ 
526+ErrCode ArkWeb_ResourceHandler::DidFinish()
527+{
528+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
529+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
530+ 
531+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
532+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
533+ 
534+ jmethodID setResponseFinishMethod = env_->GetMethodID(schemeRequestClass, "setResponseFinish", "(Z)V");
535+ CHECK_NULL_RETURN(setResponseFinishMethod, NWebError::PARAM_CHECK_ERROR);
536+ SetFinishFlag();
537+ env_->CallVoidMethod(schemeRequestHandler_, setResponseFinishMethod, isFinished_);
538+ ErrCode ret = NWebError::NO_ERROR;
539+ if (env_->ExceptionCheck()) {
540+ env_->ExceptionDescribe();
541+ env_->ExceptionClear();
542+ ret = NWebError::PARAM_CHECK_ERROR;
543+ }
544+ return ret;
545+}
546+ 
547+ErrCode ArkWeb_ResourceHandler::DidFailWithError(
548+ ArkWeb_NetError errorCode, const std::string& errorDescription, bool completeIfNoResponse)
549+{
550+ CHECK_NULL_RETURN(env_, NWebError::PARAM_CHECK_ERROR);
551+ CHECK_NULL_RETURN(schemeRequestHandler_, NWebError::PARAM_CHECK_ERROR);
552+ 
553+ jclass schemeRequestClass = env_->GetObjectClass(schemeRequestHandler_);
554+ CHECK_NULL_RETURN(schemeRequestClass, NWebError::PARAM_CHECK_ERROR);
555+ 
556+ jmethodID didFailMethod = env_->GetMethodID(schemeRequestClass, "didFail", "(ILjava/lang/String;Z)V");
557+ if (didFailMethod == nullptr) {
558+ LOGE("ArkWeb_ResourceHandler::DidFailWithError get didFail method failed");
559+ return NWebError::PARAM_CHECK_ERROR;
560+ }
561+ jstring jsErrorDescription = env_->NewStringUTF(errorDescription.c_str());
562+ CHECK_NULL_RETURN(jsErrorDescription, NWebError::PARAM_CHECK_ERROR);
563+ env_->CallVoidMethod(schemeRequestHandler_, didFailMethod, static_cast<int32_t>(errorCode), jsErrorDescription,
564+ completeIfNoResponse);
565+ 
566+ ErrCode ret = NWebError::NO_ERROR;
567+ if (env_->ExceptionCheck()) {
568+ env_->ExceptionDescribe();
569+ env_->ExceptionClear();
570+ ret = NWebError::PARAM_CHECK_ERROR;
571+ }
572+ env_->DeleteLocalRef(jsErrorDescription);
573+ return ret;
574+}
575+ 
576+ArkWeb_ResourceHandler::~ArkWeb_ResourceHandler()
577+{
578+ if (schemeRequestHandler_ != nullptr && env_ != nullptr) {
579+ env_->DeleteLocalRef(schemeRequestHandler_);
580+ schemeRequestHandler_ = nullptr;
581+ }
582+ if (handler_ != nullptr) {
583+ delete handler_;
584+ handler_ = nullptr;
585+ }
586+}
587+ 
588+void ArkWeb_ResourceHandler::DestroyArkWebResourceHandler()
589+{
590+ isFinished_ = false;
591+ if (schemeRequestHandler_ != nullptr && env_ != nullptr) {
592+ env_->DeleteLocalRef(schemeRequestHandler_);
593+ schemeRequestHandler_ = nullptr;
594+ }
595+}
596+} // namespace OHOS::Plugin
@@ -0,0 +1,169 @@
1+/*
2+ * Copyright (c) 2025 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+#ifndef PLUGINS_WEB_WEBVIEW_ANDROID_JAVA_JNI_WEB_SCHEME_HANDLER_JNI_H
17+#define PLUGINS_WEB_WEBVIEW_ANDROID_JAVA_JNI_WEB_SCHEME_HANDLER_JNI_H
18+ 
19+#include <jni.h>
20+#include <map>
21+#include <string>
22+#include <unordered_map>
23+#include <utility>
24+#include <vector>
25+ 
26+#include "arkweb_net_error_list.h"
27+#include "web_errors.h"
28+ 
29+namespace OHOS::Plugin {
30+struct ArkWeb_SchemeHandler;
31+struct ArkWeb_Response;
32+class ArkWeb_ResourceHandler;
33+typedef void (*ArkWeb_OnRequestStart)(struct ArkWeb_SchemeHandler* schemeHandler,
34+ struct ArkWeb_ResourceRequest* resourceRequest, ArkWeb_ResourceHandler* resourceHandler, bool* intercept);
35+ 
36+typedef void (*ArkWeb_OnRequestStop)(
37+ struct ArkWeb_SchemeHandler* schemeHandler, struct ArkWeb_ResourceRequest* resourceRequest);
38+using WebHeaderList = std::vector<std::pair<std::string, std::string>>;
39+ 
40+class WebSchemeHandlerJni final {
41+public:
42+ WebSchemeHandlerJni() = delete;
43+ ~WebSchemeHandlerJni() = delete;
44+ static bool Register(void* env);
45+ static void NativeInit(JNIEnv* env, jobject jobj);
46+ static bool OnSchemeHandlerRequestStart(JNIEnv* env, jclass jcls, jstring scheme, jobject schemeRequestHandler);
47+ static void OnSchemeHandlerRequestStop(JNIEnv* env, jclass jcls, jstring scheme, jobject schemeRequestHandler);
48+ static ArkWeb_SchemeHandler* CreateArkSchemeHandler();
49+ static void DeleteArkSchemeHandler(ArkWeb_SchemeHandler* handler);
50+ static void SetOnRequestStart(ArkWeb_SchemeHandler* handler, ArkWeb_OnRequestStart callback);
51+ static void SetOnRequestStop(ArkWeb_SchemeHandler* handler, ArkWeb_OnRequestStop callback);
52+ static void InsertSchemeRequestHandler(std::string& scheme, ArkWeb_SchemeHandler* handler);
53+ static void ClearSchemeRequestHandler();
54+ static bool GetIsIntercept();
55+ static void SetIsIntercept(bool intercept);
56+ 
57+private:
58+ static ArkWeb_ResourceRequest* CreateArkResourceRequest(JNIEnv* env, jobject jRequest);
59+ static void DestroyArkResourceRequest(ArkWeb_ResourceRequest* request);
60+ static std::map<std::string, std::string> GetRequestHeader(JNIEnv* env, jobject javaObject);
61+ static std::string GetUTFString(JNIEnv* env, jstring jstr);
62+ static bool GetBooleanFromJava(JNIEnv* env, jclass clazz, jobject jobj, ArkWeb_ResourceRequest*& request,
63+ const char* methodName, bool& outBool);
64+ static bool GetStringFromJava(JNIEnv* env, jclass clazz, jobject jobj, ArkWeb_ResourceRequest*& request,
65+ const char* methodName, std::string& outStr);
66+ static jobject GetHeaderIterator(JNIEnv* env, jobject jHeadersMap);
67+ static void IterateAndFillHeaders(JNIEnv* env, jobject iterator, const jmethodID* methodIds,
68+ std::map<std::string, std::string>& headers);
69+ static bool GetIteratorAndEntryMethodIds(
70+ JNIEnv* env, jclass iteratorClass, jclass entryClass, jmethodID* methodIds);
71+ 
72+public:
73+ static ArkWeb_SchemeHandler* handler_;
74+ static ArkWeb_ResourceRequest* resourceRequest_;
75+private:
76+ static std::map<std::string, ArkWeb_SchemeHandler*> g_schemeRequestHandlerMap_;
77+ static bool isIntercept_;
78+};
79+ 
80+struct ArkWeb_ResourceRequest {
81+public:
82+ ArkWeb_ResourceRequest() = default;
83+ ~ArkWeb_ResourceRequest()
84+ {
85+ url_ = "";
86+ method_ = "";
87+ referrer_ = "";
88+ isRedirect_ = false;
89+ isMainFrame_ = false;
90+ hasGesture_ = false;
91+ headerList_.clear();
92+ requestResourceType_ = -1;
93+ frameUrl_ = "";
94+ };
95+ 
96+public:
97+ std::string url_ = "";
98+ std::string method_ = "";
99+ std::string referrer_ = "";
100+ bool isRedirect_ = false;
101+ bool isMainFrame_ = false;
102+ bool hasGesture_ = false;
103+ WebHeaderList headerList_;
104+ int32_t requestResourceType_ = -1;
105+ std::string frameUrl_ = "";
106+};
107+ 
108+class ArkWeb_ResourceHandler {
109+public:
110+ ArkWeb_ResourceHandler(JNIEnv* env, jobject schemeRequestHandler)
111+ : env_(env), schemeRequestHandler_(schemeRequestHandler)
112+ {}
113+ ~ArkWeb_ResourceHandler();
114+ 
115+ ErrCode DidReceiveResponse(const ArkWeb_Response* response);
116+ ErrCode DidReceiveData(const uint8_t* buffer, int64_t buflen);
117+ ErrCode DidFinish();
118+ ErrCode DidFailWithError(ArkWeb_NetError errorCode, const std::string& errorDescription, bool completeIfNoResponse);
119+ void DestroyArkWebResourceHandler();
120+ void SetFinishFlag()
121+ {
122+ isFinished_ = true;
123+ }
124+ 
125+private:
126+ jobject ConvertMapToJavaMap(JNIEnv* env, const std::unordered_map<std::string, std::string>& headersMap);
127+ ErrCode SetResponseUrl(const std::string& url);
128+ ErrCode SetResponseErrcode(ArkWeb_NetError errorCode, const std::string& errorDescription);
129+ 
130+private:
131+ bool isFinished_ = false;
132+ JNIEnv* env_ = nullptr;
133+ jobject schemeRequestHandler_ = nullptr;
134+ ArkWeb_ResourceHandler* handler_ = nullptr;
135+};
136+ 
137+struct ArkWeb_Response {
138+public:
139+ ArkWeb_Response() = default;
140+ ~ArkWeb_Response()
141+ {
142+ url_ = "";
143+ status_ = 0;
144+ statusText_ = "";
145+ mimeType_ = "";
146+ encoding_ = "";
147+ data_ = "";
148+ headers_.clear();
149+ errorCode_ = 0;
150+ errorDescription_ = "";
151+ }
152+ 
153+ std::string url_ = "";
154+ int32_t status_ = 0;
155+ std::string statusText_ = "";
156+ std::string mimeType_ = "";
157+ std::string encoding_ = "";
158+ std::string data_ = "";
159+ std::unordered_map<std::string, std::string> headers_;
160+ int32_t errorCode_ = 0;
161+ std::string errorDescription_ = "";
162+};
163+ 
164+struct ArkWeb_SchemeHandler {
165+ ArkWeb_OnRequestStart on_request_start;
166+ ArkWeb_OnRequestStop on_request_stop;
167+};
168+} // namespace OHOS::Plugin
169+#endif // PLUGINS_WEB_WEBVIEW_ANDROID_JAVA_JNI_WEB_SCHEME_HANDLER_JNI_H
@@ -15,6 +15,7 @@
15 15 
16#include "webview_controller_android.h"16#include "webview_controller_android.h"
17 17 
18+#include "inner_api/plugin_utils_inner.h"
18#include "log.h"19#include "log.h"
19#include "plugins/web/webview/android/java/jni/webview_controller_jni.h"20#include "plugins/web/webview/android/java/jni/webview_controller_jni.h"
20 21 
@@ -217,4 +218,26 @@ void WebviewControllerAndroid::DeleteJavaScriptRegister(const std::string& objNa
217{218{
218 WebviewControllerJni::DeleteJavaScriptRegister(webId_, objName);219 WebviewControllerJni::DeleteJavaScriptRegister(webId_, objName);
219}220}
221+ 
222+bool WebviewControllerAndroid::SetWebSchemeHandler(const char* scheme, WebSchemeHandler* handler)
223+{
224+ CHECK_NULL_RETURN(scheme, false);
225+ CHECK_NULL_RETURN(handler, false);
226+ std::string schemeStr(scheme);
227+ auto arkHandler = WebSchemeHandler::GetArkWebSchemeHandler(handler);
228+ WebSchemeHandlerJni::InsertSchemeRequestHandler(schemeStr, arkHandler);
229+ return WebviewControllerJni::SetWebSchemeHandler(webId_, schemeStr);
230+}
231+ 
232+bool WebviewControllerAndroid::ClearWebSchemeHandler()
233+{
234+ WebSchemeHandlerJni::ClearSchemeRequestHandler();
235+ WebviewControllerJni::ClearWebSchemeHandler(webId_);
236+ return true;
237+}
238+ 
239+std::string WebviewControllerAndroid::GetUserAgent()
240+{
241+ return WebviewControllerJni::GetUserAgent(webId_);
242+}
220}243}
@@ -62,6 +62,9 @@ public:
62 void StartDownload(const std::string& url) override;62 void StartDownload(const std::string& url) override;
63 void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) override;63 void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) override;
64 void DeleteJavaScriptRegister(const std::string& objName) override;64 void DeleteJavaScriptRegister(const std::string& objName) override;
65+ bool SetWebSchemeHandler(const char* scheme, WebSchemeHandler* handler) override;
66+ bool ClearWebSchemeHandler() override;
67+ std::string GetUserAgent() override;
65};68};
66}69}
67#endif70#endif
@@ -126,6 +126,12 @@ static const char METHOD_REGISTERJAVASCRIPTPROXY[] = "registerJavaScriptProxy";
126 126 
127static const char METHOD_DELETEJAVASCRIPTREGISTER[] = "deleteJavaScriptRegister";127static const char METHOD_DELETEJAVASCRIPTREGISTER[] = "deleteJavaScriptRegister";
128 128 
129+static const char METHOD_SET_WEB_SCHEME_HANDLER[] = "setWebSchemeHandler";
130+ 
131+static const char METHOD_CLEAR_WEB_SCHEME_HANDLER[] = "clearWebSchemeHandler";
132+ 
133+static const char METHOD_GET_USER_AGENT[] = "getUserAgent";
134+ 
129static const char SIGNATURE_LOADURL[] = "(JLjava/lang/String;Ljava/util/HashMap;)V";135static const char SIGNATURE_LOADURL[] = "(JLjava/lang/String;Ljava/util/HashMap;)V";
130 136 
131static const char SIGNATURE_LOADDATA[] = "(JLjava/util/HashMap;)V";137static const char SIGNATURE_LOADDATA[] = "(JLjava/util/HashMap;)V";
@@ -209,6 +215,12 @@ static const char SIGNATURE_REGISTERJAVASCRIPTPROXY[] =
209 215 
210static const char SIGNATURE_DELETEJAVASCRIPTREGISTER[] = "(JLjava/lang/String;)V";216static const char SIGNATURE_DELETEJAVASCRIPTREGISTER[] = "(JLjava/lang/String;)V";
211 217 
218+static const char SIGNATURE_SET_WEB_SCHEME_HANDLER[] = "(JLjava/lang/String;)Z";
219+ 
220+static const char SIGNATURE_CLEAR_WEB_SCHEME_HANDLER[] = "(J)V";
221+ 
222+static const char SIGNATURE_GET_USER_AGENT[] = "(J)Ljava/lang/String;";
223+ 
212bool _webDebuggingAccessInit = false;224bool _webDebuggingAccessInit = false;
213 225 
214struct {226struct {
@@ -253,6 +265,9 @@ struct {
253 jmethodID onWebMessagePortEventExt;265 jmethodID onWebMessagePortEventExt;
254 jmethodID registerJavaScriptProxy;266 jmethodID registerJavaScriptProxy;
255 jmethodID deleteJavaScriptRegister;267 jmethodID deleteJavaScriptRegister;
268+ jmethodID setWebSchemeHandler;
269+ jmethodID clearWebSchemeHandler;
270+ jmethodID getUserAgent;
256 jobject globalRef;271 jobject globalRef;
257} g_webWebviewClass;272} g_webWebviewClass;
258}273}
@@ -320,6 +335,11 @@ void WebviewControllerJni::NativeInit(JNIEnv* env, jobject jobj)
320 env->GetMethodID(cls, METHOD_REGISTERJAVASCRIPTPROXY, SIGNATURE_REGISTERJAVASCRIPTPROXY);335 env->GetMethodID(cls, METHOD_REGISTERJAVASCRIPTPROXY, SIGNATURE_REGISTERJAVASCRIPTPROXY);
321 g_webWebviewClass.deleteJavaScriptRegister =336 g_webWebviewClass.deleteJavaScriptRegister =
322 env->GetMethodID(cls, METHOD_DELETEJAVASCRIPTREGISTER, SIGNATURE_DELETEJAVASCRIPTREGISTER);337 env->GetMethodID(cls, METHOD_DELETEJAVASCRIPTREGISTER, SIGNATURE_DELETEJAVASCRIPTREGISTER);
338+ g_webWebviewClass.setWebSchemeHandler =
339+ env->GetMethodID(cls, METHOD_SET_WEB_SCHEME_HANDLER, SIGNATURE_SET_WEB_SCHEME_HANDLER);
340+ g_webWebviewClass.clearWebSchemeHandler =
341+ env->GetMethodID(cls, METHOD_CLEAR_WEB_SCHEME_HANDLER, SIGNATURE_CLEAR_WEB_SCHEME_HANDLER);
342+ g_webWebviewClass.getUserAgent = env->GetMethodID(cls, METHOD_GET_USER_AGENT, SIGNATURE_GET_USER_AGENT);
323 env->DeleteLocalRef(cls);343 env->DeleteLocalRef(cls);
324}344}
325 345 
@@ -1752,4 +1772,58 @@ void WebviewControllerJni::DeleteJavaScriptRegister(int id, const std::string& o
1752 env->ExceptionClear();1772 env->ExceptionClear();
1753 }1773 }
1754}1774}
1775+ 
1776+bool WebviewControllerJni::SetWebSchemeHandler(int id, const std::string& scheme)
1777+{
1778+ auto env = ARKUI_X_Plugin_GetJniEnv();
1779+ CHECK_NULL_RETURN(env, false);
1780+ CHECK_NULL_RETURN(g_webWebviewClass.globalRef, false);
1781+ CHECK_NULL_RETURN(g_webWebviewClass.setWebSchemeHandler, false);
1782+ jstring jsScheme = env->NewStringUTF(scheme.c_str());
1783+ bool ret = env->CallBooleanMethod(g_webWebviewClass.globalRef, g_webWebviewClass.setWebSchemeHandler, id, jsScheme);
1784+ env->DeleteLocalRef(jsScheme);
1785+ if (env->ExceptionCheck()) {
1786+ env->ExceptionDescribe();
1787+ env->ExceptionClear();
1788+ }
1789+ return ret;
1790+}
1791+ 
1792+void WebviewControllerJni::ClearWebSchemeHandler(int id)
1793+{
1794+ auto env = ARKUI_X_Plugin_GetJniEnv();
1795+ CHECK_NULL_VOID(env);
1796+ CHECK_NULL_VOID(g_webWebviewClass.globalRef);
1797+ CHECK_NULL_VOID(g_webWebviewClass.clearWebSchemeHandler);
1798+ env->CallVoidMethod(g_webWebviewClass.globalRef, g_webWebviewClass.clearWebSchemeHandler, id);
1799+ if (env->ExceptionCheck()) {
1800+ env->ExceptionDescribe();
1801+ env->ExceptionClear();
1802+ }
1803+}
1804+ 
1805+std::string WebviewControllerJni::GetUserAgent(int id)
1806+{
1807+ auto env = ARKUI_X_Plugin_GetJniEnv();
1808+ CHECK_NULL_RETURN(env, "");
1809+ CHECK_NULL_RETURN(g_webWebviewClass.globalRef, "");
1810+ CHECK_NULL_RETURN(g_webWebviewClass.getUserAgent, "");
1811+ jstring jResult = static_cast<jstring>(
1812+ env->CallObjectMethod(g_webWebviewClass.globalRef, g_webWebviewClass.getUserAgent, id));
1813+ if (env->ExceptionCheck()) {
1814+ env->ExceptionDescribe();
1815+ env->ExceptionClear();
1816+ return "";
1817+ }
1818+ std::string result = "";
1819+ const char* content = env->GetStringUTFChars(jResult, nullptr);
1820+ if (content != nullptr) {
1821+ result.assign(content);
1822+ env->ReleaseStringUTFChars(jResult, content);
1823+ }
1824+ if (jResult != nullptr) {
1825+ env->DeleteLocalRef(jResult);
1826+ }
1827+ return result;
1828+}
1755}1829}
@@ -95,6 +95,9 @@ public:
95 static jobject ConvertWebStringToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);95 static jobject ConvertWebStringToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);
96 static jobject ConvertWebListToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);96 static jobject ConvertWebListToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);
97 static jobject ConvertWebDictionaryToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);97 static jobject ConvertWebDictionaryToJava(JNIEnv* env, std::shared_ptr<Ace::WebJSValue>& ret);
98+ static bool SetWebSchemeHandler(int id, const std::string& scheme);
99+ static void ClearWebSchemeHandler(int id);
100+ static std::string GetUserAgent(int id);
98};101};
99}102}
100 103 
@@ -0,0 +1,68 @@
1+/*
2+ * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
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+package ohos.ace.plugin.webviewplugin.androidasset;
17+ 
18+import android.content.Context;
19+import android.content.res.AssetManager;
20+ 
21+import java.io.IOException;
22+import java.io.InputStream;
23+ 
24+/**
25+ * AndroidAssetPlugin is used to manage AndroidAsset
26+ *
27+ * @since 22
28+ */
29+public class AndroidAssetPlugin {
30+ private static final String LOG_TAG = "AndroidAssetPlugin";
31+ private static final String ANDROID_VIRTUAL_ASSET_PREFIX = "file:///android_asset/";
32+ 
33+ private final Context context;
34+ 
35+ public AndroidAssetPlugin(Context context) {
36+ this.context = context;
37+ nativeInit();
38+ }
39+ 
40+ /**
41+ * Checks whether a virtual asset exists at the specified URL.
42+ *
43+ * <p>This method verifies if the given URL starts with the expected virtual asset prefix.
44+ * If so, it attempts to open the asset using the {@link AssetManager}. If the asset can be
45+ * opened without throwing an {@link IOException}, it is considered to exist.</p>
46+ *
47+ * @param url The URL of the virtual asset to check.
48+ * @return {@code true} if the virtual asset exists; {@code false} otherwise.
49+ */
50+ public boolean existsVirtualAsset(String url) {
51+ if (!url.startsWith(ANDROID_VIRTUAL_ASSET_PREFIX)) {
52+ return false;
53+ }
54+ 
55+ AssetManager assetManager = this.context.getAssets();
56+ String assetPath = url.substring(ANDROID_VIRTUAL_ASSET_PREFIX.length());
57+ try (InputStream inputStream = assetManager.open(assetPath)) {
58+ return true;
59+ } catch (IOException e) {
60+ return false;
61+ }
62+ }
63+ 
64+ /**
65+ * Initialize the native environment.
66+ */
67+ protected final native void nativeInit();
68+}
@@ -234,4 +234,23 @@ void WebviewControllerIOS::DeleteJavaScriptRegister(const std::string& objName)
234{234{
235 deleteJavaScriptRegisterOC(webId_, objName);235 deleteJavaScriptRegisterOC(webId_, objName);
236}236}
237+ 
238+bool WebviewControllerIOS::SetWebSchemeHandler(const char* scheme, WebSchemeHandler* handler)
239+{
240+ if (!handler || !scheme) {
241+ return false;
242+ }
243+ auto arkHandler = WebSchemeHandler::GetArkWebSchemeHandler(handler);
244+ return setWebSchemeHandlerOC(webId_, scheme, arkHandler);
245+}
246+ 
247+bool WebviewControllerIOS::ClearWebSchemeHandler()
248+{
249+ return clearWebSchemeHandlerOC(webId_);
250+}
251+ 
252+std::string WebviewControllerIOS::GetUserAgent()
253+{
254+ return getUserAgentOC();
255+}
237} // namespace OHOS::Plugin256} // namespace OHOS::Plugin
@@ -18,6 +18,7 @@
18 18 
19#include "plugins/web/webview/webview_controller.h"19#include "plugins/web/webview/webview_controller.h"
20#include "plugins/web/webview/web_download_delegate.h"20#include "plugins/web/webview/web_download_delegate.h"
21+#include "plugins/web/webview/web_scheme_handler_request.h"
21 22 
22namespace OHOS::Plugin {23namespace OHOS::Plugin {
23class WebviewControllerIOS : public WebviewController {24class WebviewControllerIOS : public WebviewController {
@@ -61,6 +62,9 @@ public:
61 void StartDownload(const std::string& url) override;62 void StartDownload(const std::string& url) override;
62 void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) override;63 void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) override;
63 void DeleteJavaScriptRegister(const std::string& objName) override;64 void DeleteJavaScriptRegister(const std::string& objName) override;
65+ bool SetWebSchemeHandler(const char* scheme, WebSchemeHandler* handler) override;
66+ bool ClearWebSchemeHandler() override;
67+ std::string GetUserAgent() override;
64};68};
65} // namespace OHOS::Plugin69} // namespace OHOS::Plugin
66#endif70#endif
@@ -30,6 +30,7 @@
30#include "log.h"30#include "log.h"
31#include "napi_parse_utils.h"31#include "napi_parse_utils.h"
32#include "napi_web_message_ext.h"32#include "napi_web_message_ext.h"
33+#include "napi_web_scheme_handler_request.h"
33#include "plugin_utils.h"34#include "plugin_utils.h"
34#include "web_download_delegate.h"35#include "web_download_delegate.h"
35#include "web_download_item.h"36#include "web_download_item.h"
@@ -37,7 +38,9 @@
37#include "web_message_port.h"38#include "web_message_port.h"
38#include "webview_controller.h"39#include "webview_controller.h"
39#include "webview_javascript_async_work_callback.h"40#include "webview_javascript_async_work_callback.h"
41+#include "web_scheme_handler_request.h"
40#ifdef ANDROID_PLATFORM42#ifdef ANDROID_PLATFORM
43+#include "android/java/jni/android_asset_helper_jni.h"
41#include "android/java/jni/web_cookie_manager_android.h"44#include "android/java/jni/web_cookie_manager_android.h"
42#include "android/java/jni/web_cookie_manager_jni.h"45#include "android/java/jni/web_cookie_manager_jni.h"
43#include "android/java/jni/web_data_base_android.h"46#include "android/java/jni/web_data_base_android.h"
@@ -51,6 +54,7 @@
51#include "android/java/jni/web_storage_jni.h"54#include "android/java/jni/web_storage_jni.h"
52#include "android/java/jni/webview_controller_android.h"55#include "android/java/jni/webview_controller_android.h"
53#include "android/java/jni/webview_controller_jni.h"56#include "android/java/jni/webview_controller_jni.h"
57+#include "android/java/jni/web_scheme_handler_jni.h"
54#endif58#endif
55#ifdef IOS_PLATFORM59#ifdef IOS_PLATFORM
56#include "ios/webview_controller_ios.h"60#include "ios/webview_controller_ios.h"
@@ -67,9 +71,11 @@ thread_local napi_ref g_classWebMsgPort;
67thread_local napi_ref g_jsMsgExtClassRef;71thread_local napi_ref g_jsMsgExtClassRef;
68thread_local int32_t g_asyncCallbackInfoId = 0;72thread_local int32_t g_asyncCallbackInfoId = 0;
69constexpr int32_t MAX_COUNT_ID = 1024;73constexpr int32_t MAX_COUNT_ID = 1024;
74+const std::string ANDROID_ASSET = "file:///android_asset/";
75+const std::string ARKUIX_PATH_MARKER = "files/arkui-x/";
70const std::string HTTP = "http://";76const std::string HTTP = "http://";
71const std::string HTTPS = "https://";77const std::string HTTPS = "https://";
72-const std::string RESOURCE = "resource://rawfile";78+const std::string RESOURCE = "resource://rawfile/";
73const std::string FILE = "file";79const std::string FILE = "file";
74constexpr int32_t MAX_WEB_STRING_LENGTH = 40960;80constexpr int32_t MAX_WEB_STRING_LENGTH = 40960;
75constexpr uint32_t URL_MAXIMUM = 2048;81constexpr uint32_t URL_MAXIMUM = 2048;
@@ -79,6 +85,24 @@ const char* rawfile = "resource://rawfile/";
79const char* replacement = "file:///";85const char* replacement = "file:///";
80std::regex reg("^(https?|file)://[\\w.-/]+(:\\d+)?(/.*)?$");86std::regex reg("^(https?|file)://[\\w.-/]+(:\\d+)?(/.*)?$");
81 87 
88+bool ExistsWebFileUrl(const std::string &webFileUrl)
89+{
90+#ifdef ANDROID_PLATFORM
91+ if (webFileUrl.substr(INTEGER_ZERO, ANDROID_ASSET.size()) == ANDROID_ASSET) {
92+ return AndroidAssetHelperJni::ExistsVirtualAsset(webFileUrl);
93+ }
94+#endif
95+ 
96+ std::string fileProtocolName = "file";
97+ if (webFileUrl.substr(INTEGER_ZERO, fileProtocolName.size()) == "file") {
98+ std::string filePath = webFileUrl;
99+ std::string fileProtocol = "file:///";
100+ filePath.erase(INTEGER_ZERO, fileProtocol.size());
101+ return access(filePath.c_str(), F_OK) != -1;
102+ }
103+ 
104+ return true;
105+}
82 106 
83bool GetRawFileUrl(const std::string &fileName, std::string &result)107bool GetRawFileUrl(const std::string &fileName, std::string &result)
84{108{
@@ -86,7 +110,19 @@ bool GetRawFileUrl(const std::string &fileName, std::string &result)
86 return false;110 return false;
87 }111 }
88 result = NapiWebviewController::appHapPath_ + "/resources/rawfile/" + fileName;112 result = NapiWebviewController::appHapPath_ + "/resources/rawfile/" + fileName;
89- LOGE("The parsed url is: %{public}s", result.c_str());113+ 
114+#ifdef ANDROID_PLATFORM
115+ size_t pos = NapiWebviewController::appHapPath_.find(ARKUIX_PATH_MARKER);
116+ if (pos != std::string::npos) {
117+ std::string assetPath = ANDROID_ASSET +
118+ NapiWebviewController::appHapPath_.substr(pos + std::strlen("files/")) + "/resources/rawfile/" + fileName;
119+ if (AndroidAssetHelperJni::ExistsVirtualAsset(assetPath)) {
120+ result = assetPath;
121+ }
122+ }
123+#endif
124+ 
125+ LOGD("The parsed url is: %{public}s", result.c_str());
90 return true;126 return true;
91}127}
92 128 
@@ -307,15 +343,8 @@ napi_value NapiWebviewController::LoadUrl(napi_env env, napi_callback_info info)
307 LOGE("ParseUrl failed");343 LOGE("ParseUrl failed");
308 return nullptr;344 return nullptr;
309 }345 }
310- std::string fileProtocolName = "file";346+ if (!ExistsWebFileUrl(webSrc)) {
311- if (webSrc.substr(INTEGER_ZERO, fileProtocolName.size()) == "file") {347+ BusinessError::ThrowErrorByErrcode(env, INVALID_RESOURCE);
312- std::string filePath = webSrc;
313- std::string fileProtocol = "file:///";
314- filePath.erase(INTEGER_ZERO, fileProtocol.size());
315- int isFileExist = access(filePath.c_str(), F_OK);
316- if (isFileExist == -1) {
317- BusinessError::ThrowErrorByErrcode(env, INVALID_RESOURCE);
318- }
319 }348 }
320 if (argc == INTEGER_ONE) {349 if (argc == INTEGER_ONE) {
321 ErrCode ret = webviewController->LoadUrl(webSrc);350 ErrCode ret = webviewController->LoadUrl(webSrc);
@@ -1770,6 +1799,59 @@ napi_value NapiWebviewController::RegisterJavaScriptProxy(napi_env env, napi_cal
1770 return result;1799 return result;
1771}1800}
1772 1801 
1802+napi_value NapiWebviewController::SetWebSchemeHandler(napi_env env, napi_callback_info info)
1803+{
1804+ size_t argc = 2;
1805+ napi_value argv[2] = {0};
1806+ napi_value thisVar = nullptr;
1807+ void* data = nullptr;
1808+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1809+ 
1810+ WebviewController *webviewController = nullptr;
1811+ NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webviewController));
1812+ if (webviewController == nullptr || !webviewController->IsInit()) {
1813+ BusinessError::ThrowErrorByErrcode(env, INIT_ERROR);
1814+ LOGE("create message port failed, napi unwrap webviewController failed");
1815+ return nullptr;
1816+ }
1817+ 
1818+ std::string scheme = "";
1819+ if (!NapiParseUtils::ParseString(env, argv[0], scheme)) {
1820+ LOGE("NapiWebviewController::SetWebSchemeHandler parse scheme failed");
1821+ BusinessError::ThrowErrorByErrcode(env, PARAM_CHECK_ERROR,
1822+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scheme", "string"));
1823+ return nullptr;
1824+ }
1825+ 
1826+ WebSchemeHandler* handler = nullptr;
1827+ napi_value obj = argv[1];
1828+ napi_unwrap(env, obj, (void**)&handler);
1829+ if (!handler) {
1830+ LOGE("NapiWebviewController::SetWebSchemeHandler handler is null");
1831+ return nullptr;
1832+ }
1833+ if (!webviewController->SetWebSchemeHandler(scheme.c_str(), handler)) {
1834+ LOGE("NapiWebviewController::SetWebSchemeHandler failed");
1835+ }
1836+ return nullptr;
1837+}
1838+ 
1839+napi_value NapiWebviewController::ClearWebSchemeHandler(napi_env env, napi_callback_info info)
1840+{
1841+ napi_value result = nullptr;
1842+ WebviewController *webviewController = GetWebviewController(env, info);
jinpeng0804
jinpeng0804jinpeng08042025年10月13日

返回值类型为napi_value,返回nullptr可能导致NAPI运行时异常或未定义行为,返回前调用napi_get_undefined获取结果值,而非直接返回nullptr

likedislike
quguiren
2025年10月15日 评论:
1843+ if (!webviewController) {
1844+ napi_get_undefined(env, &result);
1845+ return result;
1846+ }
1847+ 
1848+ if (!webviewController->ClearWebSchemeHandler()) {
1849+ LOGE("NapiWebviewController::ClearWebSchemeHandler failed");
1850+ }
1851+ NAPI_CALL(env, napi_get_undefined(env, &result));
1852+ return result;
1853+}
1854+ 
1773napi_value NapiWebviewController::DeleteJavaScriptRegister(napi_env env, napi_callback_info info)1855napi_value NapiWebviewController::DeleteJavaScriptRegister(napi_env env, napi_callback_info info)
1774{1856{
1775 napi_value thisVar = nullptr;1857 napi_value thisVar = nullptr;
@@ -1809,6 +1891,21 @@ napi_value NapiWebviewController::DeleteJavaScriptRegister(napi_env env, napi_ca
1809 return result;1891 return result;
1810}1892}
1811 1893 
1894+napi_value NapiWebviewController::GetUserAgent(napi_env env, napi_callback_info info)
1895+{
1896+ napi_value result = nullptr;
1897+ WebviewController *webviewController = GetWebviewController(env, info);
1898+ if (!webviewController) {
1899+ return nullptr;
1900+ }
1901+ 
1902+ std::string userAgent = "";
1903+ userAgent = webviewController->GetUserAgent();
1904+ napi_create_string_utf8(env, userAgent.c_str(), userAgent.length(), &result);
1905+ 
1906+ return result;
1907+}
1908+ 
1812napi_value NapiWebviewController::Init(napi_env env, napi_value exports)1909napi_value NapiWebviewController::Init(napi_env env, napi_value exports)
1813{1910{
1814 napi_property_descriptor properties[] = {1911 napi_property_descriptor properties[] = {
@@ -1852,6 +1949,9 @@ napi_value NapiWebviewController::Init(napi_env env, napi_value exports)
1852 DECLARE_NAPI_FUNCTION("registerJavaScriptProxy", NapiWebviewController::RegisterJavaScriptProxy),1949 DECLARE_NAPI_FUNCTION("registerJavaScriptProxy", NapiWebviewController::RegisterJavaScriptProxy),
1853 DECLARE_NAPI_FUNCTION("deleteJavaScriptRegister", NapiWebviewController::DeleteJavaScriptRegister),1950 DECLARE_NAPI_FUNCTION("deleteJavaScriptRegister", NapiWebviewController::DeleteJavaScriptRegister),
1854 DECLARE_NAPI_FUNCTION("jsProxy", NapiWebviewController::RegisterJavaScriptProxy),1951 DECLARE_NAPI_FUNCTION("jsProxy", NapiWebviewController::RegisterJavaScriptProxy),
1952+ DECLARE_NAPI_FUNCTION("setWebSchemeHandler", NapiWebviewController::SetWebSchemeHandler),
1953+ DECLARE_NAPI_FUNCTION("clearWebSchemeHandler", NapiWebviewController::ClearWebSchemeHandler),
1954+ DECLARE_NAPI_FUNCTION("getUserAgent", NapiWebviewController::GetUserAgent),
1855 };1955 };
1856 1956 
1857 napi_value constructor = nullptr;1957 napi_value constructor = nullptr;
@@ -2072,6 +2172,9 @@ static napi_value WebWebviewExport(napi_env env, napi_value exports)
2072 NapiWebDownloadManager::Init(env, exports);2172 NapiWebDownloadManager::Init(env, exports);
2073 NapiWebDownloadItem::Init(env, exports);2173 NapiWebDownloadItem::Init(env, exports);
2074 NapiWebMessageExt::Init(env, exports);2174 NapiWebMessageExt::Init(env, exports);
2175+ NapiWebSchemeHandler::Init(env, exports);
2176+ NapiWebSchemeHandlerRequest::Init(env, exports);
2177+ NapiWebSchemeHandlerResponse::Init(env, exports);
2075 return exports;2178 return exports;
2076}2179}
2077 2180 
@@ -2102,6 +2205,10 @@ static void WebWebviewJniRegister()
2102 ARKUI_X_Plugin_RegisterJavaPlugin(&WebDownloadDelegateJni::Register, webDownloadDelegateClassName);2205 ARKUI_X_Plugin_RegisterJavaPlugin(&WebDownloadDelegateJni::Register, webDownloadDelegateClassName);
2103 const char webDownloadItemClassName[] = "ohos.ace.adapter.capability.web.AceWebPluginBase";2206 const char webDownloadItemClassName[] = "ohos.ace.adapter.capability.web.AceWebPluginBase";
2104 ARKUI_X_Plugin_RegisterJavaPlugin(&WebDownloadItemJni::Register, webDownloadItemClassName);2207 ARKUI_X_Plugin_RegisterJavaPlugin(&WebDownloadItemJni::Register, webDownloadItemClassName);
2208+ const char webSchemeRequestClassName[] = "ohos.ace.adapter.capability.web.AceWebPluginBase";
2209+ ARKUI_X_Plugin_RegisterJavaPlugin(&WebSchemeHandlerJni::Register, webSchemeRequestClassName);
2210+ const char AndroidAssetClassName[] = "ohos.ace.plugin.webviewplugin.androidasset.AndroidAssetPlugin";
2211+ ARKUI_X_Plugin_RegisterJavaPlugin(&AndroidAssetHelperJni::Register, AndroidAssetClassName);
2105}2212}
2106#endif2213#endif
2107 2214 
@@ -4028,4 +4135,102 @@ napi_status NapiWebDownloadItem::DefineProperties(napi_env env, napi_value* obje
4028 };4135 };
4029 return napi_define_properties(env, *object, sizeof(properties) / sizeof(properties[0]), properties);4136 return napi_define_properties(env, *object, sizeof(properties) / sizeof(properties[0]), properties);
4030}4137}
4138+ 
4139+napi_value NapiWebSchemeHandler::Init(napi_env env, napi_value exports)
4140+{
4141+ napi_property_descriptor properties[] = {
4142+ DECLARE_NAPI_FUNCTION("onRequestStart", JS_RequestStart),
4143+ DECLARE_NAPI_FUNCTION("onRequestStop", JS_RequestStop),
4144+ };
4145+ napi_value webSchemeHandler = nullptr;
4146+ napi_define_class(env, WEB_SCHEME_HANDLER.c_str(), WEB_SCHEME_HANDLER.length(),
4147+ JS_Constructor, nullptr,
4148+ sizeof(properties) / sizeof(properties[0]), properties, &webSchemeHandler);
4149+ napi_set_named_property(env, exports, WEB_SCHEME_HANDLER.c_str(),
4150+ webSchemeHandler);
4151+ return exports;
4152+}
4153+ 
4154+napi_value NapiWebSchemeHandler::JS_Constructor(napi_env env, napi_callback_info info)
4155+{
4156+ napi_value thisVar = nullptr;
4157+ void *data = nullptr;
4158+ napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
4159+ 
4160+ WebSchemeHandler *handler = new WebSchemeHandler(env);
4161+ 
4162+ napi_wrap(
4163+ env, thisVar, handler,
4164+ [](napi_env /* env */, void *data, void * /* hint */) {
4165+ WebSchemeHandler *handler = (WebSchemeHandler *)data;
4166+ delete handler;
4167+ },
4168+ nullptr, nullptr);
4169+ 
4170+ return thisVar;
4171+}
4172+ 
4173+napi_value NapiWebSchemeHandler::JS_RequestStart(napi_env env, napi_callback_info info)
4174+{
4175+ size_t argc = 1;
4176+ napi_value argv[1] = {0};
4177+ napi_value thisVar = nullptr;
4178+ void *data = nullptr;
4179+ WebSchemeHandler *handler = nullptr;
4180+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
4181+ 
4182+ napi_unwrap(env, thisVar, (void **)&handler);
4183+ if (!handler) {
4184+ LOGE("webSchemeHandler is null");
4185+ return thisVar;
4186+ }
4187+ 
4188+ napi_valuetype valueType = napi_undefined;
4189+ napi_typeof(env, argv[0], &valueType);
4190+ 
4191+ if (argc != INTEGER_ONE) {
4192+ BusinessError::ThrowErrorByErrcode(env, PARAM_CHECK_ERROR,
4193+ NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_ONE, "one"));
4194+ return nullptr;
4195+ }
4196+ if (valueType != napi_function) {
4197+ BusinessError::ThrowErrorByErrcode(env, PARAM_CHECK_ERROR,
4198+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "callback", "function"));
4199+ return nullptr;
4200+ }
4201+ 
4202+ handler->PutRequestStart(env, argv[0]);
4203+ return thisVar;
4204+}
4205+ 
4206+napi_value NapiWebSchemeHandler::JS_RequestStop(napi_env env, napi_callback_info info)
4207+{
4208+ size_t argc = 1;
4209+ napi_value argv[1] = {0};
4210+ napi_value thisVar = nullptr;
4211+ void *data = nullptr;
4212+ WebSchemeHandler *handler = nullptr;
4213+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
4214+ if (argc != INTEGER_ONE) {
4215+ BusinessError::ThrowErrorByErrcode(env, PARAM_CHECK_ERROR);
4216+ return nullptr;
4217+ }
4218+ 
4219+ napi_unwrap(env, thisVar, (void **)&handler);
4220+ if (!handler) {
4221+ LOGE("webSchemeHandler is null");
4222+ return thisVar;
4223+ }
4224+ 
4225+ napi_valuetype valueType = napi_undefined;
4226+ napi_typeof(env, argv[0], &valueType);
4227+ 
4228+ if (valueType != napi_function) {
4229+ BusinessError::ThrowErrorByErrcode(env, PARAM_CHECK_ERROR);
4230+ return nullptr;
4231+ }
4232+ 
4233+ handler->PutRequestStop(env, argv[0]);
4234+ return thisVar;
4235+}
4031} // namespace OHOS::Plugin4236} // namespace OHOS::Plugin
@@ -143,6 +143,12 @@ private:
143 static napi_value RegisterJavaScriptProxy(napi_env env, napi_callback_info info);143 static napi_value RegisterJavaScriptProxy(napi_env env, napi_callback_info info);
144 144 
145 static napi_value DeleteJavaScriptRegister(napi_env env, napi_callback_info info);145 static napi_value DeleteJavaScriptRegister(napi_env env, napi_callback_info info);
146+ 
147+ static napi_value SetWebSchemeHandler(napi_env env, napi_callback_info info);
148+ 
149+ static napi_value ClearWebSchemeHandler(napi_env env, napi_callback_info info);
150+ 
151+ static napi_value GetUserAgent(napi_env env, napi_callback_info info);
146};152};
147 153 
148class NapiWebDataBase {154class NapiWebDataBase {
@@ -367,5 +373,16 @@ private:
367 static void CreateGetStoredGeolocationAsyncWork(napi_env env,373 static void CreateGetStoredGeolocationAsyncWork(napi_env env,
368 const std::shared_ptr<GeolocationPermissionsResultCallbackInfo> &callbackInfo);374 const std::shared_ptr<GeolocationPermissionsResultCallbackInfo> &callbackInfo);
369};375};
376+ 
377+class NapiWebSchemeHandler {
378+public:
379+ NapiWebSchemeHandler() = default;
380+ ~NapiWebSchemeHandler() = default;
381+ 
382+ static napi_value Init(napi_env env, napi_value exports);
383+ static napi_value JS_Constructor(napi_env env, napi_callback_info info);
384+ static napi_value JS_RequestStart(napi_env env, napi_callback_info info);
385+ static napi_value JS_RequestStop(napi_env env, napi_callback_info info);
386+};
370}387}
371#endif388#endif
@@ -0,0 +1,1186 @@
1+/*
2+ * Copyright (c) 2025 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 "napi_web_scheme_handler_request.h"
17+ 
18+#include <algorithm>
19+#include <unordered_set>
20+ 
21+#include "business_error.h"
22+#include "log.h"
23+#include "napi_parse_utils.h"
24+#include "web_errors.h"
25+#include "web_scheme_handler_request.h"
26+ 
27+namespace OHOS::Plugin {
28+static const std::unordered_map<int32_t, std::string> g_netErrorCodeMap = {
29+ {ARKWEB_NET_OK, "NET_OK"},
30+ {ARKWEB_ERR_IO_PENDING, "ERR_IO_PENDING"},
31+ {ARKWEB_ERR_FAILED, "ERR_FAILED"},
32+ {ARKWEB_ERR_ABORTED, "ERR_ABORTED"},
33+ {ARKWEB_ERR_INVALID_ARGUMENT, "ERR_INVALID_ARGUMENT"},
34+ {ARKWEB_ERR_INVALID_HANDLE, "ERR_INVALID_HANDLE"},
35+ {ARKWEB_ERR_FILE_NOT_FOUND, "ERR_FILE_NOT_FOUND"},
36+ {ARKWEB_ERR_TIMED_OUT, "ERR_TIMED_OUT"},
37+ {ARKWEB_ERR_FILE_TOO_LARGE, "ERR_FILE_TOO_LARGE"},
38+ {ARKWEB_ERR_UNEXPECTED, "ERR_UNEXPECTED"},
39+ {ARKWEB_ERR_ACCESS_DENIED, "ERR_ACCESS_DENIED"},
40+ {ARKWEB_ERR_NOT_IMPLEMENTED, "ERR_NOT_IMPLEMENTED"},
41+ {ARKWEB_ERR_INSUFFICIENT_RESOURCES, "ERR_INSUFFICIENT_RESOURCES"},
42+ {ARKWEB_ERR_OUT_OF_MEMORY, "ERR_OUT_OF_MEMORY"},
43+ {ARKWEB_ERR_UPLOAD_FILE_CHANGED, "ERR_UPLOAD_FILE_CHANGED"},
44+ {ARKWEB_ERR_SOCKET_NOT_CONNECTED, "ERR_SOCKET_NOT_CONNECTED"},
45+ {ARKWEB_ERR_FILE_EXISTS, "ERR_FILE_EXISTS"},
46+ {ARKWEB_ERR_FILE_PATH_TOO_LONG, "ERR_FILE_PATH_TOO_LONG"},
47+ {ARKWEB_ERR_FILE_NO_SPACE, "ERR_FILE_NO_SPACE"},
48+ {ARKWEB_ERR_FILE_VIRUS_INFECTED, "ERR_FILE_VIRUS_INFECTED"},
49+ {ARKWEB_ERR_BLOCKED_BY_CLIENT, "ERR_BLOCKED_BY_CLIENT"},
50+ {ARKWEB_ERR_NETWORK_CHANGED, "ERR_NETWORK_CHANGED"},
51+ {ARKWEB_ERR_BLOCKED_BY_ADMINISTRATOR, "ERR_BLOCKED_BY_ADMINISTRATOR"},
52+ {ARKWEB_ERR_SOCKET_CONNECTED, "ERR_SOCKET_CONNECTED"},
53+ {ARKWEB_ERR_UPLOAD_STREAM_REWIND_NOT_SUPPORTED, "ERR_UPLOAD_STREAM_REWIND_NOT_SUPPORTED"},
54+ {ARKWEB_ERR_CONTEXT_SHUT_DOWN, "ERR_CONTEXT_SHUT_DOWN"},
55+ {ARKWEB_ERR_BLOCKED_BY_RESPONSE, "ERR_BLOCKED_BY_RESPONSE"},
56+ {ARKWEB_ERR_CLEARTEXT_NOT_PERMITTED, "ERR_CLEARTEXT_NOT_PERMITTED"},
57+ {ARKWEB_ERR_BLOCKED_BY_CSP, "ERR_BLOCKED_BY_CSP"},
58+ {ARKWEB_ERR_H2_OR_QUIC_REQUIRED, "ERR_H2_OR_QUIC_REQUIRED"},
59+ {ARKWEB_ERR_BLOCKED_BY_ORB, "ERR_BLOCKED_BY_ORB"},
60+ {ARKWEB_ERR_CONNECTION_CLOSED, "ERR_CONNECTION_CLOSED"},
61+ {ARKWEB_ERR_CONNECTION_RESET, "ERR_CONNECTION_RESET"},
62+ {ARKWEB_ERR_CONNECTION_REFUSED, "ERR_CONNECTION_REFUSED"},
63+ {ARKWEB_ERR_CONNECTION_ABORTED, "ERR_CONNECTION_ABORTED"},
64+ {ARKWEB_ERR_CONNECTION_FAILED, "ERR_CONNECTION_FAILED"},
65+ {ARKWEB_ERR_NAME_NOT_RESOLVED, "ERR_NAME_NOT_RESOLVED"},
66+ {ARKWEB_ERR_INTERNET_DISCONNECTED, "ERR_INTERNET_DISCONNECTED"},
67+ {ARKWEB_ERR_SSL_PROTOCOL_ERROR, "ERR_SSL_PROTOCOL_ERROR"},
68+ {ARKWEB_ERR_ADDRESS_INVALID, "ERR_ADDRESS_INVALID"},
69+ {ARKWEB_ERR_ADDRESS_UNREACHABLE, "ERR_ADDRESS_UNREACHABLE"},
70+ {ARKWEB_ERR_SSL_CLIENT_AUTH_CERT_NEEDED, "ERR_SSL_CLIENT_AUTH_CERT_NEEDED"},
71+ {ARKWEB_ERR_TUNNEL_CONNECTION_FAILED, "ERR_TUNNEL_CONNECTION_FAILED"},
72+ {ARKWEB_ERR_NO_SSL_VERSIONS_ENABLED, "ERR_NO_SSL_VERSIONS_ENABLED"},
73+ {ARKWEB_ERR_SSL_VERSION_OR_CIPHER_MISMATCH, "ERR_SSL_VERSION_OR_CIPHER_MISMATCH"},
74+ {ARKWEB_ERR_SSL_RENEGOTIATION_REQUESTED, "ERR_SSL_RENEGOTIATION_REQUESTED"},
75+ {ARKWEB_ERR_PROXY_AUTH_UNSUPPORTED, "ERR_PROXY_AUTH_UNSUPPORTED"},
76+ {ARKWEB_ERR_BAD_SSL_CLIENT_AUTH_CERT, "ERR_BAD_SSL_CLIENT_AUTH_CERT"},
77+ {ARKWEB_ERR_CONNECTION_TIMED_OUT, "ERR_CONNECTION_TIMED_OUT"},
78+ {ARKWEB_ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, "ERR_HOST_RESOLVER_QUEUE_TOO_LARGE"},
79+ {ARKWEB_ERR_SOCKS_CONNECTION_FAILED, "ERR_SOCKS_CONNECTION_FAILED"},
80+ {ARKWEB_ERR_SOCKS_CONNECTION_HOST_UNREACHABLE, "ERR_SOCKS_CONNECTION_HOST_UNREACHABLE"},
81+ {ARKWEB_ERR_ALPN_NEGOTIATION_FAILED, "ERR_ALPN_NEGOTIATION_FAILED"},
82+ {ARKWEB_ERR_SSL_NO_RENEGOTIATION, "ERR_SSL_NO_RENEGOTIATION"},
83+ {ARKWEB_ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES, "ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES"},
84+ {ARKWEB_ERR_SSL_DECOMPRESSION_FAILURE_ALERT, "ERR_SSL_DECOMPRESSION_FAILURE_ALERT"},
85+ {ARKWEB_ERR_SSL_BAD_RECORD_MAC_ALERT, "ERR_SSL_BAD_RECORD_MAC_ALERT"},
86+ {ARKWEB_ERR_PROXY_AUTH_REQUESTED, "ERR_PROXY_AUTH_REQUESTED"},
87+ {ARKWEB_ERR_PROXY_CONNECTION_FAILED, "ERR_PROXY_CONNECTION_FAILED"},
88+ {ARKWEB_ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, "ERR_MANDATORY_PROXY_CONFIGURATION_FAILED"},
89+ {ARKWEB_ERR_PRECONNECT_MAX_SOCKET_LIMIT, "ERR_PRECONNECT_MAX_SOCKET_LIMIT"},
90+ {ARKWEB_ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED, "ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED"},
91+ {ARKWEB_ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY, "ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY"},
92+ {ARKWEB_ERR_PROXY_CERTIFICATE_INVALID, "ERR_PROXY_CERTIFICATE_INVALID"},
93+ {ARKWEB_ERR_NAME_RESOLUTION_FAILED, "ERR_NAME_RESOLUTION_FAILED"},
94+ {ARKWEB_ERR_NETWORK_ACCESS_DENIED, "ERR_NETWORK_ACCESS_DENIED"},
95+ {ARKWEB_ERR_TEMPORARILY_THROTTLED, "ERR_TEMPORARILY_THROTTLED"},
96+ {ARKWEB_ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT, "ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT"},
97+ {ARKWEB_ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED, "ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED"},
98+ {ARKWEB_ERR_MSG_TOO_BIG, "ERR_MSG_TOO_BIG"},
99+ {ARKWEB_ERR_WS_PROTOCOL_ERROR, "ERR_WS_PROTOCOL_ERROR"},
100+ {ARKWEB_ERR_ADDRESS_IN_USE, "ERR_ADDRESS_IN_USE"},
101+ {ARKWEB_ERR_SSL_HANDSHAKE_NOT_COMPLETED, "ERR_SSL_HANDSHAKE_NOT_COMPLETED"},
102+ {ARKWEB_ERR_SSL_BAD_PEER_PUBLIC_KEY, "ERR_SSL_BAD_PEER_PUBLIC_KEY"},
103+ {ARKWEB_ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, "ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN"},
104+ {ARKWEB_ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED, "ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED"},
105+ {ARKWEB_ERR_SSL_DECRYPT_ERROR_ALERT, "ERR_SSL_DECRYPT_ERROR_ALERT"},
106+ {ARKWEB_ERR_WS_THROTTLE_QUEUE_TOO_LARGE, "ERR_WS_THROTTLE_QUEUE_TOO_LARGE"},
107+ {ARKWEB_ERR_SSL_SERVER_CERT_CHANGED, "ERR_SSL_SERVER_CERT_CHANGED"},
108+ {ARKWEB_ERR_SSL_UNRECOGNIZED_NAME_ALERT, "ERR_SSL_UNRECOGNIZED_NAME_ALERT"},
109+ {ARKWEB_ERR_SOCKET_SET_RECEIVE_BUFFER_SIZE_ERROR, "ERR_SOCKET_SET_RECEIVE_BUFFER_SIZE_ERROR"},
110+ {ARKWEB_ERR_SOCKET_SET_SEND_BUFFER_SIZE_ERROR, "ERR_SOCKET_SET_SEND_BUFFER_SIZE_ERROR"},
111+ {ARKWEB_ERR_SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE, "ERR_SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE"},
112+ {ARKWEB_ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE, "ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE"},
113+ {ARKWEB_ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT, "ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT"},
114+ {ARKWEB_ERR_ICANN_NAME_COLLISION, "ERR_ICANN_NAME_COLLISION"},
115+ {ARKWEB_ERR_SSL_SERVER_CERT_BAD_FORMAT, "ERR_SSL_SERVER_CERT_BAD_FORMAT"},
116+ {ARKWEB_ERR_CT_STH_PARSING_FAILED, "ERR_CT_STH_PARSING_FAILED"},
117+ {ARKWEB_ERR_CT_STH_INCOMPLETE, "ERR_CT_STH_INCOMPLETE"},
118+ {ARKWEB_ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH, "ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH"},
119+ {ARKWEB_ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED, "ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED"},
120+ {ARKWEB_ERR_SSL_OBSOLETE_CIPHER, "ERR_SSL_OBSOLETE_CIPHER"},
121+ {ARKWEB_ERR_WS_UPGRADE, "ERR_WS_UPGRADE"},
122+ {ARKWEB_ERR_READ_IF_READY_NOT_IMPLEMENTED, "ERR_READ_IF_READY_NOT_IMPLEMENTED"},
123+ {ARKWEB_ERR_NO_BUFFER_SPACE, "ERR_NO_BUFFER_SPACE"},
124+ {ARKWEB_ERR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS, "ERR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS"},
125+ {ARKWEB_ERR_EARLY_DATA_REJECTED, "ERR_EARLY_DATA_REJECTED"},
126+ {ARKWEB_ERR_WRONG_VERSION_ON_EARLY_DATA, "ERR_WRONG_VERSION_ON_EARLY_DATA"},
127+ {ARKWEB_ERR_TLS13_DOWNGRADE_DETECTED, "ERR_TLS13_DOWNGRADE_DETECTED"},
128+ {ARKWEB_ERR_SSL_KEY_USAGE_INCOMPATIBLE, "ERR_SSL_KEY_USAGE_INCOMPATIBLE"},
129+ {ARKWEB_ERR_INVALID_ECH_CONFIG_LIST, "ERR_INVALID_ECH_CONFIG_LIST"},
130+ {ARKWEB_ERR_ECH_NOT_NEGOTIATED, "ERR_ECH_NOT_NEGOTIATED"},
131+ {ARKWEB_ERR_ECH_FALLBACK_CERTIFICATE_INVALID, "ERR_ECH_FALLBACK_CERTIFICATE_INVALID"},
132+ {ARKWEB_ERR_CERT_COMMON_NAME_INVALID, "ERR_CERT_COMMON_NAME_INVALID"},
133+ {ARKWEB_ERR_CERT_DATE_INVALID, "ERR_CERT_DATE_INVALID"},
134+ {ARKWEB_ERR_CERT_AUTHORITY_INVALID, "ERR_CERT_AUTHORITY_INVALID"},
135+ {ARKWEB_ERR_CERT_CONTAINS_ERRORS, "ERR_CERT_CONTAINS_ERRORS"},
136+ {ARKWEB_ERR_CERT_NO_REVOCATION_MECHANISM, "ERR_CERT_NO_REVOCATION_MECHANISM"},
137+ {ARKWEB_ERR_CERT_UNABLE_TO_CHECK_REVOCATION, "ERR_CERT_UNABLE_TO_CHECK_REVOCATION"},
138+ {ARKWEB_ERR_CERT_REVOKED, "ERR_CERT_REVOKED"},
139+ {ARKWEB_ERR_CERT_INVALID, "ERR_CERT_INVALID"},
140+ {ARKWEB_ERR_CERT_WEAK_SIGNATURE_ALGORITHM, "ERR_CERT_WEAK_SIGNATURE_ALGORITHM"},
141+ {ARKWEB_ERR_CERT_NON_UNIQUE_NAME, "ERR_CERT_NON_UNIQUE_NAME"},
142+ {ARKWEB_ERR_CERT_WEAK_KEY, "ERR_CERT_WEAK_KEY"},
143+ {ARKWEB_ERR_CERT_NAME_CONSTRAINT_VIOLATION, "ERR_CERT_NAME_CONSTRAINT_VIOLATION"},
144+ {ARKWEB_ERR_CERT_VALIDITY_TOO_LONG, "ERR_CERT_VALIDITY_TOO_LONG"},
145+ {ARKWEB_ERR_CERTIFICATE_TRANSPARENCY_REQUIRED, "ERR_CERTIFICATE_TRANSPARENCY_REQUIRED"},
146+ {ARKWEB_ERR_CERT_SYMANTEC_LEGACY, "ERR_CERT_SYMANTEC_LEGACY"},
147+ {ARKWEB_ERR_CERT_KNOWN_INTERCEPTION_BLOCKED, "ERR_CERT_KNOWN_INTERCEPTION_BLOCKED"},
148+ {ARKWEB_ERR_SSL_OBSOLETE_VERSION_OR_CIPHER, "ERR_SSL_OBSOLETE_VERSION_OR_CIPHER"},
149+ {ARKWEB_ERR_CERT_END, "ERR_CERT_END"},
150+ {ARKWEB_ERR_INVALID_URL, "ERR_INVALID_URL"},
151+ {ARKWEB_ERR_DISALLOWED_URL_SCHEME, "ERR_DISALLOWED_URL_SCHEME"},
152+ {ARKWEB_ERR_UNKNOWN_URL_SCHEME, "ERR_UNKNOWN_URL_SCHEME"},
153+ {ARKWEB_ERR_INVALID_REDIRECT, "ERR_INVALID_REDIRECT"},
154+ {ARKWEB_ERR_TOO_MANY_REDIRECTS, "ERR_TOO_MANY_REDIRECTS"},
155+ {ARKWEB_ERR_UNSAFE_REDIRECT, "ERR_UNSAFE_REDIRECT"},
156+ {ARKWEB_ERR_UNSAFE_PORT, "ERR_UNSAFE_PORT"},
157+ {ARKWEB_ERR_INVALID_RESPONSE, "ERR_INVALID_RESPONSE"},
158+ {ARKWEB_ERR_INVALID_CHUNKED_ENCODING, "ERR_INVALID_CHUNKED_ENCODING"},
159+ {ARKWEB_ERR_METHOD_UNSUPPORTED, "ERR_METHOD_UNSUPPORTED"},
160+ {ARKWEB_ERR_UNEXPECTED_PROXY_AUTH, "ERR_UNEXPECTED_PROXY_AUTH"},
161+ {ARKWEB_ERR_EMPTY_RESPONSE, "ERR_EMPTY_RESPONSE"},
162+ {ARKWEB_ERR_RESPONSE_HEADERS_TOO_BIG, "ERR_RESPONSE_HEADERS_TOO_BIG"},
163+ {ARKWEB_ERR_PAC_SCRIPT_FAILED, "ERR_PAC_SCRIPT_FAILED"},
164+ {ARKWEB_ERR_REQUEST_RANGE_NOT_SATISFIABLE, "ERR_REQUEST_RANGE_NOT_SATISFIABLE"},
165+ {ARKWEB_ERR_MALFORMED_IDENTITY, "ERR_MALFORMED_IDENTITY"},
166+ {ARKWEB_ERR_CONTENT_DECODING_FAILED, "ERR_CONTENT_DECODING_FAILED"},
167+ {ARKWEB_ERR_NETWORK_IO_SUSPENDED, "ERR_NETWORK_IO_SUSPENDED"},
168+ {ARKWEB_ERR_SYN_REPLY_NOT_RECEIVED, "ERR_SYN_REPLY_NOT_RECEIVED"},
169+ {ARKWEB_ERR_ENCODING_CONVERSION_FAILED, "ERR_ENCODING_CONVERSION_FAILED"},
170+ {ARKWEB_ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT, "ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT"},
171+ {ARKWEB_ERR_NO_SUPPORTED_PROXIES, "ERR_NO_SUPPORTED_PROXIES"},
172+ {ARKWEB_ERR_HTTP2_PROTOCOL_ERROR, "ERR_HTTP2_PROTOCOL_ERROR"},
173+ {ARKWEB_ERR_INVALID_AUTH_CREDENTIALS, "ERR_INVALID_AUTH_CREDENTIALS"},
174+ {ARKWEB_ERR_UNSUPPORTED_AUTH_SCHEME, "ERR_UNSUPPORTED_AUTH_SCHEME"},
175+ {ARKWEB_ERR_ENCODING_DETECTION_FAILED, "ERR_ENCODING_DETECTION_FAILED"},
176+ {ARKWEB_ERR_MISSING_AUTH_CREDENTIALS, "ERR_MISSING_AUTH_CREDENTIALS"},
177+ {ARKWEB_ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS, "ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS"},
178+ {ARKWEB_ERR_MISCONFIGURED_AUTH_ENVIRONMENT, "ERR_MISCONFIGURED_AUTH_ENVIRONMENT"},
179+ {ARKWEB_ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS, "ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS"},
180+ {ARKWEB_ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN, "ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN"},
181+ {ARKWEB_ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, "ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH"},
182+ {ARKWEB_ERR_INCOMPLETE_HTTP2_HEADERS, "ERR_INCOMPLETE_HTTP2_HEADERS"},
183+ {ARKWEB_ERR_PAC_NOT_IN_DHCP, "ERR_PAC_NOT_IN_DHCP"},
184+ {ARKWEB_ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, "ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION"},
185+ {ARKWEB_ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, "ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION"},
186+ {ARKWEB_ERR_HTTP2_SERVER_REFUSED_STREAM, "ERR_HTTP2_SERVER_REFUSED_STREAM"},
187+ {ARKWEB_ERR_HTTP2_PING_FAILED, "ERR_HTTP2_PING_FAILED"},
188+ {ARKWEB_ERR_CONTENT_LENGTH_MISMATCH, "ERR_CONTENT_LENGTH_MISMATCH"},
189+ {ARKWEB_ERR_INCOMPLETE_CHUNKED_ENCODING, "ERR_INCOMPLETE_CHUNKED_ENCODING"},
190+ {ARKWEB_ERR_QUIC_PROTOCOL_ERROR, "ERR_QUIC_PROTOCOL_ERROR"},
191+ {ARKWEB_ERR_RESPONSE_HEADERS_TRUNCATED, "ERR_RESPONSE_HEADERS_TRUNCATED"},
192+ {ARKWEB_ERR_QUIC_HANDSHAKE_FAILED, "ERR_QUIC_HANDSHAKE_FAILED"},
193+ {ARKWEB_ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY, "ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY"},
194+ {ARKWEB_ERR_HTTP2_FLOW_CONTROL_ERROR, "ERR_HTTP2_FLOW_CONTROL_ERROR"},
195+ {ARKWEB_ERR_HTTP2_FRAME_SIZE_ERROR, "ERR_HTTP2_FRAME_SIZE_ERROR"},
196+ {ARKWEB_ERR_HTTP2_COMPRESSION_ERROR, "ERR_HTTP2_COMPRESSION_ERROR"},
197+ {ARKWEB_ERR_PROXY_AUTH_REQUESTED_WITH_NO_CONNECTION, "ERR_PROXY_AUTH_REQUESTED_WITH_NO_CONNECTION"},
198+ {ARKWEB_ERR_HTTP_1_1_REQUIRED, "ERR_HTTP_1_1_REQUIRED"},
199+ {ARKWEB_ERR_PROXY_HTTP_1_1_REQUIRED, "ERR_PROXY_HTTP_1_1_REQUIRED"},
200+ {ARKWEB_ERR_PAC_SCRIPT_TERMINATED, "ERR_PAC_SCRIPT_TERMINATED"},
201+ {ARKWEB_ERR_INVALID_HTTP_RESPONSE, "ERR_INVALID_HTTP_RESPONSE"},
202+ {ARKWEB_ERR_CONTENT_DECODING_INIT_FAILED, "ERR_CONTENT_DECODING_INIT_FAILED"},
203+ {ARKWEB_ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED, "ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED"},
204+ {ARKWEB_ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE, "ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE"},
205+ {ARKWEB_ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER, "ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER"},
206+ {ARKWEB_ERR_TOO_MANY_RETRIES, "ERR_TOO_MANY_RETRIES"},
207+ {ARKWEB_ERR_HTTP2_STREAM_CLOSED, "ERR_HTTP2_STREAM_CLOSED"},
208+ {ARKWEB_ERR_HTTP2_CLIENT_REFUSED_STREAM, "ERR_HTTP2_CLIENT_REFUSED_STREAM"},
209+ {ARKWEB_ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH, "ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH"},
210+ {ARKWEB_ERR_HTTP_RESPONSE_CODE_FAILURE, "ERR_HTTP_RESPONSE_CODE_FAILURE"},
211+ {ARKWEB_ERR_QUIC_UNKNOWN_CERT_ROOT, "ERR_QUIC_UNKNOWN_CERT_ROOT"},
212+ {ARKWEB_ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED, "ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED"},
213+ {ARKWEB_ERR_TOO_MANY_ACCEPT_CH_RESTARTS, "ERR_TOO_MANY_ACCEPT_CH_RESTARTS"},
214+ {ARKWEB_ERR_INCONSISTENT_IP_ADDRESS_SPACE, "ERR_INCONSISTENT_IP_ADDRESS_SPACE"},
215+ {ARKWEB_ERR_CACHED_IP_ADDRESS_SPACE_BLOCKED_BY_LOCAL_NETWORK_ACCESS_POLICY,
216+ "ERR_CACHED_IP_ADDRESS_SPACE_BLOCKED_BY_LOCAL_NETWORK_ACCESS_POLICY"},
217+ {ARKWEB_ERR_CACHE_MISS, "ERR_CACHE_MISS"},
218+ {ARKWEB_ERR_CACHE_READ_FAILURE, "ERR_CACHE_READ_FAILURE"},
219+ {ARKWEB_ERR_CACHE_WRITE_FAILURE, "ERR_CACHE_WRITE_FAILURE"},
220+ {ARKWEB_ERR_CACHE_OPERATION_UNSUPPORTED, "ERR_CACHE_OPERATION_UNSUPPORTED"},
221+ {ARKWEB_ERR_CACHE_OPEN_FAILURE, "ERR_CACHE_OPEN_FAILURE"},
222+ {ARKWEB_ERR_CACHE_CREATE_FAILURE, "ERR_CACHE_CREATE_FAILURE"},
223+ {ARKWEB_ERR_CACHE_RACE, "ERR_CACHE_RACE"},
224+ {ARKWEB_ERR_CACHE_CHECKSUM_READ_FAILURE, "ERR_CACHE_CHECKSUM_READ_FAILURE"},
225+ {ARKWEB_ERR_CACHE_CHECKSUM_MISMATCH, "ERR_CACHE_CHECKSUM_MISMATCH"},
226+ {ARKWEB_ERR_CACHE_LOCK_TIMEOUT, "ERR_CACHE_LOCK_TIMEOUT"},
227+ {ARKWEB_ERR_CACHE_AUTH_FAILURE_AFTER_READ, "ERR_CACHE_AUTH_FAILURE_AFTER_READ"},
228+ {ARKWEB_ERR_CACHE_ENTRY_NOT_SUITABLE, "ERR_CACHE_ENTRY_NOT_SUITABLE"},
229+ {ARKWEB_ERR_CACHE_DOOM_FAILURE, "ERR_CACHE_DOOM_FAILURE"},
230+ {ARKWEB_ERR_CACHE_OPEN_OR_CREATE_FAILURE, "ERR_CACHE_OPEN_OR_CREATE_FAILURE"},
231+ {ARKWEB_ERR_INSECURE_RESPONSE, "ERR_INSECURE_RESPONSE"},
232+ {ARKWEB_ERR_NO_PRIVATE_KEY_FOR_CERT, "ERR_NO_PRIVATE_KEY_FOR_CERT"},
233+ {ARKWEB_ERR_ADD_USER_CERT_FAILED, "ERR_ADD_USER_CERT_FAILED"},
234+ {ARKWEB_ERR_INVALID_SIGNED_EXCHANGE, "ERR_INVALID_SIGNED_EXCHANGE"},
235+ {ARKWEB_ERR_INVALID_WEB_BUNDLE, "ERR_INVALID_WEB_BUNDLE"},
236+ {ARKWEB_ERR_TRUST_TOKEN_OPERATION_FAILED, "ERR_TRUST_TOKEN_OPERATION_FAILED"},
237+ {ARKWEB_ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST,
238+ "ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST"},
239+ {ARKWEB_ERR_FTP_FAILED, "ERR_FTP_FAILED"},
240+ {ARKWEB_ERR_FTP_SERVICE_UNAVAILABLE, "ERR_FTP_SERVICE_UNAVAILABLE"},
241+ {ARKWEB_ERR_FTP_TRANSFER_ABORTED, "ERR_FTP_TRANSFER_ABORTED"},
242+ {ARKWEB_ERR_FTP_FILE_BUSY, "ERR_FTP_FILE_BUSY"},
243+ {ARKWEB_ERR_FTP_SYNTAX_ERROR, "ERR_FTP_SYNTAX_ERROR"},
244+ {ARKWEB_ERR_FTP_COMMAND_UNSUPPORTED, "ERR_FTP_COMMAND_UNSUPPORTED"},
245+ {ARKWEB_ERR_FTP_BAD_COMMAND_SEQUENCE, "ERR_FTP_BAD_COMMAND_SEQUENCE"},
246+ {ARKWEB_ERR_PKCS12_IMPORT_BAD_PASSWORD, "ERR_PKCS12_IMPORT_BAD_PASSWORD"},
247+ {ARKWEB_ERR_PKCS12_IMPORT_FAILED, "ERR_PKCS12_IMPORT_FAILED"},
248+ {ARKWEB_ERR_IMPORT_CA_CERT_NOT_CA, "ERR_IMPORT_CA_CERT_NOT_CA"},
249+ {ARKWEB_ERR_IMPORT_CERT_ALREADY_EXISTS, "ERR_IMPORT_CERT_ALREADY_EXISTS"},
250+ {ARKWEB_ERR_IMPORT_CA_CERT_FAILED, "ERR_IMPORT_CA_CERT_FAILED"},
251+ {ARKWEB_ERR_IMPORT_SERVER_CERT_FAILED, "ERR_IMPORT_SERVER_CERT_FAILED"},
252+ {ARKWEB_ERR_PKCS12_IMPORT_INVALID_MAC, "ERR_PKCS12_IMPORT_INVALID_MAC"},
253+ {ARKWEB_ERR_PKCS12_IMPORT_INVALID_FILE, "ERR_PKCS12_IMPORT_INVALID_FILE"},
254+ {ARKWEB_ERR_PKCS12_IMPORT_UNSUPPORTED, "ERR_PKCS12_IMPORT_UNSUPPORTED"},
255+ {ARKWEB_ERR_KEY_GENERATION_FAILED, "ERR_KEY_GENERATION_FAILED"},
256+ {ARKWEB_ERR_PRIVATE_KEY_EXPORT_FAILED, "ERR_PRIVATE_KEY_EXPORT_FAILED"},
257+ {ARKWEB_ERR_SELF_SIGNED_CERT_GENERATION_FAILED, "ERR_SELF_SIGNED_CERT_GENERATION_FAILED"},
258+ {ARKWEB_ERR_CERT_DATABASE_CHANGED, "ERR_CERT_DATABASE_CHANGED"},
259+ {ARKWEB_ERR_CERT_VERIFIER_CHANGED, "ERR_CERT_VERIFIER_CHANGED"},
260+ {ARKWEB_ERR_DNS_MALFORMED_RESPONSE, "ERR_DNS_MALFORMED_RESPONSE"},
261+ {ARKWEB_ERR_DNS_SERVER_REQUIRES_TCP, "ERR_DNS_SERVER_REQUIRES_TCP"},
262+ {ARKWEB_ERR_DNS_SERVER_FAILED, "ERR_DNS_SERVER_FAILED"},
263+ {ARKWEB_ERR_DNS_TIMED_OUT, "ERR_DNS_TIMED_OUT"},
264+ {ARKWEB_ERR_DNS_CACHE_MISS, "ERR_DNS_CACHE_MISS"},
265+ {ARKWEB_ERR_DNS_SEARCH_EMPTY, "ERR_DNS_SEARCH_EMPTY"},
266+ {ARKWEB_ERR_DNS_SORT_ERROR, "ERR_DNS_SORT_ERROR"},
267+ {ARKWEB_ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED, "ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED"},
268+ {ARKWEB_ERR_DNS_NAME_HTTPS_ONLY, "ERR_DNS_NAME_HTTPS_ONLY"},
269+ {ARKWEB_ERR_DNS_REQUEST_CANCELED, "ERR_DNS_REQUEST_CANCELED"},
270+ {ARKWEB_ERR_DNS_NO_MATCHING_SUPPORTED_ALPN, "ERR_DNS_NO_MATCHING_SUPPORTED_ALPN"}
271+};
272+ 
273+struct NetErrorInfo {
274+ bool isValid;
275+ std::string errorName;
276+ 
277+ explicit NetErrorInfo(bool valid = false, const std::string& name = "") : isValid(valid), errorName(name) {}
278+};
279+ 
280+NetErrorInfo ValidateAndGetNetErrorName(int32_t code)
281+{
282+ auto it = g_netErrorCodeMap.find(code);
283+ if (it != g_netErrorCodeMap.end()) {
284+ return NetErrorInfo(true, it->second);
285+ }
286+ return NetErrorInfo(false, "UNKNOWN_ERROR_CODE");
287+}
288+ 
289+napi_value NapiWebSchemeHandlerRequest::Init(napi_env env, napi_value exports)
290+{
291+ ExportWebSchemeHandlerRequestClass(env, &exports);
292+ return exports;
293+}
294+ 
295+void NapiWebSchemeHandlerRequest::ExportWebSchemeHandlerRequestClass(napi_env env, napi_value* exportsPointer)
jinpeng0804
jinpeng0804jinpeng08042025年10月13日

与下面DefineProperties函数中定义的一致?考虑合并

likedislike
quguiren
2025年10月14日 评论:
296+{
297+ napi_property_descriptor properties[] = {
298+ DECLARE_NAPI_FUNCTION("getHeader", JS_GetHeader),
299+ DECLARE_NAPI_FUNCTION("getRequestUrl", JS_GetRequestUrl),
300+ DECLARE_NAPI_FUNCTION("getRequestMethod", JS_GetRequestMethod),
301+ DECLARE_NAPI_FUNCTION("getReferrer", JS_GetReferrer),
302+ DECLARE_NAPI_FUNCTION("isRedirect", JS_IsRedirect),
303+ DECLARE_NAPI_FUNCTION("isMainFrame", JS_IsMainFrame),
304+ DECLARE_NAPI_FUNCTION("hasGesture", JS_HasGesture),
305+ DECLARE_NAPI_FUNCTION("getHttpBodyStream", JS_HttpBodyStream),
306+ DECLARE_NAPI_FUNCTION("getRequestResourceType", JS_GetRequestResourceType),
307+ DECLARE_NAPI_FUNCTION("getFrameUrl", JS_GetFrameUrl),
308+ };
309+ napi_value webSchemeHandlerRequest = nullptr;
310+ napi_define_class(env, WEB_SCHEME_HANDLER_REQUEST.c_str(), WEB_SCHEME_HANDLER_REQUEST.length(), JS_Constructor,
311+ nullptr, sizeof(properties) / sizeof(properties[0]), properties, &webSchemeHandlerRequest);
312+ napi_set_named_property(env, *exportsPointer, WEB_SCHEME_HANDLER_REQUEST.c_str(), webSchemeHandlerRequest);
313+}
314+ 
315+napi_status NapiWebSchemeHandlerRequest::DefineProperties(napi_env env, napi_value* object)
316+{
317+ napi_property_descriptor properties[] = {
318+ DECLARE_NAPI_FUNCTION("getHeader", JS_GetHeader),
319+ DECLARE_NAPI_FUNCTION("getRequestUrl", JS_GetRequestUrl),
320+ DECLARE_NAPI_FUNCTION("getRequestMethod", JS_GetRequestMethod),
321+ DECLARE_NAPI_FUNCTION("getReferrer", JS_GetReferrer),
322+ DECLARE_NAPI_FUNCTION("isRedirect", JS_IsRedirect),
323+ DECLARE_NAPI_FUNCTION("isMainFrame", JS_IsMainFrame),
324+ DECLARE_NAPI_FUNCTION("hasGesture", JS_HasGesture),
325+ DECLARE_NAPI_FUNCTION("getHttpBodyStream", JS_HttpBodyStream),
326+ DECLARE_NAPI_FUNCTION("getRequestResourceType", JS_GetRequestResourceType),
327+ DECLARE_NAPI_FUNCTION("getFrameUrl", JS_GetFrameUrl),
328+ };
329+ return napi_define_properties(env, *object, sizeof(properties) / sizeof(properties[0]), properties);
330+}
331+ 
332+napi_value NapiWebSchemeHandlerRequest::JS_Constructor(napi_env env, napi_callback_info cbinfo)
333+{
334+ napi_value thisVar = nullptr;
335+ void* data = nullptr;
336+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
337+ 
338+ WebSchemeHandlerRequest* request = new (std::nothrow) WebSchemeHandlerRequest(env);
339+ if (request == nullptr) {
340+ return nullptr;
341+ }
342+ 
343+ napi_wrap(
344+ env, thisVar, request,
345+ [](napi_env /* env */, void* data, void* /* hint */) {
346+ WebSchemeHandlerRequest* request = reinterpret_cast<WebSchemeHandlerRequest*>(data);
347+ delete request;
348+ },
349+ nullptr, nullptr);
350+ 
351+ return thisVar;
352+}
353+ 
354+napi_value NapiWebSchemeHandlerRequest::JS_GetHeader(napi_env env, napi_callback_info cbinfo)
355+{
356+ napi_value thisVar = nullptr;
357+ void* data = nullptr;
358+ WebSchemeHandlerRequest* request = nullptr;
359+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
360+ 
361+ napi_unwrap(env, thisVar, (void**)&request);
362+ if (!request) {
363+ LOGE("NapiWebSchemeHandlerRequest::JS_GetHeader request is nullptr");
364+ return nullptr;
365+ }
366+ 
367+ napi_handle_scope scope;
368+ napi_status status_scope = napi_open_handle_scope(env, &scope);
369+ if (status_scope != napi_ok) {
370+ LOGE("scheme handler RequestStart scope is nullptr");
371+ return nullptr;
372+ }
373+ WebHeaderList list = request->GetHeaderList();
374+ napi_value result = nullptr;
375+ napi_create_array(env, &result);
376+ size_t headerSize = list.size();
377+ for (size_t index = 0; index < headerSize; index++) {
378+ napi_value webHeaderObj = nullptr;
379+ napi_value headerKey = nullptr;
380+ napi_value headerValue = nullptr;
381+ NAPI_CALL(env, napi_create_object(env, &webHeaderObj));
382+ napi_create_string_utf8(env, list[index].first.c_str(), NAPI_AUTO_LENGTH, &headerKey);
383+ napi_create_string_utf8(env, list[index].second.c_str(), NAPI_AUTO_LENGTH, &headerValue);
384+ napi_set_named_property(env, webHeaderObj, "headerKey", headerKey);
385+ napi_set_named_property(env, webHeaderObj, "headerValue", headerValue);
386+ napi_set_element(env, result, index, webHeaderObj);
387+ }
388+ napi_close_handle_scope(env, scope);
389+ return result;
390+}
391+ 
392+napi_value NapiWebSchemeHandlerRequest::JS_GetRequestUrl(napi_env env, napi_callback_info cbinfo)
393+{
394+ napi_value thisVar = nullptr;
395+ void* data = nullptr;
396+ WebSchemeHandlerRequest* request = nullptr;
397+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
398+ 
399+ napi_unwrap(env, thisVar, (void**)&request);
400+ if (!request) {
401+ LOGE("NapiWebSchemeHandlerRequest::JS_GetRequestUrl request is nullptr");
402+ return nullptr;
403+ }
404+ 
405+ napi_value value;
406+ napi_status status = napi_create_string_utf8(env, request->GetUrl().c_str(), NAPI_AUTO_LENGTH, &value);
407+ if (status != napi_ok) {
408+ LOGE("NapiWebSchemeHandlerRequest::JS_GetRequestUrl response get url failed");
409+ return nullptr;
410+ }
411+ return value;
412+}
413+ 
414+napi_value NapiWebSchemeHandlerRequest::JS_GetRequestMethod(napi_env env, napi_callback_info cbinfo)
415+{
416+ napi_value thisVar = nullptr;
417+ void* data = nullptr;
418+ WebSchemeHandlerRequest* request = nullptr;
419+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
420+ 
421+ napi_unwrap(env, thisVar, (void**)&request);
422+ if (!request) {
423+ LOGE("NapiWebSchemeHandlerRequest::JS_GetRequestMethod request is nullptr");
424+ return nullptr;
425+ }
426+ 
427+ napi_value value;
428+ napi_status status = napi_create_string_utf8(env, request->GetMethod().c_str(), NAPI_AUTO_LENGTH, &value);
429+ if (status != napi_ok) {
430+ LOGE("NapiWebSchemeHandlerRequest::JS_GetRequestMethod response get url failed");
431+ return nullptr;
432+ }
433+ return value;
434+}
435+ 
436+napi_value NapiWebSchemeHandlerRequest::JS_GetReferrer(napi_env env, napi_callback_info cbinfo)
437+{
438+ napi_value thisVar = nullptr;
439+ void* data = nullptr;
440+ WebSchemeHandlerRequest* request = nullptr;
441+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
442+ 
443+ napi_unwrap(env, thisVar, (void**)&request);
444+ if (!request) {
445+ LOGE("NapiWebSchemeHandlerRequest::JS_GetReferrer request is nullptr");
446+ return nullptr;
447+ }
448+ 
449+ napi_value value;
450+ napi_status status = napi_create_string_utf8(env, request->GetReferrer().c_str(), NAPI_AUTO_LENGTH, &value);
451+ if (status != napi_ok) {
452+ LOGE("NapiWebSchemeHandlerRequest::JS_GetReferrer response get url failed");
453+ return nullptr;
454+ }
455+ return value;
456+}
457+ 
458+napi_value NapiWebSchemeHandlerRequest::JS_IsRedirect(napi_env env, napi_callback_info cbinfo)
459+{
460+ napi_value thisVar = nullptr;
461+ void* data = nullptr;
462+ WebSchemeHandlerRequest* request = nullptr;
463+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
464+ 
465+ napi_unwrap(env, thisVar, (void**)&request);
466+ if (!request) {
467+ LOGE("NapiWebSchemeHandlerRequest::JS_IsRedirect request is nullptr");
468+ return nullptr;
469+ }
470+ 
471+ napi_value value;
472+ NAPI_CALL(env, napi_get_boolean(env, request->GetIsRedirect(), &value));
473+ return value;
474+}
475+ 
476+napi_value NapiWebSchemeHandlerRequest::JS_IsMainFrame(napi_env env, napi_callback_info cbinfo)
477+{
478+ napi_value thisVar = nullptr;
479+ void* data = nullptr;
480+ WebSchemeHandlerRequest* request = nullptr;
481+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
482+ 
483+ napi_unwrap(env, thisVar, (void**)&request);
484+ if (!request) {
485+ LOGE("NapiWebSchemeHandlerRequest::JS_IsMainFrame request is nullptr");
486+ return nullptr;
487+ }
488+ 
489+ napi_value value;
490+ NAPI_CALL(env, napi_get_boolean(env, request->GetIsMainFrame(), &value));
491+ return value;
492+}
493+ 
494+napi_value NapiWebSchemeHandlerRequest::JS_HasGesture(napi_env env, napi_callback_info cbinfo)
495+{
496+ napi_value thisVar = nullptr;
497+ void* data = nullptr;
498+ WebSchemeHandlerRequest* request = nullptr;
499+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
500+ 
501+ napi_unwrap(env, thisVar, (void**)&request);
502+ if (!request) {
503+ LOGE("NapiWebSchemeHandlerRequest::JS_HasGesture request is nullptr");
504+ return nullptr;
505+ }
506+ 
507+ napi_value value;
508+ NAPI_CALL(env, napi_get_boolean(env, request->GetHasGesture(), &value));
509+ napi_get_undefined(env, &value);
510+ return value;
511+}
512+ 
513+napi_value NapiWebSchemeHandlerRequest::JS_HttpBodyStream(napi_env env, napi_callback_info cbinfo)
514+{
515+ napi_value value = nullptr;
516+ napi_get_undefined(env, &value);
517+ return value;
518+}
519+ 
520+napi_value NapiWebSchemeHandlerRequest::JS_GetRequestResourceType(napi_env env, napi_callback_info cbinfo)
521+{
522+ napi_value thisVar = nullptr;
523+ void* data = nullptr;
524+ WebSchemeHandlerRequest* request = nullptr;
525+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
526+ 
527+ napi_unwrap(env, thisVar, (void**)&request);
528+ if (!request) {
529+ LOGE("NapiWebSchemeHandlerRequest::JS_GetRequestResourceType request is nullptr");
530+ return nullptr;
531+ }
532+ 
533+ napi_value value;
534+ napi_create_int32(env, request->GetRequestResourceType(), &value);
535+ return value;
536+}
537+ 
538+napi_value NapiWebSchemeHandlerRequest::JS_GetFrameUrl(napi_env env, napi_callback_info cbinfo)
539+{
540+ napi_value thisVar = nullptr;
541+ void* data = nullptr;
542+ WebSchemeHandlerRequest* request = nullptr;
543+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
544+ 
545+ napi_unwrap(env, thisVar, (void**)&request);
546+ if (!request) {
547+ LOGE("NapiWebSchemeHandlerRequest::JS_GetFrameUrl request is nullptr");
548+ return nullptr;
549+ }
550+ 
551+ napi_value value;
552+ napi_status status = napi_create_string_utf8(env, request->GetFrameUrl().c_str(), NAPI_AUTO_LENGTH, &value);
553+ if (status != napi_ok) {
554+ LOGE("NapiWebSchemeHandlerRequest::JS_GetFrameUrl response get frame url failed");
555+ return nullptr;
556+ }
557+ return value;
558+}
559+ 
560+napi_status NapiWebSchemeHandlerRequest::ExportEnumWebResourceType(napi_env env, napi_value* value)
561+{
562+ napi_value enumValue = nullptr;
563+ const std::string napiWebResourceTypeEnumName = "WebResourceType";
564+ return napi_set_named_property(env, *value, napiWebResourceTypeEnumName.c_str(), enumValue);
565+}
566+ 
567+napi_value NapiWebSchemeHandlerResponse::Init(napi_env env, napi_value exports)
568+{
569+ ExportWebSchemeHandlerResponseClass(env, &exports);
570+ return exports;
571+}
572+ 
573+void NapiWebSchemeHandlerResponse::ExportWebSchemeHandlerResponseClass(napi_env env, napi_value* exportsPointer)
574+{
575+ napi_property_descriptor properties[] = {
576+ DECLARE_NAPI_FUNCTION("getUrl", JS_GetUrl),
577+ DECLARE_NAPI_FUNCTION("setUrl", JS_SetUrl),
578+ DECLARE_NAPI_FUNCTION("getStatus", JS_GetStatus),
579+ DECLARE_NAPI_FUNCTION("setStatus", JS_SetStatus),
580+ DECLARE_NAPI_FUNCTION("getStatusText", JS_GetStatusText),
581+ DECLARE_NAPI_FUNCTION("setStatusText", JS_SetStatusText),
582+ DECLARE_NAPI_FUNCTION("getMimeType", JS_GetMimeType),
583+ DECLARE_NAPI_FUNCTION("setMimeType", JS_SetMimeType),
584+ DECLARE_NAPI_FUNCTION("getEncoding", JS_GetEncoding),
585+ DECLARE_NAPI_FUNCTION("setEncoding", JS_SetEncoding),
586+ DECLARE_NAPI_FUNCTION("getHeaderByName", JS_GetHeaderByName),
587+ DECLARE_NAPI_FUNCTION("setHeaderByName", JS_SetHeaderByName),
588+ DECLARE_NAPI_FUNCTION("getNetErrorCode", JS_GetNetErrorCode),
589+ DECLARE_NAPI_FUNCTION("setNetErrorCode", JS_SetNetErrorCode),
590+ };
591+ napi_value webSchemeHandlerResponse = nullptr;
592+ napi_define_class(env, WEB_SCHEME_HANDLER_RESPONSE.c_str(), WEB_SCHEME_HANDLER_RESPONSE.length(), JS_Constructor,
593+ nullptr, sizeof(properties) / sizeof(properties[0]), properties, &webSchemeHandlerResponse);
594+ napi_set_named_property(env, *exportsPointer, WEB_SCHEME_HANDLER_RESPONSE.c_str(), webSchemeHandlerResponse);
595+}
596+ 
597+napi_value NapiWebSchemeHandlerResponse::JS_Constructor(napi_env env, napi_callback_info cbinfo)
598+{
599+ napi_value thisVar = nullptr;
600+ void* data = nullptr;
601+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, &data);
602+ 
603+ WebSchemeHandlerResponse* response = new (std::nothrow) WebSchemeHandlerResponse(env);
604+ if (response == nullptr) {
605+ LOGE("NapiWebSchemeHandlerResponse::JS_Constructor response is nullptr");
606+ NAPI_CALL(env, napi_get_undefined(env, &thisVar));
607+ return thisVar;
608+ }
609+ 
610+ napi_wrap(
611+ env, thisVar, response,
612+ [](napi_env /* env */, void* data, void* /* hint */) {
613+ WebSchemeHandlerResponse* response = (WebSchemeHandlerResponse*)data;
614+ delete response;
615+ },
616+ nullptr, nullptr);
617+ 
618+ return thisVar;
619+}
620+ 
621+napi_value NapiWebSchemeHandlerResponse::JS_GetUrl(napi_env env, napi_callback_info cbinfo)
622+{
623+ size_t argc = 1;
624+ napi_value argv[1] = { 0 };
625+ napi_value thisVar = nullptr;
626+ void* data = nullptr;
627+ WebSchemeHandlerResponse* response = nullptr;
628+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
629+ 
630+ napi_unwrap(env, thisVar, (void**)&response);
631+ if (!response) {
632+ LOGE("NapiWebSchemeHandlerResponse::JS_GetUrl response is nullptr");
633+ return nullptr;
634+ }
635+ 
636+ napi_value urlValue;
637+ napi_status status = napi_create_string_utf8(env, response->GetUrl().c_str(), NAPI_AUTO_LENGTH, &urlValue);
638+ if (status != napi_ok) {
639+ LOGE("NapiWebSchemeHandlerResponse::JS_GetUrl response get url failed");
640+ return nullptr;
641+ }
642+ return urlValue;
643+}
644+ 
645+napi_value NapiWebSchemeHandlerResponse::JS_SetUrl(napi_env env, napi_callback_info cbinfo)
646+{
647+ size_t argc = 1;
648+ napi_value argv[1] = { 0 };
649+ napi_value thisVar = nullptr;
650+ void* data = nullptr;
651+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
652+ 
653+ WebSchemeHandlerResponse* response = nullptr;
654+ napi_unwrap(env, thisVar, (void**)&response);
655+ 
656+ if (!response) {
657+ LOGE("unwrap WebSchemeHandlerResponse failed");
658+ return nullptr;
659+ }
660+ std::string url = "";
661+ if (!NapiParseUtils::ParseString(env, argv[0], url)) {
662+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
663+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "url", "string"));
664+ return nullptr;
665+ }
666+ response->SetUrl(url);
667+ return nullptr;
668+}
669+ 
670+napi_value NapiWebSchemeHandlerResponse::JS_GetStatus(napi_env env, napi_callback_info cbinfo)
671+{
672+ size_t argc = 1;
673+ napi_value argv[1] = { 0 };
674+ napi_value thisVar = nullptr;
675+ void* data = nullptr;
676+ WebSchemeHandlerResponse* response = nullptr;
677+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
678+ 
679+ napi_unwrap(env, thisVar, (void**)&response);
680+ if (!response) {
681+ LOGE("NapiWebSchemeHandlerResponse::JS_GetStatus response is nullptr");
682+ return nullptr;
683+ }
684+ 
685+ napi_value status;
686+ napi_create_int32(env, response->GetStatus(), &status);
687+ return status;
688+}
689+ 
690+napi_value NapiWebSchemeHandlerResponse::JS_SetStatus(napi_env env, napi_callback_info cbinfo)
691+{
692+ size_t argc = 1;
693+ napi_value argv[1] = { 0 };
694+ napi_value thisVar = nullptr;
695+ void* data = nullptr;
696+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
697+ 
698+ WebSchemeHandlerResponse* response = nullptr;
699+ napi_unwrap(env, thisVar, (void**)&response);
700+ 
701+ if (!response) {
702+ LOGE("unwrap WebSchemeHandlerResponse failed");
703+ return nullptr;
704+ }
705+ int32_t status = 0;
706+ if (!NapiParseUtils::ParseInt32(env, argv[0], status)) {
707+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
708+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "code", "int"));
709+ LOGE("NapiWebSchemeHandlerResponse::JS_SetStatus parse failed");
710+ return nullptr;
711+ }
712+ response->SetStatus(status);
713+ return nullptr;
714+}
715+ 
716+napi_value NapiWebSchemeHandlerResponse::JS_GetStatusText(napi_env env, napi_callback_info cbinfo)
717+{
718+ size_t argc = 1;
719+ napi_value argv[1] = { 0 };
720+ napi_value thisVar = nullptr;
721+ void* data = nullptr;
722+ WebSchemeHandlerResponse* response = nullptr;
723+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
724+ 
725+ napi_unwrap(env, thisVar, (void**)&response);
726+ if (!response) {
727+ LOGE("NapiWebSchemeHandlerResponse::JS_GetStatusText response is nullptr");
728+ return nullptr;
729+ }
730+ 
731+ napi_value statusText;
732+ napi_status status = napi_create_string_utf8(env, response->GetStatusText().c_str(), NAPI_AUTO_LENGTH, &statusText);
733+ if (status != napi_ok) {
734+ LOGE("NapiWebSchemeHandlerResponse::JS_GetStatusText response get failed");
735+ return nullptr;
736+ }
737+ return statusText;
738+}
739+ 
740+napi_value NapiWebSchemeHandlerResponse::JS_SetStatusText(napi_env env, napi_callback_info cbinfo)
741+{
742+ size_t argc = 1;
743+ napi_value argv[1] = { 0 };
744+ napi_value thisVar = nullptr;
745+ void* data = nullptr;
746+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
747+ 
748+ WebSchemeHandlerResponse* response = nullptr;
749+ napi_unwrap(env, thisVar, (void**)&response);
750+ 
751+ if (!response) {
752+ LOGE("unwrap WebSchemeHandlerResponse failed");
753+ return nullptr;
754+ }
755+ std::string statusText = "";
756+ if (!NapiParseUtils::ParseString(env, argv[0], statusText)) {
757+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
758+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "text", "string"));
759+ return nullptr;
760+ }
761+ response->SetStatusText(statusText);
762+ return nullptr;
763+}
764+ 
765+napi_value NapiWebSchemeHandlerResponse::JS_GetMimeType(napi_env env, napi_callback_info cbinfo)
766+{
767+ size_t argc = 1;
768+ napi_value argv[1] = { 0 };
769+ napi_value thisVar = nullptr;
770+ void* data = nullptr;
771+ WebSchemeHandlerResponse* response = nullptr;
772+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
773+ 
774+ napi_unwrap(env, thisVar, (void**)&response);
775+ if (!response) {
776+ LOGE("NapiWebSchemeHandlerResponse::JS_GetMimeType response is nullptr");
777+ return nullptr;
778+ }
779+ 
780+ napi_value mimeType;
781+ napi_status status = napi_create_string_utf8(env, response->GetMimeType().c_str(), NAPI_AUTO_LENGTH, &mimeType);
782+ if (status != napi_ok) {
783+ LOGE("NapiWebSchemeHandlerResponse::JS_GetMimeType response get failed");
784+ return nullptr;
785+ }
786+ return mimeType;
787+}
788+ 
789+napi_value NapiWebSchemeHandlerResponse::JS_SetMimeType(napi_env env, napi_callback_info cbinfo)
790+{
791+ size_t argc = 1;
792+ napi_value argv[1] = { 0 };
793+ napi_value thisVar = nullptr;
794+ void* data = nullptr;
795+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
796+ WebSchemeHandlerResponse* response = nullptr;
797+ napi_unwrap(env, thisVar, (void**)&response);
798+ 
799+ if (!response) {
800+ LOGE("unwrap WebSchemeHandlerResponse failed");
801+ return nullptr;
802+ }
803+ std::string mimeType = "";
804+ if (!NapiParseUtils::ParseString(env, argv[0], mimeType)) {
805+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
806+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "type", "string"));
807+ return nullptr;
808+ }
809+ response->SetMimeType(mimeType);
810+ return nullptr;
811+}
812+ 
813+napi_value NapiWebSchemeHandlerResponse::JS_GetEncoding(napi_env env, napi_callback_info cbinfo)
814+{
815+ size_t argc = 1;
816+ napi_value argv[1] = { 0 };
817+ napi_value thisVar = nullptr;
818+ void* data = nullptr;
819+ WebSchemeHandlerResponse* response = nullptr;
820+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
821+ 
822+ napi_unwrap(env, thisVar, (void**)&response);
823+ if (!response) {
824+ LOGE("NapiWebSchemeHandlerResponse::JS_GetEncoding response is nullptr");
825+ return nullptr;
826+ }
827+ 
828+ napi_value encoding;
829+ napi_status status = napi_create_string_utf8(env, response->GetEncoding().c_str(), NAPI_AUTO_LENGTH, &encoding);
830+ if (status != napi_ok) {
831+ LOGE("NapiWebSchemeHandlerResponse::JS_GetEncoding response get failed");
832+ return nullptr;
833+ }
834+ return encoding;
835+}
836+ 
837+napi_value NapiWebSchemeHandlerResponse::JS_SetEncoding(napi_env env, napi_callback_info cbinfo)
838+{
839+ size_t argc = 1;
840+ napi_value argv[1] = { 0 };
841+ napi_value thisVar = nullptr;
842+ void* data = nullptr;
843+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
844+ 
845+ WebSchemeHandlerResponse* response = nullptr;
846+ napi_unwrap(env, thisVar, (void**)&response);
847+ 
848+ if (!response) {
849+ LOGE("unwrap WebSchemeHandlerResponse failed");
850+ return nullptr;
851+ }
852+ std::string encoding = "";
853+ if (!NapiParseUtils::ParseString(env, argv[0], encoding)) {
854+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
855+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "encoding", "string"));
856+ return nullptr;
857+ }
858+ response->SetEncoding(encoding);
859+ return nullptr;
860+}
861+ 
862+napi_value NapiWebSchemeHandlerResponse::JS_GetHeaderByName(napi_env env, napi_callback_info cbinfo)
863+{
864+ size_t argc = 1;
865+ napi_value argv[1] = { 0 };
866+ napi_value thisVar = nullptr;
867+ void* data = nullptr;
868+ WebSchemeHandlerResponse* response = nullptr;
869+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
870+ 
871+ napi_unwrap(env, thisVar, (void**)&response);
872+ if (!response) {
873+ LOGE("NapiWebSchemeHandlerResponse::JS_GetHeaderByName response is nullptr");
874+ return nullptr;
875+ }
876+ 
877+ std::string name;
878+ if (!NapiParseUtils::ParseString(env, argv[0], name)) {
879+ return nullptr;
880+ }
881+ 
882+ napi_value headerValue;
883+ std::string value = response->GetHeaderByName(name);
884+ napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &headerValue);
885+ if (status != napi_ok) {
886+ LOGE("NapiWebSchemeHandlerResponse::JS_GetHeaderByName response get failed");
887+ return nullptr;
888+ }
889+ return headerValue;
890+}
891+ 
892+napi_value NapiWebSchemeHandlerResponse::JS_SetHeaderByName(napi_env env, napi_callback_info cbinfo)
893+{
894+ size_t argc = INTEGER_THREE;
895+ napi_value argv[INTEGER_THREE] = { 0 };
896+ napi_value thisVar = nullptr;
897+ void* data = nullptr;
898+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
899+ 
900+ WebSchemeHandlerResponse* response = nullptr;
901+ napi_unwrap(env, thisVar, (void**)&response);
902+ 
903+ if (!response) {
904+ LOGE("unwrap WebSchemeHandlerResponse failed");
905+ return nullptr;
906+ }
907+ std::string name;
908+ std::string value;
909+ bool overwrite = false;
910+ if (argc != INTEGER_THREE) {
911+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
912+ NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_ONE, "three"));
913+ LOGE("NapiWebSchemeHandlerResponse::JS_SetHeaderByName parse failed");
914+ return nullptr;
915+ }
916+ if (!NapiParseUtils::ParseString(env, argv[INTEGER_ZERO], name)) {
917+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
918+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "name", "string"));
919+ LOGE("NapiWebSchemeHandlerResponse::JS_SetHeaderByName parse failed");
920+ return nullptr;
921+ }
922+ if (!NapiParseUtils::ParseString(env, argv[INTEGER_ONE], value)) {
923+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
924+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "value", "string"));
925+ LOGE("NapiWebSchemeHandlerResponse::JS_SetHeaderByName parse failed");
926+ return nullptr;
927+ }
928+ if (!NapiParseUtils::ParseBoolean(env, argv[INTEGER_TWO], overwrite)) {
929+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
930+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "overwrite", "booleane"));
931+ LOGE("NapiWebSchemeHandlerResponse::JS_SetHeaderByName parse failed");
932+ return nullptr;
933+ }
934+ response->SetHeaderByName(name, value, overwrite);
935+ return nullptr;
936+}
937+ 
938+napi_value NapiWebSchemeHandlerResponse::JS_GetNetErrorCode(napi_env env, napi_callback_info cbinfo)
939+{
940+ size_t argc = 1;
941+ napi_value argv[1] = { 0 };
942+ napi_value thisVar = nullptr;
943+ void* data = nullptr;
944+ WebSchemeHandlerResponse* response = nullptr;
945+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
946+ 
947+ napi_unwrap(env, thisVar, (void**)&response);
948+ if (!response) {
949+ LOGE("NapiWebSchemeHandlerResponse::JS_GetEncoding response is nullptr");
950+ return nullptr;
951+ }
952+ 
953+ napi_value code;
954+ NAPI_CALL(env, napi_create_int32(env, response->GetErrorCode(), &code));
955+ return code;
956+}
957+ 
958+napi_value NapiWebSchemeHandlerResponse::JS_SetNetErrorCode(napi_env env, napi_callback_info cbinfo)
959+{
960+ size_t argc = INTEGER_ONE;
961+ napi_value argv[INTEGER_ONE] = { 0 };
962+ napi_value thisVar = nullptr;
963+ void* data = nullptr;
964+ WebSchemeHandlerResponse* response = nullptr;
965+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
966+ 
967+ napi_unwrap(env, thisVar, (void**)&response);
968+ if (!response) {
969+ LOGE("NapiWebSchemeHandlerResponse::JS_GetEncoding response is nullptr");
970+ return nullptr;
971+ }
972+ int32_t code = 0;
973+ if (argc != INTEGER_ONE) {
974+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
975+ NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_ONE, "one"));
976+ return nullptr;
977+ }
978+ if (!NapiParseUtils::ParseInt32(env, argv[0], code)) {
979+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
980+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "code", "int"));
981+ return nullptr;
982+ }
983+ NetErrorInfo errorInfo = ValidateAndGetNetErrorName(code);
984+ response->SetErrorCode(code, errorInfo.errorName.c_str());
985+ return nullptr;
986+}
987+ 
988+napi_value NapiWebResourceHandler::Init(napi_env env, napi_value exports)
989+{
990+ ExportWebResourceHandlerClass(env, &exports);
991+ return exports;
992+}
993+ 
994+void NapiWebResourceHandler::ExportWebResourceHandlerClass(napi_env env, napi_value* exportsPointer)
995+{
996+ napi_property_descriptor properties[] = {
997+ DECLARE_NAPI_FUNCTION("didReceiveResponse", JS_DidReceiveResponse),
998+ DECLARE_NAPI_FUNCTION("didReceiveResponseBody", JS_DidReceiveResponseBody),
999+ DECLARE_NAPI_FUNCTION("didFinish", JS_DidFinish),
1000+ DECLARE_NAPI_FUNCTION("didFail", JS_DidFailWithError),
1001+ };
1002+ napi_value webResourceHandler = nullptr;
1003+ napi_define_class(env, WEB_RESOURCE_HANDLER.c_str(), WEB_RESOURCE_HANDLER.length(), JS_Constructor, nullptr,
1004+ sizeof(properties) / sizeof(properties[0]), properties, &webResourceHandler);
1005+ napi_set_named_property(env, *exportsPointer, WEB_RESOURCE_HANDLER.c_str(), webResourceHandler);
1006+}
1007+ 
1008+napi_status NapiWebResourceHandler::DefineProperties(napi_env env, napi_value* object)
1009+{
1010+ napi_property_descriptor properties[] = {
1011+ DECLARE_NAPI_FUNCTION("didReceiveResponse", JS_DidReceiveResponse),
1012+ DECLARE_NAPI_FUNCTION("didReceiveResponseBody", JS_DidReceiveResponseBody),
1013+ DECLARE_NAPI_FUNCTION("didFinish", JS_DidFinish),
1014+ DECLARE_NAPI_FUNCTION("didFail", JS_DidFailWithError),
1015+ };
1016+ return napi_define_properties(env, *object, sizeof(properties) / sizeof(properties[0]), properties);
1017+}
1018+ 
1019+napi_value NapiWebResourceHandler::JS_Constructor(napi_env env, napi_callback_info info)
1020+{
1021+ napi_value thisVar = nullptr;
1022+ void* data = nullptr;
1023+ napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1024+ 
1025+ WebResourceHandler* handler = new WebResourceHandler(env);
1026+ 
1027+ napi_wrap(
1028+ env, thisVar, handler,
1029+ [](napi_env /* env */, void* data, void* /* hint */) {
1030+ WebResourceHandler* handler = (WebResourceHandler*)data;
1031+ delete handler;
1032+ },
1033+ nullptr, nullptr);
1034+ 
1035+ return thisVar;
1036+}
1037+ 
1038+napi_value NapiWebResourceHandler::JS_DidReceiveResponse(napi_env env, napi_callback_info info)
1039+{
1040+ size_t argc = 1;
1041+ napi_value argv[1] = { 0 };
1042+ napi_value thisVar = nullptr;
1043+ void* data = nullptr;
1044+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1045+ 
1046+ if (argc != 1) {
1047+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
1048+ NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_ONE, "one"));
1049+ return nullptr;
1050+ }
1051+ 
1052+ WebResourceHandler* resourceHandler = nullptr;
1053+ napi_unwrap(env, thisVar, (void**)&resourceHandler);
1054+ 
1055+ if (!resourceHandler) {
1056+ LOGE("JS_DidReceiveResponse unwrap resource handler failed");
1057+ return nullptr;
1058+ }
1059+ 
1060+ WebSchemeHandlerResponse* response = nullptr;
1061+ napi_value obj = argv[0];
1062+ napi_unwrap(env, obj, (void**)&response);
1063+ if (!response) {
1064+ LOGE("JS_DidReceiveResponse unwrap response failed");
1065+ return nullptr;
1066+ }
1067+ int32_t ret = resourceHandler->DidReceiveResponse(response->GetArkWebResponse());
1068+ if (ret != 0) {
1069+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::RESOURCE_HANDLER_INVALID);
1070+ }
1071+ return nullptr;
1072+}
1073+ 
1074+napi_value NapiWebResourceHandler::JS_DidReceiveResponseBody(napi_env env, napi_callback_info info)
1075+{
1076+ LOGI("NapiWebResourceHandler::JS_DidReceiveResponseBody enter");
1077+ size_t argc = 1;
1078+ napi_value argv[1] = { 0 };
1079+ napi_value thisVar = nullptr;
1080+ void* data = nullptr;
1081+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1082+ 
1083+ if (argc != 1) {
1084+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
1085+ NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_ONE, "one"));
1086+ return nullptr;
1087+ }
1088+ 
1089+ WebResourceHandler* resourceHandler = nullptr;
1090+ napi_unwrap(env, thisVar, (void**)&resourceHandler);
1091+ 
1092+ if (!resourceHandler) {
1093+ LOGE("unwrap resource handler failed");
1094+ return nullptr;
1095+ }
1096+ bool isArrayBuffer = false;
1097+ NAPI_CALL(env, napi_is_arraybuffer(env, argv[0], &isArrayBuffer));
1098+ if (!isArrayBuffer) {
1099+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
1100+ return nullptr;
1101+ }
1102+ 
1103+ uint8_t* arrBuf = nullptr;
1104+ size_t byteLength = 0;
1105+ napi_get_arraybuffer_info(env, argv[0], (void**)&arrBuf, &byteLength);
1106+ int32_t ret = resourceHandler->DidReceiveResponseBody(arrBuf, static_cast<int64_t>(byteLength));
1107+ if (ret != 0) {
1108+ LOGE("JS_DidReceiveResponseBody ret=%{public}d", ret);
1109+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::RESOURCE_HANDLER_INVALID);
1110+ }
1111+ return nullptr;
1112+}
1113+ 
1114+napi_value NapiWebResourceHandler::JS_DidFinish(napi_env env, napi_callback_info info)
1115+{
1116+ napi_value thisVar = nullptr;
1117+ void* data = nullptr;
1118+ napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1119+ 
1120+ WebResourceHandler* resourceHandler = nullptr;
1121+ napi_unwrap(env, thisVar, (void**)&resourceHandler);
1122+ 
1123+ if (!resourceHandler) {
1124+ LOGE("unwrap resource handler failed");
1125+ return nullptr;
1126+ }
1127+ 
1128+ int32_t ret = resourceHandler->DidFinish();
1129+ if (ret != 0) {
1130+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::RESOURCE_HANDLER_INVALID);
1131+ LOGE("JS_DidFinish ret=%{public}d", ret);
1132+ }
1133+ return nullptr;
1134+}
1135+ 
1136+napi_value NapiWebResourceHandler::JS_DidFailWithError(napi_env env, napi_callback_info info)
1137+{
1138+ size_t argc = 2;
1139+ napi_value argv[2] = { 0 };
1140+ napi_value thisVar = nullptr;
1141+ void* data = nullptr;
1142+ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1143+ 
1144+ WebResourceHandler* resourceHandler = nullptr;
1145+ napi_unwrap(env, thisVar, (void**)&resourceHandler);
1146+ 
1147+ if (!resourceHandler) {
1148+ LOGE("unwrap resource handler failed");
1149+ return nullptr;
1150+ }
1151+ 
1152+ int32_t errorCode;
1153+ static constexpr int LEVEL_COUNT = 2;
1154+ if (!NapiParseUtils::ParseInt32(env, argv[0], errorCode)) {
1155+ LOGE("JS_DidFailWithError unwrap error code failed");
1156+ if (argc < LEVEL_COUNT) {
1157+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR,
1158+ NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "code", "int"));
1159+ } else {
1160+ NWebError::BusinessError::ThrowErrorByErrcode(
1161+ env, NWebError::INVALID_NET_ERROR, NWebError::GetErrMsgByErrCode(NWebError::INVALID_NET_ERROR));
1162+ }
1163+ 
1164+ return nullptr;
1165+ }
1166+
1167+ NetErrorInfo errorInfo = ValidateAndGetNetErrorName(errorCode);
1168+ if (argc >= LEVEL_COUNT && (!errorInfo.isValid || errorCode == ARKWEB_NET_OK)) {
1169+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_NET_ERROR,
1170+ NWebError::GetErrMsgByErrCode(NWebError::INVALID_NET_ERROR));
1171+ return nullptr;
1172+ }
1173+ 
1174+ bool completeIfNoResponse = false;
1175+ if (!NapiParseUtils::ParseBoolean(env, argv[1], completeIfNoResponse)) {
1176+ LOGE("JS_DidFailWithError unwrap error completeIfNoResponse failed");
1177+ }
1178+ int32_t ret = resourceHandler->DidFailWithError(
1179+ static_cast<ArkWeb_NetError>(errorCode), errorInfo.errorName.c_str(), completeIfNoResponse);
1180+ if (ret != 0) {
1181+ NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::RESOURCE_HANDLER_INVALID);
1182+ LOGE("JS_DidFailWithError ret=%{public}d", ret);
1183+ }
1184+ return nullptr;
1185+}
1186+} // namespace OHOS::Plugin
@@ -0,0 +1,98 @@
1+/*
2+ * Copyright (c) 2025 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+ 
17+#ifndef PLUGIN_WEB_WEBVIEW_NAPI_WEB_SCHEME_HANDLER_REQUEST_H
18+#define PLUGIN_WEB_WEBVIEW_NAPI_WEB_SCHEME_HANDLER_REQUEST_H
19+ 
20+#include <string>
21+#include <node_api.h>
22+#include "napi/native_common.h"
23+ 
24+namespace OHOS::Plugin {
25+const std::string WEB_SCHEME_HANDLER = "WebSchemeHandler";
26+const std::string WEB_SCHEME_HANDLER_REQUEST = "WebSchemeHandlerRequest";
27+const std::string WEB_SCHEME_HANDLER_RESPONSE = "WebSchemeHandlerResponse";
28+const std::string WEB_RESOURCE_HANDLER = "WebResourceHandler";
29+const std::string WEB_HTTP_BODY_STREAM = "WebHttpBodyStream";
30+const std::string WEB_NET_ERROR_CODE = "WebNetErrorCode";
31+class NapiWebSchemeHandlerRequest {
32+public:
33+ NapiWebSchemeHandlerRequest() = default;
34+ ~NapiWebSchemeHandlerRequest() = default;
35+ 
36+ static napi_value Init(napi_env env, napi_value exports);
37+ static void ExportWebSchemeHandlerRequestClass(napi_env, napi_value* exportsPointer);
38+ static napi_status DefineProperties(napi_env env, napi_value* object);
39+
40+ static napi_value JS_Constructor(napi_env env, napi_callback_info cbinfo);
41+ static napi_value JS_GetHeader(napi_env env, napi_callback_info cbinfo);
42+ static napi_value JS_GetRequestUrl(napi_env env, napi_callback_info cbinfo);
43+ static napi_value JS_GetRequestMethod(napi_env env, napi_callback_info cbinfo);
44+ static napi_value JS_GetReferrer(napi_env env, napi_callback_info cbinfo);
45+ static napi_value JS_IsRedirect(napi_env env, napi_callback_info cbinfo);
46+ static napi_value JS_IsMainFrame(napi_env env, napi_callback_info cbinfo);
47+ static napi_value JS_HasGesture(napi_env env, napi_callback_info cbinfo);
48+ static napi_value JS_HttpBodyStream(napi_env env, napi_callback_info cbinfo);
49+ static napi_value JS_GetRequestResourceType(napi_env env, napi_callback_info cbinfo);
50+ static napi_value JS_GetFrameUrl(napi_env env, napi_callback_info cbinfo);
51+ 
52+private:
53+ static napi_status ExportEnumWebResourceType(napi_env env, napi_value* value);
54+};
55+ 
56+class NapiWebSchemeHandlerResponse {
57+public:
58+ NapiWebSchemeHandlerResponse() = default;
59+ ~NapiWebSchemeHandlerResponse() = default;
60+ 
61+ static napi_value Init(napi_env env, napi_value exports);
62+ static void ExportWebSchemeHandlerResponseClass(napi_env, napi_value* exportsPointer);
63+ 
64+ static napi_value JS_Constructor(napi_env env, napi_callback_info cbinfo);
65+ static napi_value JS_GetUrl(napi_env env, napi_callback_info cbinfo);
66+ static napi_value JS_SetUrl(napi_env env, napi_callback_info cbinfo);
67+ static napi_value JS_GetStatus(napi_env env, napi_callback_info cbinfo);
68+ static napi_value JS_SetStatus(napi_env env, napi_callback_info cbinfo);
69+ static napi_value JS_GetStatusText(napi_env env, napi_callback_info cbinfo);
70+ static napi_value JS_SetStatusText(napi_env env, napi_callback_info cbinfo);
71+ static napi_value JS_GetMimeType(napi_env env, napi_callback_info cbinfo);
72+ static napi_value JS_SetMimeType(napi_env env, napi_callback_info cbinfo);
73+ static napi_value JS_GetEncoding(napi_env env, napi_callback_info cbinfo);
74+ static napi_value JS_SetEncoding(napi_env env, napi_callback_info cbinfo);
75+ static napi_value JS_GetHeaderByName(napi_env env, napi_callback_info cbinfo);
76+ static napi_value JS_SetHeaderByName(napi_env env, napi_callback_info cbinfo);
77+ static napi_value JS_GetNetErrorCode(napi_env env, napi_callback_info cbinfo);
78+ static napi_value JS_SetNetErrorCode(napi_env env, napi_callback_info cbinfo);
79+};
80+ 
81+class NapiWebResourceHandler {
82+public:
83+ NapiWebResourceHandler() = default;
84+ ~NapiWebResourceHandler() = default;
85+ 
86+ static napi_value Init(napi_env env, napi_value exports);
87+ static void ExportWebResourceHandlerClass(napi_env, napi_value* exportsPointer);
88+ static napi_status DefineProperties(napi_env env, napi_value* object);
89+ 
90+ static napi_value JS_Constructor(napi_env env, napi_callback_info info);
91+ static napi_value JS_DidReceiveResponse(napi_env env, napi_callback_info info);
92+ static napi_value JS_DidReceiveResponseBody(napi_env env, napi_callback_info info);
93+ static napi_value JS_DidFinish(napi_env env, napi_callback_info info);
94+ static napi_value JS_DidFailWithError(napi_env env, napi_callback_info info);
95+};
96+}
97+ 
98+#endif // PLUGIN_WEB_WEBVIEW_NAPI_WEB_SCHEME_HANDLER_REQUEST_H
@@ -0,0 +1,630 @@
1+/*
2+ * Copyright (c) 2025 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 "web_scheme_handler_request.h"
17+ 
18+#include <uv.h>
19+ 
20+#include "log.h"
21+#include "napi_parse_utils.h"
22+#include "napi_web_scheme_handler_request.h"
23+#include "web_errors.h"
24+ 
25+namespace OHOS::Plugin {
26+ 
27+struct RequestStopParam {
28+ napi_env env_;
29+ napi_ref callbackRef_;
30+ WebSchemeHandlerRequest* request_;
31+ const ArkWeb_ResourceRequest* arkWebRequest_;
32+};
33+ 
34+static void RequestStopAfterWorkCb(uv_work_t* work, int status);
35+ 
36+std::unordered_map<WebSchemeHandler*, ArkWeb_SchemeHandler*> g_web_scheme_handler_map;
37+std::unordered_map<ArkWeb_SchemeHandler*, WebSchemeHandler*> g_arkui_web_scheme_handler_map;
38+std::mutex g_mutexForHandlerMap;
39+ 
40+void OnRequestStart(ArkWeb_SchemeHandler* schemeHandler, ArkWeb_ResourceRequest* resourceRequest,
41+ ArkWeb_ResourceHandler* resourceHandler, bool* intercept)
42+{
43+ WebSchemeHandler* handler = WebSchemeHandler::GetWebSchemeHandler(schemeHandler);
44+ if (handler == nullptr) {
45+ return;
46+ }
47+ handler->RequestStart(resourceRequest, resourceHandler, intercept);
48+}
49+ 
50+void OnRequestStop(ArkWeb_SchemeHandler* schemeHandler, ArkWeb_ResourceRequest* resourceRequest)
51+{
52+ WebSchemeHandler* handler = WebSchemeHandler::GetWebSchemeHandler(schemeHandler);
53+ if (handler == nullptr) {
54+ return;
55+ }
56+ handler->RequestStop(resourceRequest);
57+}
58+ 
59+WebResourceHandler::WebResourceHandler(napi_env env) : env_(env), handler_(nullptr) {}
60+ 
61+WebResourceHandler::WebResourceHandler(napi_env env, const ArkWeb_ResourceHandler* handler)
62+ : env_(env), handler_(const_cast<ArkWeb_ResourceHandler*>(handler))
63+{}
64+ 
65+WebResourceHandler::~WebResourceHandler() {}
66+ 
67+int32_t WebResourceHandler::DidReceiveResponse(const ArkWeb_Response* response)
68+{
69+ if (isFinished_) {
70+ return ARKWEB_ERROR_UNKNOWN;
71+ }
72+ 
73+ if (!response || !handler_) {
74+ return ARKWEB_INVALID_PARAM;
75+ }
76+ 
77+ if (handler_->DidReceiveResponse(response) != NWebError::NO_ERROR) {
78+ return ARKWEB_INVALID_PARAM;
79+ }
80+ return ARKWEB_NET_OK;
81+}
82+ 
83+int32_t WebResourceHandler::DidReceiveResponseBody(const uint8_t* webResourceHandlerbuffer, int64_t bufferLen)
84+{
85+ if (isFinished_) {
86+ LOGI("WebResourceHandler::DidReceiveResponseBody already finished");
87+ return ARKWEB_ERROR_UNKNOWN;
88+ }
89+ if (!handler_) {
90+ LOGE("WebResourceHandler::DidReceiveResponseBody handler_ is null");
91+ return ARKWEB_INVALID_PARAM;
92+ }
93+ if (handler_->DidReceiveData(webResourceHandlerbuffer, bufferLen) != NWebError::NO_ERROR) {
94+ return ARKWEB_INVALID_PARAM;
95+ }
96+ return ARKWEB_NET_OK;
97+}
98+ 
99+int32_t WebResourceHandler::DidFinish()
100+{
101+ if (isFinished_) {
102+ return ARKWEB_ERROR_UNKNOWN;
103+ }
104+ if (!handler_) {
105+ return ARKWEB_INVALID_PARAM;
106+ }
107+ if (handler_->DidFinish() != NWebError::NO_ERROR) {
108+ return ARKWEB_INVALID_PARAM;
109+ }
110+ isFinished_ = true;
111+ return ARKWEB_NET_OK;
112+}
113+ 
114+int32_t WebResourceHandler::DidFailWithError(
115+ ArkWeb_NetError errorCode, const std::string errorDescription, bool completeIfNoResponse)
116+{
117+ if (isFinished_) {
118+ return ArkWeb_ErrorCode::ARKWEB_ERROR_UNKNOWN;
119+ }
120+ if (handler_->DidFailWithError(errorCode, errorDescription, completeIfNoResponse) != NWebError::NO_ERROR) {
121+ return ARKWEB_INVALID_PARAM;
122+ }
123+ isFinished_ = true;
124+ return ARKWEB_NET_OK;
125+}
126+ 
127+void WebResourceHandler::DestroyArkWebResourceHandler()
128+{
129+ if (handler_) {
130+ handler_->DestroyArkWebResourceHandler();
131+ handler_ = nullptr;
132+ }
133+}
134+ 
135+WebSchemeHandlerRequest::WebSchemeHandlerRequest(napi_env env) : env_(env) {}
136+ 
137+WebSchemeHandlerRequest::WebSchemeHandlerRequest(napi_env env, const ArkWeb_ResourceRequest* request)
138+{
139+ env_ = env;
140+ if (request) {
141+ url_ = request->url_;
142+ method_ = request->method_;
143+ referrer_ = request->referrer_;
144+ isRedirect_ = request->isRedirect_;
145+ isMainFrame_ = request->isMainFrame_;
146+ hasGesture_ = request->hasGesture_;
147+ headerList_ = request->headerList_;
148+ requestResourceType_ = request->requestResourceType_;
149+ frameUrl_ = request->frameUrl_;
150+ }
151+}
152+ 
153+WebSchemeHandlerRequest::~WebSchemeHandlerRequest() {}
154+ 
155+std::string WebSchemeHandlerRequest::GetUrl() const
156+{
157+ return url_;
158+}
159+ 
160+std::string WebSchemeHandlerRequest::GetMethod() const
161+{
162+ return method_;
163+}
164+std::string WebSchemeHandlerRequest::GetReferrer() const
165+{
166+ return referrer_;
167+}
168+ 
169+bool WebSchemeHandlerRequest::GetIsRedirect() const
170+{
171+ return isRedirect_;
172+}
173+ 
174+bool WebSchemeHandlerRequest::GetIsMainFrame() const
175+{
176+ return isMainFrame_;
177+}
178+ 
179+bool WebSchemeHandlerRequest::GetHasGesture() const
180+{
181+ return hasGesture_;
182+}
183+ 
184+WebHeaderList WebSchemeHandlerRequest::GetHeaderList() const
185+{
186+ return headerList_;
187+}
188+ 
189+int32_t WebSchemeHandlerRequest::GetRequestResourceType() const
190+{
191+ return requestResourceType_;
192+}
193+ 
194+std::string WebSchemeHandlerRequest::GetFrameUrl() const
195+{
196+ return frameUrl_;
197+}
198+ 
199+void WebSchemeHandlerRequest::SetUrl(const std::string& url)
200+{
201+ url_ = url;
202+}
203+ 
204+void WebSchemeHandlerRequest::SetMethod(const std::string& method)
205+{
206+ method_ = method;
207+}
208+ 
209+void WebSchemeHandlerRequest::SetReferrer(const std::string& referrer)
210+{
211+ referrer_ = referrer;
212+}
213+ 
214+void WebSchemeHandlerRequest::SetIsRedirect(bool isRedirect)
215+{
216+ isRedirect_ = isRedirect;
217+}
218+ 
219+void WebSchemeHandlerRequest::SetIsMainFrame(bool isMainFrame)
220+{
221+ isMainFrame_ = isMainFrame;
222+}
223+ 
224+void WebSchemeHandlerRequest::SetHasGesture(bool hasGesture)
225+{
226+ hasGesture_ = hasGesture;
227+}
228+ 
229+void WebSchemeHandlerRequest::SetHeaderList(const WebHeaderList& headerList)
230+{
231+ headerList_ = headerList;
232+}
233+ 
234+void WebSchemeHandlerRequest::SetRequestResourceType(int32_t requestResourceType)
235+{
236+ requestResourceType_ = requestResourceType;
237+}
238+ 
239+void WebSchemeHandlerRequest::SetFrameUrl(const std::string& frameUrl)
240+{
241+ frameUrl_ = frameUrl;
242+}
243+ 
244+WebSchemeHandlerResponse::WebSchemeHandlerResponse(napi_env env) : env_(env)
245+{
246+ if (response_ == nullptr) {
247+ response_ = new ArkWeb_Response();
248+ }
249+}
250+ 
251+WebSchemeHandlerResponse::WebSchemeHandlerResponse(napi_env env, ArkWeb_Response* response)
252+ : env_(env), response_(response)
253+{}
254+ 
255+WebSchemeHandlerResponse::~WebSchemeHandlerResponse()
256+{
257+ if (response_ != nullptr) {
258+ delete response_;
259+ response_ = nullptr;
260+ }
261+}
262+ 
263+std::string WebSchemeHandlerResponse::GetUrl() const
264+{
265+ if (!response_) {
266+ return "";
267+ }
268+ return response_->url_;
269+}
270+ 
271+int32_t WebSchemeHandlerResponse::SetUrl(const std::string url)
272+{
273+ if (!response_ || url.empty()) {
274+ return ARKWEB_INVALID_PARAM;
275+ }
276+ 
277+ response_->url_ = url;
278+ return ARKWEB_NET_OK;
279+}
280+ 
281+int32_t WebSchemeHandlerResponse::GetStatus() const
282+{
283+ if (!response_) {
284+ return ARKWEB_INVALID_PARAM;
285+ }
286+ return response_->status_;
287+}
288+ 
289+int32_t WebSchemeHandlerResponse::SetStatus(int32_t status)
290+{
291+ if (!response_) {
292+ return ARKWEB_INVALID_PARAM;
293+ }
294+ response_->status_ = status;
295+ return ARKWEB_NET_OK;
296+}
297+ 
298+std::string WebSchemeHandlerResponse::GetStatusText() const
299+{
300+ if (!response_) {
301+ return "";
302+ }
303+ return response_->statusText_;
304+}
305+ 
306+int32_t WebSchemeHandlerResponse::SetStatusText(const std::string statusText)
307+{
308+ if (!response_ || statusText.empty()) {
309+ return ARKWEB_INVALID_PARAM;
310+ }
311+ response_->statusText_ = statusText;
312+ return ARKWEB_NET_OK;
313+}
314+ 
315+std::string WebSchemeHandlerResponse::GetMimeType() const
316+{
317+ if (!response_) {
318+ return "";
319+ }
320+ return response_->mimeType_;
321+}
322+ 
323+int32_t WebSchemeHandlerResponse::SetMimeType(const std::string mimeType)
324+{
325+ if (!response_ || mimeType.empty()) {
326+ return ARKWEB_INVALID_PARAM;
327+ }
328+ response_->mimeType_ = mimeType;
329+ return ARKWEB_NET_OK;
330+}
331+ 
332+std::string WebSchemeHandlerResponse::GetEncoding() const
333+{
334+ if (!response_) {
335+ return "";
336+ }
337+ return response_->encoding_;
338+}
339+ 
340+int32_t WebSchemeHandlerResponse::SetEncoding(const std::string encoding)
341+{
342+ if (!response_ || encoding.empty()) {
343+ return ARKWEB_INVALID_PARAM;
344+ }
345+ response_->encoding_ = encoding;
346+ return ARKWEB_NET_OK;
347+}
348+ 
349+std::string WebSchemeHandlerResponse::GetHeaderByName(const std::string name)
350+{
351+ if (!response_ || name.empty()) {
352+ return "";
353+ }
354+ auto it = response_->headers_.find(name);
355+ if (it != response_->headers_.end()) {
356+ return it->second;
357+ }
358+ return "";
359+}
360+ 
361+int32_t WebSchemeHandlerResponse::SetHeaderByName(const std::string name, const std::string value, bool overwrite)
362+{
363+ if (!response_ || name.empty() || value.empty()) {
364+ return ARKWEB_INVALID_PARAM;
365+ }
366+ auto it = response_->headers_.find(name);
367+ if (overwrite) {
368+ response_->headers_[name] = value;
369+ } else {
370+ if (it == response_->headers_.end()) {
371+ response_->headers_[name] = value;
372+ }
373+ }
374+ return ARKWEB_NET_OK;
375+}
376+ 
377+int32_t WebSchemeHandlerResponse::GetErrorCode() const
378+{
379+ if (!response_) {
380+ return ARKWEB_ERR_FAILED;
381+ }
382+ return response_->errorCode_;
383+}
384+ 
385+int32_t WebSchemeHandlerResponse::SetErrorCode(int32_t code, const std::string errorDescription)
386+{
387+ if (!response_) {
388+ return ARKWEB_INVALID_PARAM;
389+ }
390+ response_->errorCode_ = code;
391+ response_->errorDescription_ = errorDescription;
392+ return ARKWEB_NET_OK;
393+}
394+ 
395+WebSchemeHandler::WebSchemeHandler(napi_env env) : env_(env)
396+{
397+#ifdef IOS_PLATFORM
398+ ArkWeb_SchemeHandler* handler = AceWebSchemeHandler::CreateArkHandler();
399+ AceWebSchemeHandler::setOnRequestStart(handler, OnRequestStart);
400+ AceWebSchemeHandler::setOnRequestStop(handler, OnRequestStop);
401+#endif
402+#ifdef ANDROID_PLATFORM
403+ auto handler = WebSchemeHandlerJni::CreateArkSchemeHandler();
404+ WebSchemeHandlerJni::SetOnRequestStart(handler, OnRequestStart);
405+ WebSchemeHandlerJni::SetOnRequestStop(handler, OnRequestStop);
406+#endif
407+ if (!handler) {
408+ return;
409+ }
410+ std::lock_guard<std::mutex> auto_lock(g_mutexForHandlerMap);
411+ g_web_scheme_handler_map.insert(std::make_pair(this, handler));
412+ g_arkui_web_scheme_handler_map.insert(std::make_pair(handler, this));
413+}
414+ 
415+WebSchemeHandler::~WebSchemeHandler()
jinpeng0804
jinpeng0804jinpeng08042025年10月13日

先获取锁并删除g_web_scheme_handler_map/g_arkui_web_scheme_handler_map中的条目,再释放锁并销毁handler,确保回调中不会访问到正在销毁的对象

likedislike
quguiren
2025年10月15日 评论:
416+{
417+ ArkWeb_SchemeHandler* handler = const_cast<ArkWeb_SchemeHandler*>(GetArkWebSchemeHandler(this));
418+ if (handler) {
419+ std::lock_guard<std::mutex> auto_lock(g_mutexForHandlerMap);
420+ g_web_scheme_handler_map.erase(this);
421+ g_arkui_web_scheme_handler_map.erase(handler);
422+#ifdef IOS_PLATFORM
423+ AceWebSchemeHandler::destroySchemeHandler(handler);
424+#endif
425+#ifdef ANDROID_PLATFORM
426+ WebSchemeHandlerJni::DeleteArkSchemeHandler(handler);
427+#endif
428+ }
429+}
430+ 
431+ArkWeb_SchemeHandler* WebSchemeHandler::GetArkWebSchemeHandler(WebSchemeHandler* handler)
432+{
433+ if (!handler) {
434+ return nullptr;
435+ }
436+ std::lock_guard<std::mutex> lock(g_mutexForHandlerMap);
437+ auto it = g_web_scheme_handler_map.find(handler);
438+ if (it != g_web_scheme_handler_map.end()) {
439+ return it->second;
440+ }
441+ return nullptr;
442+}
443+ 
444+WebSchemeHandler* WebSchemeHandler::GetWebSchemeHandler(ArkWeb_SchemeHandler* arkHandler)
445+{
446+ if (!arkHandler) {
447+ return nullptr;
448+ }
449+ std::lock_guard<std::mutex> lock(g_mutexForHandlerMap);
450+ auto it = g_arkui_web_scheme_handler_map.find(arkHandler);
451+ if (it != g_arkui_web_scheme_handler_map.end()) {
452+ return it->second;
453+ }
454+ return nullptr;
455+}
456+ 
457+void WebSchemeHandler::ClearWebSchemeHandler()
458+{
459+ std::lock_guard<std::mutex> lock(g_mutexForHandlerMap);
460+ g_web_scheme_handler_map.clear();
461+ g_arkui_web_scheme_handler_map.clear();
462+}
463+ 
464+void WebSchemeHandler::PutRequestStart(napi_env, napi_value callback)
465+{
466+ napi_status status = napi_create_reference(env_, callback, 1, &request_start_callback_);
467+ if (status != napi_status::napi_ok) {
468+ LOGE("PutRequestStart create reference failed.");
469+ }
470+}
471+ 
472+void WebSchemeHandler::PutRequestStop(napi_env, napi_value callback)
473+{
474+ napi_status status = napi_create_reference(env_, callback, 1, &request_stop_callback_);
475+ if (status != napi_status::napi_ok) {
476+ LOGE("PutRequestStop create reference failed.");
477+ }
478+}
479+ 
480+void WebSchemeHandler::RequestStart(
481+ ArkWeb_ResourceRequest* request, ArkWeb_ResourceHandler* arkWeb_ResourceHandler, bool* intercept)
482+{
483+ napi_handle_scope scope;
484+ napi_status status_scope = napi_open_handle_scope(env_, &scope);
485+ if (status_scope != napi_ok) {
486+ LOGE("scheme handler RequestStart scope is nullptr");
487+ return;
488+ }
489+ size_t paramCount = 2;
490+ napi_value callbackFunc = nullptr;
491+ napi_status status;
492+ if (!request_start_callback_) {
493+ LOGE("scheme handler onRequestStart nil env");
494+ return;
495+ }
496+ status = napi_get_reference_value(env_, request_start_callback_, &callbackFunc);
497+ if (status != napi_ok || callbackFunc == nullptr) {
498+ LOGE("scheme handler get onRequestStart func failed.");
499+ return;
500+ }
501+ 
502+ napi_value requestValue[2] = { 0 };
503+ napi_create_object(env_, &requestValue[0]);
504+ napi_create_object(env_, &requestValue[1]);
505+ WebSchemeHandlerRequest* schemeHandlerRequest = new (std::nothrow) WebSchemeHandlerRequest(env_, request);
506+ if (schemeHandlerRequest == nullptr) {
507+ LOGE("RequestStart, new schemeHandlerRequest failed");
508+ return;
509+ }
510+ std::shared_ptr<WebResourceHandler> resourceHandler =
511+ std::make_shared<WebResourceHandler>(env_, arkWeb_ResourceHandler);
512+ if (resourceHandler == nullptr) {
513+ LOGE("RequestStart, new resourceHandler failed");
514+ delete schemeHandlerRequest;
515+ return;
516+ }
517+ napi_wrap(
518+ env_, requestValue[0], schemeHandlerRequest,
519+ [](napi_env /* env */, void* data, void* /* hint */) {
520+ WebSchemeHandlerRequest* request = (WebSchemeHandlerRequest*)data;
521+ delete request;
522+ },
523+ nullptr, nullptr);
524+ NapiWebSchemeHandlerRequest::DefineProperties(env_, &requestValue[0]);
525+ napi_wrap(
526+ env_, requestValue[1], resourceHandler.get(),
527+ [](napi_env /* env */, void* data, void* /* hint */) {}, nullptr, nullptr);
528+ NapiWebResourceHandler::DefineProperties(env_, &requestValue[1]);
529+ napi_value result = nullptr;
530+ status = napi_call_function(env_, nullptr, callbackFunc, paramCount, requestValue, &result);
531+ if (status != napi_status::napi_ok) {
532+ LOGE("scheme handler call onRequestStart failed.");
533+ }
534+ if (!NapiParseUtils::ParseBoolean(env_, result, *intercept)) {
535+ LOGE("scheme handler onRequestStart intercept parse failed");
536+ *intercept = false;
537+ }
538+ if (!*intercept) {
539+ resourceHandler->SetFinishFlag();
540+ }
541+}
542+ 
543+void WebSchemeHandler::RequestStop(ArkWeb_ResourceRequest* resourceRequest)
544+{
545+ uv_loop_s* loop = nullptr;
546+ uv_work_t* work = nullptr;
547+ napi_get_uv_event_loop(env_, &loop);
548+ if (loop == nullptr) {
549+ return;
550+ }
551+ work = new (std::nothrow) uv_work_t;
552+ if (work == nullptr) {
553+ return;
554+ }
555+ RequestStopParam* param = new (std::nothrow) RequestStopParam();
556+ if (param == nullptr) {
557+ delete work;
558+ return;
559+ }
560+ param->env_ = env_;
561+ param->callbackRef_ = request_stop_callback_;
562+ param->request_ = new (std::nothrow) WebSchemeHandlerRequest(param->env_, resourceRequest);
563+ if (param->request_ == nullptr) {
564+ delete work;
565+ delete param;
566+ return;
567+ }
568+ param->arkWebRequest_ = resourceRequest;
569+ work->data = reinterpret_cast<void*>(param);
570+ int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, RequestStopAfterWorkCb, uv_qos_user_initiated);
571+ if (ret != 0) {
572+ if (param != nullptr) {
573+ delete param;
574+ param = nullptr;
575+ }
576+ if (work != nullptr) {
577+ delete work;
578+ work = nullptr;
579+ }
580+ }
581+}
582+ 
583+static void RequestStopAfterWorkCb(uv_work_t* work, int status)
584+{
585+ RequestStopParam* param = reinterpret_cast<RequestStopParam*>(work->data);
586+ if (param == nullptr) {
587+ delete work;
588+ return;
589+ }
590+ 
591+ napi_handle_scope scope;
592+ napi_status status_scope = napi_open_handle_scope(param->env_, &scope);
593+ if (status_scope != napi_ok) {
594+ LOGE("scheme handler RequestStopAfterWorkCb scope is nullptr");
595+ delete param->request_;
596+ delete param;
597+ delete work;
598+ return;
599+ }
600+ 
601+ if (param->callbackRef_) {
602+ napi_value callbackFunc = nullptr;
603+ napi_status napi_status = napi_get_reference_value(param->env_, param->callbackRef_, &callbackFunc);
604+ if (napi_status == napi_ok && callbackFunc != nullptr) {
605+ napi_value requestValue;
606+ napi_create_object(param->env_, &requestValue);
607+ napi_wrap(
608+ param->env_, requestValue, param->request_,
609+ [](napi_env /* env */, void* data, void* /* hint */) {
610+ WebSchemeHandlerRequest* request = (WebSchemeHandlerRequest*)data;
611+ delete request;
612+ },
613+ nullptr, nullptr);
614+ NapiWebSchemeHandlerRequest::DefineProperties(param->env_, &requestValue);
615+ 
616+ napi_value result = nullptr;
617+ napi_status = napi_call_function(param->env_, nullptr, callbackFunc, 1, &requestValue, &result);
618+ if (napi_status != napi_status::napi_ok) {
619+ LOGE("scheme handler call onRequestStop failed.");
620+ }
621+ }
622+ } else {
623+ delete param->request_;
624+ }
625+ 
626+ napi_close_handle_scope(param->env_, scope);
627+ delete param;
628+ delete work;
629+}
630+} // namespace OHOS::Plugin
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright (c) 2025 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+#ifndef PLUGINS_WEB_WEBVIEW_WEB_SCHEME_HANDLER_REQUEST_H
17+#define PLUGINS_WEB_WEBVIEW_WEB_SCHEME_HANDLER_REQUEST_H
18+ 
19+#include <memory>
20+#include <mutex>
21+#include <node_api.h>
22+#include <unordered_map>
23+ 
24+#include "arkweb_error_code.h"
25+#include "arkweb_net_error_list.h"
26+#include "napi_parse_utils.h"
27+#ifdef IOS_PLATFORM
28+#include "AceWebSchemeHandler.h"
29+#endif
30+#ifdef ANDROID_PLATFORM
31+#include "android/java/jni/web_scheme_handler_jni.h"
32+#endif
33+ 
34+namespace OHOS::Plugin {
35+using WebHeaderList = std::vector<std::pair<std::string, std::string>>;
36+class WebSchemeHandlerRequest {
37+public:
38+ explicit WebSchemeHandlerRequest(napi_env env);
39+ WebSchemeHandlerRequest(napi_env env, const ArkWeb_ResourceRequest* request);
40+ ~WebSchemeHandlerRequest();
41+ 
42+public:
43+ std::string GetUrl() const;
44+ std::string GetMethod() const;
45+ std::string GetReferrer() const;
46+ bool GetIsRedirect() const;
47+ bool GetIsMainFrame() const;
48+ bool GetHasGesture() const;
49+ WebHeaderList GetHeaderList() const;
50+ int32_t GetRequestResourceType() const;
51+ std::string GetFrameUrl() const;
52+ void SetUrl(const std::string& url);
53+ void SetMethod(const std::string& method);
54+ void SetReferrer(const std::string& referrer);
55+ void SetIsRedirect(bool isRedirect);
56+ void SetIsMainFrame(bool isMainFrame);
57+ void SetHasGesture(bool hasGesture);
58+ void SetHeaderList(const WebHeaderList& headerList);
59+ void SetRequestResourceType(int32_t requestResourceType);
60+ void SetFrameUrl(const std::string& frameUrl);
61+ 
62+private:
63+ std::string url_ = "";
64+ std::string method_ = "";
65+ std::string referrer_ = "";
66+ bool isRedirect_ = false;
67+ bool isMainFrame_ = false;
68+ bool hasGesture_ = false;
69+ WebHeaderList headerList_;
70+ int32_t requestResourceType_ = -1;
71+ std::string frameUrl_ = "";
72+ napi_env env_;
73+};
74+ 
75+class WebSchemeHandlerResponse {
76+public:
77+ explicit WebSchemeHandlerResponse(napi_env env);
78+ WebSchemeHandlerResponse(napi_env env, ArkWeb_Response* response);
79+ ~WebSchemeHandlerResponse();
80+ 
81+ std::string GetUrl() const;
82+ int32_t SetUrl(const std::string url);
83+ int32_t GetStatus() const;
84+ int32_t SetStatus(int32_t status);
85+ std::string GetStatusText() const;
86+ int32_t SetStatusText(const std::string statusText);
87+ std::string GetMimeType() const;
88+ int32_t SetMimeType(const std::string mimeType);
89+ std::string GetEncoding() const;
90+ int32_t SetEncoding(const std::string encoding);
91+ std::string GetHeaderByName(const std::string name);
92+ int32_t SetHeaderByName(const std::string name, const std::string value, bool overwrite);
93+ int32_t GetErrorCode() const;
94+ int32_t SetErrorCode(int32_t code, const std::string errorDescription);
95+ ArkWeb_Response* GetArkWebResponse()
96+ {
97+ return response_;
98+ }
99+ 
100+private:
101+ napi_env env_;
102+ ArkWeb_Response* response_ = nullptr;
103+};
104+ 
105+class WebResourceHandler {
106+public:
107+ explicit WebResourceHandler(napi_env env);
108+ WebResourceHandler(napi_env env, const ArkWeb_ResourceHandler* handler);
109+ ~WebResourceHandler();
110+ int32_t DidReceiveResponse(const ArkWeb_Response* response);
111+ int32_t DidReceiveResponseBody(const uint8_t* webResourceHandlerbuffer, int64_t bufferLen);
112+ int32_t DidFinish();
113+ int32_t DidFailWithError(ArkWeb_NetError errorCode, const std::string errorDescription, bool completeIfNoResponse);
114+ void DestroyArkWebResourceHandler();
115+ void SetFinishFlag()
116+ {
117+ isFinished_ = true;
118+ }
119+ 
120+private:
121+ bool isFinished_ = false;
122+ ArkWeb_ResourceHandler* handler_ = nullptr;
123+ napi_env env_;
124+};
125+ 
126+class WebSchemeHandler {
127+public:
128+ explicit WebSchemeHandler(napi_env env);
129+ ~WebSchemeHandler();
130+ napi_ref delegate_ = nullptr;
131+ static ArkWeb_SchemeHandler* GetArkWebSchemeHandler(WebSchemeHandler* handler);
132+ static WebSchemeHandler* GetWebSchemeHandler(ArkWeb_SchemeHandler* handler);
133+ static void ClearWebSchemeHandler();
134+ void RequestStart(ArkWeb_ResourceRequest* request, ArkWeb_ResourceHandler* ArkWeb_ResourceHandler, bool* intercept);
135+ void RequestStop(ArkWeb_ResourceRequest* resourceRequest);
136+ 
137+ void PutRequestStart(napi_env, napi_value callback);
138+ void PutRequestStop(napi_env, napi_value callback);
139+ 
140+private:
141+ napi_env env_;
142+ napi_ref request_start_callback_ = nullptr;
143+ napi_ref request_stop_callback_ = nullptr;
144+};
145+} // namespace OHOS::Plugin
146+#endif // PLUGINS_WEB_WEBVIEW_WEB_SCHEME_HANDLER_REQUEST_H
@@ -28,4 +28,6 @@ web_include = [
28web_source = [28web_source = [
29 "$SUBSYSTEM_DIR/interfaces/kits/nativecommon/web_errors.cpp",29 "$SUBSYSTEM_DIR/interfaces/kits/nativecommon/web_errors.cpp",
30 "$SUBSYSTEM_DIR/interfaces/kits/napi/common/business_error.cpp",30 "$SUBSYSTEM_DIR/interfaces/kits/napi/common/business_error.cpp",
31+ "$SUBSYSTEM_DIR/interfaces/kits/napi/web_net_error_code/napi_web_net_errorcode.cpp",
32+ "$SUBSYSTEM_DIR/interfaces/kits/napi/web_net_error_code/napi_web_net_errorcode_module.cpp",
31]33]
@@ -26,6 +26,7 @@
26#include "web_value.h"26#include "web_value.h"
27#include "webview_async_work_callback.h"27#include "webview_async_work_callback.h"
28#include "webview_javascript_async_work_callback.h"28#include "webview_javascript_async_work_callback.h"
29+#include "web_scheme_handler_request.h"
29 30 
30namespace OHOS::Plugin {31namespace OHOS::Plugin {
31struct WebHistoryItem final {32struct WebHistoryItem final {
@@ -125,6 +126,9 @@ public:
125 virtual int32_t GetPageHeight() = 0;126 virtual int32_t GetPageHeight() = 0;
126 virtual void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) = 0;127 virtual void RegisterJavaScriptProxy(const RegisterJavaScriptProxyParam& param) = 0;
127 virtual void DeleteJavaScriptRegister(const std::string& objName) = 0;128 virtual void DeleteJavaScriptRegister(const std::string& objName) = 0;
129+ virtual bool SetWebSchemeHandler(const char* scheme, WebSchemeHandler* handler) = 0;
130+ virtual bool ClearWebSchemeHandler() = 0;
131+ virtual std::string GetUserAgent() = 0;
128 virtual ErrCode ClearHistory() {132 virtual ErrCode ClearHistory() {
129 return NWebError::NO_ERROR;133 return NWebError::NO_ERROR;
130 }134 }