From 26adbf283b153927508fd9450d4e459a2e936f1b Mon Sep 17 00:00:00 2001 From: icaozhengfei Date: Mon, 21 Jul 2025 17:42:02 +0800 Subject: [PATCH] Add Once Signed-off-by: icaozhengfei --- interfaces/kits/ani/webview/BUILD.gn | 4 +- .../ani/webview/ets/@ohos.web.webview.ets | 12 +- .../webview_web_inited_callback.cpp | 105 ++++++++-------- .../webfunction/webview_web_inited_callback.h | 30 +++-- .../kits/ani/webview/src/sts_web_webview.cpp | 2 + .../src/webfunction/ani_webview_function.cpp | 114 ++++++++++++++++++ .../src/webfunction/ani_webview_function.h | 38 ++++++ .../ani_webview_controller.cpp | 19 +-- 8 files changed, 248 insertions(+), 76 deletions(-) create mode 100644 interfaces/kits/ani/webview/src/webfunction/ani_webview_function.cpp create mode 100644 interfaces/kits/ani/webview/src/webfunction/ani_webview_function.h diff --git a/interfaces/kits/ani/webview/BUILD.gn b/interfaces/kits/ani/webview/BUILD.gn index 03803aa4a..f50ac42ce 100644 --- a/interfaces/kits/ani/webview/BUILD.gn +++ b/interfaces/kits/ani/webview/BUILD.gn @@ -104,6 +104,7 @@ ohos_shared_library("webview_ani") { "./src/webadsblockmanager", "./src/webdatabase", "./src/webviewcontroller", + "./src/webfunction", ] sources = [ @@ -136,7 +137,8 @@ ohos_shared_library("webview_ani") { "./src/proxycontroller/proxy_config.cpp", "./src/proxycontroller/proxy_config.h", "./src/proxycontroller/proxy_rule.cpp", - "./src/proxycontroller/proxy_rule.h", + "./src/webfunction/ani_webview_function.h", + "./src/webfunction/ani_webview_function.cpp", "./src/sts_web_webview.cpp", ] diff --git a/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets b/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets index 7df5e2f89..36713bf1d 100644 --- a/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets +++ b/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets @@ -35,6 +35,11 @@ let destroyRegister = new FinalizationRegistry(CleanerCallback) let unregisterToken = new object() export default namespace webview { + static { + loadLibrary("webview_ani.z"); + } + export native function once(type: string, callback: Callback): void; + export enum ScrollType { EVENT } @@ -573,7 +578,12 @@ export default namespace webview { native removeCache(clearRom: boolean): void; native setNetworkAvailable(enable: boolean): void; native isIncognitoMode(): boolean; - native serializeWebState(): Uint8Array; + native serializeWebStateInternal(): ArrayBuffer; + serializeWebState(): Uint8Array{ + let buffer = this.serializeWebStateInternal(); + let uint8Array = new Uint8Array(buffer); + return uint8Array; + } native static trimMemoryByPressureLevel(level: PressureLevel): void; native setPathAllowingUniversalAccess(pathList: Array): void; native onCreateNativeMediaPlayer(callback: (handler: NativeMediaPlayerHandler, mediaInfo: MediaInfo) => NativeMediaPlayerBridge): void; diff --git a/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.cpp b/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.cpp index 742e23ce2..50a5bb7d1 100644 --- a/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.cpp +++ b/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.cpp @@ -15,72 +15,79 @@ #include "webview_web_inited_callback.h" -#include "nweb_log.h" #include "uv.h" namespace OHOS::NWeb { +constexpr ani_size REFERENCES_MAX_NUMBER = 16; namespace { -void UvWebInitedCallbackThreadWoker(uv_work_t *work, int status) +void UvWebInitedCallbackThreadWoker(WebRunInitedCallbackImpl* obj) { - if (work == nullptr) { - WVLOG_E("uv work is null"); + WVLOG_I("enter UvWebInitedCallbackThreadWoker"); + if (!obj || !(obj->param_)) { + WVLOG_E("callback obj or param is nullptr"); return; } - WebInitedCallbackParam *data = reinterpret_cast(work->data); - if (data == nullptr) { - delete work; - work = nullptr; + + ani_size nr_refs = REFERENCES_MAX_NUMBER; + ani_env* env = obj->param_->GetEnv(); + if (!env) { + WVLOG_E("env is nullptr"); return; } - napi_handle_scope scope = nullptr; - napi_open_handle_scope(data->env_, &scope); - if (scope == nullptr) { - delete data; - data = nullptr; - delete work; - work = nullptr; + env->CreateLocalScope(nr_refs); + ani_status status; + if (obj->param_->webInitedCallback_) { + ani_ref fnReturnVal; + if ((status = env->FunctionalObject_Call( + static_cast(obj->param_->webInitedCallback_), 0, {}, &fnReturnVal)) != ANI_OK) { + WVLOG_E("UvWebInitedCallbackThreadWoker callback execute failed status : %{public}d", status); + return; + } else { + WVLOG_I("UvWebInitedCallbackThreadWoker callback execute success!"); + } + } else { + WVLOG_E("callback is nullptr"); + env->DestroyLocalScope(); return; } - napi_value webInitedResult = nullptr; - napi_value jsWebInitedCallback = nullptr; - napi_get_reference_value(data->env_, data->webInitedCallback_, &jsWebInitedCallback); - napi_call_function(data->env_, nullptr, jsWebInitedCallback, 0, {}, &webInitedResult); - - napi_close_handle_scope(data->env_, scope); - delete data; - data = nullptr; - delete work; - work = nullptr; + env->DestroyLocalScope(); + if (obj->param_) { + delete obj->param_; + } + return; } } // namespace -void WebRunInitedCallbackImpl::RunInitedCallback() +WebInitedCallbackParam::WebInitedCallbackParam(ani_env* env, ani_ref callback) { - uv_loop_s *loop = nullptr; - uv_work_t *work = nullptr; - napi_get_uv_event_loop(param_->env_, &loop); - - if (loop == nullptr) { - WVLOG_E("get uv event loop failed"); + WVLOG_I("enter WebInitedCallbackParam"); + if (!env || !callback) { + WVLOG_E("env or callback is nullptr"); return; } - work = new (std::nothrow) uv_work_t; - if (work == nullptr) { - WVLOG_E("new uv work failed"); - return; + env->GetVM(&vm_); + env->GlobalReference_Create(callback, &webInitedCallback_); +} + +WebInitedCallbackParam::~WebInitedCallbackParam() +{ + WVLOG_I("~WebInitedCallbackParam start"); + ani_env* env = GetEnv(); + if (env && webInitedCallback_) { + env->GlobalReference_Delete(webInitedCallback_); + } else { + WVLOG_E("~WebInitedCallbackParam delete ref error"); } - work->data = reinterpret_cast(param_); - int ret = uv_queue_work_with_qos( - loop, work, [](uv_work_t* work) {}, UvWebInitedCallbackThreadWoker, uv_qos_user_initiated); - if (ret != 0) { - if (param_ != nullptr) { - delete param_; - param_ = nullptr; - } - if (work != nullptr) { - delete work; - work = nullptr; - } +} + +void WebRunInitedCallbackImpl::RunInitedCallback() +{ + WVLOG_I("enter RunInitedCallback"); + if (!param_->webInitedCallback_) { + WVLOG_I("callback is null"); + return; } + UvWebInitedCallbackThreadWoker(this); + WVLOG_I("PostTask successful!"); } -} \ No newline at end of file +} // namespace OHOS::NWeb \ No newline at end of file diff --git a/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.h b/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.h index d0b687070..3e7c3502d 100644 --- a/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.h +++ b/interfaces/kits/ani/webview/native/webfunction/webview_web_inited_callback.h @@ -18,28 +18,40 @@ #include #include +#include "ani.h" #include "napi/native_api.h" #include "napi/native_node_api.h" #include "napi_parse_utils.h" +#include "nweb_log.h" #include "nweb_value_callback.h" #include "ohos_init_web_adapter.h" - namespace OHOS::NWeb { class WebInitedCallbackParam { public: - WebInitedCallbackParam(napi_env env, napi_ref callback) : env_(env), webInitedCallback_(callback) {} - - napi_env env_; - napi_ref webInitedCallback_; + WebInitedCallbackParam(ani_env* env, ani_ref callback); + ~WebInitedCallbackParam(); + ani_env* GetEnv() + { + ani_env* env = nullptr; + if (vm_) { + vm_->GetEnv(ANI_VERSION_1, &env); + } + return env; + } + ani_vm* vm_; + ani_ref webInitedCallback_; }; class WebRunInitedCallbackImpl : public WebRunInitedCallback { public: - explicit WebRunInitedCallbackImpl(WebInitedCallbackParam *param) : param_(param) {} - ~WebRunInitedCallbackImpl() override {} + explicit WebRunInitedCallbackImpl(WebInitedCallbackParam* param) : param_(param) {} + ~WebRunInitedCallbackImpl() override + { + WVLOG_I("~WebRunInitedCallbackImpl start"); + } void RunInitedCallback() override; - WebInitedCallbackParam *param_ = nullptr; + WebInitedCallbackParam* param_ = nullptr; }; -} +} // namespace OHOS::NWeb #endif diff --git a/interfaces/kits/ani/webview/src/sts_web_webview.cpp b/interfaces/kits/ani/webview/src/sts_web_webview.cpp index 5f7d847a4..ffef52410 100644 --- a/interfaces/kits/ani/webview/src/sts_web_webview.cpp +++ b/interfaces/kits/ani/webview/src/sts_web_webview.cpp @@ -28,6 +28,7 @@ #include "nweb_log.h" #include "ani_geolocation_permission.h" #include "ani_web_adsblock_manager.h" +#include "ani_webview_function.h" namespace OHOS { namespace NWeb { @@ -60,6 +61,7 @@ ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) StsWebDataBaseInit(env); StsPdfDataInit(env); StsGeolocationPermissionInit(env); + StsWebviewFunctionInit(env); *result = ANI_VERSION_1; return ANI_OK; } diff --git a/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.cpp b/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.cpp new file mode 100644 index 000000000..aec3194ce --- /dev/null +++ b/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ani_webview_function.h" + +#include +#include + +#include "ani_business_error.h" +#include "ani_parse_utils.h" +#include "nweb.h" +#include "nweb_helper.h" +#include "nweb_log.h" +#include "web_errors.h" + +namespace OHOS { +namespace NWeb { +using namespace NWebError; + +namespace { +const char* WEB_WEBVIEW_NAMESPACE_NAME = "L@ohos/web/webview/webview;"; +} + +void RegisterWebInitedCallback(ani_env* env, ani_ref callback) +{ + WVLOG_I("enter RegisterWebInitedCallback"); + WebInitedCallbackParam* param = new (std::nothrow) WebInitedCallbackParam(env, callback); + if (param == nullptr) { + return; + } + + WebRunInitedCallback* runWebInitedCallbackObj = new (std::nothrow) WebRunInitedCallbackImpl(param); + if (runWebInitedCallbackObj == nullptr) { + delete param; + return; + } + WVLOG_I("success in RegisterWebInitedCallback"); + OhosAdapterHelper::GetInstance().GetInitWebAdapter()->SetRunWebInitedCallback(std::move(runWebInitedCallbackObj)); +} + +std::unordered_map> onceType = { + { "webInited", RegisterWebInitedCallback }, +}; + +// type:string +static void JsOnce(ani_env* env, ani_string type, ani_object callback) +{ + WVLOG_I("enter JsOnce"); + if (env == nullptr) { + WVLOG_E("env is nullptr"); + return; + } + + std::string argvType = ""; + ani_class functionClass; + if (env->FindClass("Lstd/core/Function;", &functionClass) != ANI_OK) { + AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR); + return; + } + ani_boolean isFunction; + env->Object_InstanceOf(callback, functionClass, &isFunction); + + if (!(AniParseUtils::ParseString(env, type, argvType)) || !isFunction || + (onceType.find(argvType) == onceType.end())) { + WVLOG_I("JsOnce TypeError : %{public}s", argvType.c_str()); + AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR); + return; + } + WVLOG_I("JsOnce Type : %{public}s", argvType.c_str()); + + auto foundCallback = onceType.find(argvType); + if (foundCallback != onceType.end()) { + foundCallback->second(env, callback); + } else { + WVLOG_I("error"); + AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE); + return; + } + WVLOG_I("exit JsOnce"); +} + +ani_status StsWebviewFunctionInit(ani_env* env) +{ + WVLOG_I("enter StsWebviewFunctionInit"); + ani_namespace ns; + if (ANI_OK != env->FindNamespace(WEB_WEBVIEW_NAMESPACE_NAME, &ns)) { + WVLOG_E("StsWebviewFunctionInit find namespace failed"); + return ANI_ERROR; + } + std::array methods = { + ani_native_function { "once", nullptr, reinterpret_cast(JsOnce) }, + }; + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + WVLOG_E("StsWebviewFunctionInit bind native function failed"); + return ANI_ERROR; + } + WVLOG_I("exit StsWebviewFunctionInit"); + return ANI_OK; +} + +} // namespace NWeb +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.h b/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.h new file mode 100644 index 000000000..9c69cfd0c --- /dev/null +++ b/interfaces/kits/ani/webview/src/webfunction/ani_webview_function.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_NWEB_ANI_WEBVIEW_FUNCTION_H +#define OHOS_NWEB_ANI_WEBVIEW_FUNCTION_H + +#include +#include + +#include "ani.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "ohos_adapter_helper.h" +#include "webview_controller.h" +#include "webview_web_inited_callback.h" + +namespace OHOS { +namespace NWeb { + +ani_status StsWebviewFunctionInit(ani_env* env); + +} // namespace NWeb +} // namespace OHOS + +#endif // OHOS_NWEB_ANI_WEBVIEW_FUNCTION_H \ No newline at end of file diff --git a/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp b/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp index 63e499231..864d92784 100644 --- a/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp +++ b/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp @@ -2395,7 +2395,7 @@ static ani_enum_item GetRenderProcessMode(ani_env* env, ani_object object) { ani_int renderProcessMode = 0; ani_enum enumType; - env->FindEnum("Lani_enum/COLORINT;", &enumType); + env->FindEnum("L@ohos/web/webview/webview/RenderProcessMode;", &enumType); renderProcessMode = static_cast(NWebHelper::Instance().GetRenderProcessMode()); WVLOG_I("getRenderProcessMode mode = %{public}d", static_cast(renderProcessMode)); @@ -2497,7 +2497,6 @@ static ani_boolean IsIncognitoMode(ani_env *env, ani_object object) static ani_object SerializeWebState(ani_env* env, ani_object object) { ani_object result = nullptr; - if (env == nullptr) { WVLOG_E("env is nullptr"); return result; @@ -2520,19 +2519,7 @@ static ani_object SerializeWebState(ani_env* env, ani_object object) if (retCode != 0) { return result; } - - ani_class cls; - ani_method ctor; - if (env->FindClass("Lstd/core/ArrayBuffer;", &cls) != ANI_OK) { - return result; - } - if (env->Class_FindMethod(cls, "", "I:V", &ctor) != ANI_OK) { - return result; - } - - ani_object arrayObject; - env->Object_New(cls, ctor, &arrayObject, buffer); - return arrayObject; + return buffer; } static void TrimMemoryByPressureLevel(ani_env *env, ani_object object, ani_double level) @@ -4226,7 +4213,7 @@ ani_status StsWebviewControllerInit(ani_env *env) ani_native_function { "removeCache", nullptr, reinterpret_cast(RemoveCache) }, ani_native_function { "setNetworkAvailable", nullptr, reinterpret_cast(SetNetworkAvailable) }, ani_native_function { "isIncognitoMode", nullptr, reinterpret_cast(IsIncognitoMode) }, - ani_native_function { "serializeWebState", nullptr, reinterpret_cast(SerializeWebState) }, + ani_native_function { "serializeWebStateInternal", nullptr, reinterpret_cast(SerializeWebState) }, ani_native_function { "trimMemoryByPressureLevel", nullptr, reinterpret_cast(TrimMemoryByPressureLevel) }, ani_native_function { "setPathAllowingUniversalAccess", nullptr, -- Gitee