From 625eec07017a618369636c38140ccee9b8861930 Mon Sep 17 00:00:00 2001 From: lijiancheng21 Date: Mon, 25 Aug 2025 18:29:01 +0800 Subject: [PATCH] add storeWebArchive Signed-off-by: lijiancheng21 --- .../ani/webview/ets/@ohos.web.webview.ets | 8 + .../webview/src/common/ani_business_error.cpp | 4 +- .../ani_webview_controller.cpp | 154 ++++++++++++++++++ 3 files changed, 164 insertions(+), 2 deletions(-) diff --git a/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets b/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets index e16beab36..02a507674 100644 --- a/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets +++ b/interfaces/kits/ani/webview/ets/@ohos.web.webview.ets @@ -703,6 +703,14 @@ export default namespace webview { } return this.precompileJavaScriptInternal(url,resScript,cacheOptions); } + native storeWebArchiveCallback(baseName: string, autoName: boolean, callback: AsyncCallback): void; + storeWebArchive(baseName: string, autoName: boolean, callback: AsyncCallback): void { + this.storeWebArchiveCallback(baseName, autoName, callback); + } + native storeWebArchivePromise(baseName: string, autoName: boolean): Promise; + storeWebArchive(baseName: string, autoName: boolean): Promise { + return this.storeWebArchivePromise(baseName, autoName); + } } export class WebSchemeHandlerResponse { diff --git a/interfaces/kits/ani/webview/src/common/ani_business_error.cpp b/interfaces/kits/ani/webview/src/common/ani_business_error.cpp index ce2f90c62..7c352b874 100644 --- a/interfaces/kits/ani/webview/src/common/ani_business_error.cpp +++ b/interfaces/kits/ani/webview/src/common/ani_business_error.cpp @@ -75,7 +75,7 @@ ani_object CreateBusinessError(ani_env *env, ani_int code, const std::string& ms WVLOG_E("FindClass failed %{public}d", status); return nullptr; } - if ((status = env->Class_FindMethod(cls, "", "DLescompat/Error;:V", &method)) != ANI_OK) { + if ((status = env->Class_FindMethod(cls, "", "ILescompat/Error;:V", &method)) != ANI_OK) { WVLOG_E("Class_FindMethod failed %{public}d", status); return nullptr; } @@ -84,7 +84,7 @@ ani_object CreateBusinessError(ani_env *env, ani_int code, const std::string& ms WVLOG_E("error nulll"); return nullptr; } - ani_double dCode(code); + ani_int dCode(code); if ((status = env->Object_New(cls, method, &obj, dCode, error)) != ANI_OK) { WVLOG_E("Object_New failed %{public}d", status); return nullptr; 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 62120c98b..17071231e 100644 --- a/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp +++ b/interfaces/kits/ani/webview/src/webviewcontroller/ani_webview_controller.cpp @@ -51,6 +51,7 @@ #include "nweb_precompile_callback.h" #include "nweb_cache_options_impl.h" +#include "nweb_store_web_archive_callback.h" #include "bundle_mgr_proxy.h" #include "if_system_ability_manager.h" @@ -4546,6 +4547,157 @@ ani_status StsPrintDocumentAdapterInit(ani_env* env) } +static void StoreWebArchiveCallbackInternal( + ani_env* env, std::string baseNameStr, bool autoNameStr, ani_ref jsCallback, int32_t nwebId) +{ + if (!env) { + return; + } + if (jsCallback == nullptr) { + return; + } + auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId); + if (!nweb_ptr) { + std::vector resultRef; + ani_ref tmp = NWebError::AniBusinessError::CreateError(env, INVALID_RESOURCE); + resultRef.push_back(tmp); + env->GetNull(&tmp); + resultRef.push_back(tmp); + ani_ref fnReturnVal; + env->FunctionalObject_Call( + static_cast(jsCallback), resultRef.size(), resultRef.data(), &fnReturnVal); + env->GlobalReference_Delete(jsCallback); + return; + } + + auto callbackImpl = std::make_shared(); + callbackImpl->SetCallBack([env, jCallback = std::move(jsCallback)](std::string result) { + if (!env) { + return; + } + std::vector resultRef; + if (!result.empty()) { + ani_ref tmp; + env->GetNull(&tmp); + ani_string str {}; + env->String_NewUTF8(result.c_str(), result.size(), &str); + resultRef.push_back(tmp); + resultRef.push_back(str); + } else { + ani_ref tmp = NWebError::AniBusinessError::CreateError(env, INVALID_RESOURCE); + resultRef.push_back(tmp); + env->GetNull(&tmp); + resultRef.push_back(tmp); + } + ani_ref fnReturnVal; + env->FunctionalObject_Call( + static_cast(jCallback), resultRef.size(), resultRef.data(), &fnReturnVal); + env->GlobalReference_Delete(jCallback); + }); + nweb_ptr->StoreWebArchive(baseNameStr, autoNameStr, callbackImpl); +} + +static void StoreWebArchiveCallback( + ani_env* env, ani_object object, ani_string baseName, ani_boolean autoName, ani_fn_object callbackObj) +{ + if (env == nullptr) { + WVLOG_E("env is nullptr"); + return; + } + ani_boolean isUndefined = ANI_TRUE; + if (env->Reference_IsUndefined(baseName, &isUndefined) != ANI_OK || isUndefined == ANI_TRUE) { + WVLOG_E("baseName is undefined"); + return; + } + std::string baseNameStr; + if (!AniParseUtils::ParseString(env, baseName, baseNameStr)) { + WVLOG_E("Parse baseName failed"); + AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR, + NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "baseName", "string")); + return; + } + bool autoNameStr = static_cast(autoName); + + auto* controller = reinterpret_cast(AniParseUtils::Unwrap(env, object)); + if (!controller) { + WVLOG_E("controller is null"); + return; + } + int32_t webId = controller->GetWebId(); + + ani_ref jsCallback = nullptr; + env->GlobalReference_Create(callbackObj, &jsCallback); + return StoreWebArchiveCallbackInternal(env, baseNameStr, autoNameStr, jsCallback, webId); +} + +static void StoreWebArchivePromiseInternal( + ani_env* env, std::string baseNameStr, bool autoNameStr, ani_resolver deferred, int32_t nwebId) +{ + if (!env) { + return; + } + if (deferred == nullptr) { + return; + } + auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId); + if (!nweb_ptr) { + WVLOG_E("nweb_ptr is nullptr"); + ani_ref jsResult = nullptr; + jsResult = NWebError::AniBusinessError::CreateError(env, INIT_ERROR); + env->PromiseResolver_Reject(deferred, reinterpret_cast(jsResult)); + return; + } + + auto callbackImpl = std::make_shared(); + callbackImpl->SetCallBack([env, deferred](std::string result) { + if (!env) { + return; + } + std::vector resultRef(RESULT_COUNT); + resultRef[0] = NWebError::AniBusinessError::CreateError(env, INVALID_RESOURCE); + ani_string str {}; + env->String_NewUTF8(result.c_str(), result.size(), &str); + resultRef[1] = static_cast(str); + if (!result.empty()) { + env->PromiseResolver_Resolve(deferred, resultRef[1]); + } else { + env->PromiseResolver_Reject(deferred, reinterpret_cast(resultRef[0])); + } + }); + nweb_ptr->StoreWebArchive(baseNameStr, autoNameStr, callbackImpl); +} + +static ani_object StoreWebArchivePromise(ani_env* env, ani_object object, ani_string baseName, ani_boolean autoName) +{ + if (env == nullptr) { + WVLOG_E("env is nullptr"); + return nullptr; + } + ani_boolean isUndefined = ANI_TRUE; + if (env->Reference_IsUndefined(baseName, &isUndefined) != ANI_OK || isUndefined == ANI_TRUE) { + WVLOG_E("baseName is undefined"); + return nullptr; + } + std::string baseNameStr; + if (!AniParseUtils::ParseString(env, baseName, baseNameStr)) { + WVLOG_E("Parse baseName failed"); + AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR, + NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "baseName", "string")); + return nullptr; + } + bool autoNameStr = static_cast(autoName); + auto* controller = reinterpret_cast(AniParseUtils::Unwrap(env, object)); + if (!controller) { + WVLOG_E("controller is null"); + return nullptr; + } + int32_t webId = controller->GetWebId(); + ani_object promise; + ani_resolver deferred; + env->Promise_New(&deferred, &promise); + StoreWebArchivePromiseInternal(env, baseNameStr, autoNameStr, deferred, webId); + return promise; +} ani_status StsWebviewControllerInit(ani_env *env) { WVLOG_D("[DOWNLOAD] StsWebviewControllerInit"); @@ -4679,6 +4831,8 @@ ani_status StsWebviewControllerInit(ani_env *env) ani_native_function { "getMediaPlaybackState", nullptr, reinterpret_cast(GetMediaPlaybackState) }, ani_native_function { "webPageSnapshot", nullptr, reinterpret_cast(WebPageSnapshot) }, ani_native_function { "innerCompleteWindowNew", nullptr, reinterpret_cast(InnerCompleteWindowNew) }, + ani_native_function { "storeWebArchiveCallback", nullptr, reinterpret_cast(StoreWebArchiveCallback) }, + ani_native_function { "storeWebArchivePromise", nullptr, reinterpret_cast(StoreWebArchivePromise) }, }; status = env->Class_BindNativeMethods(webviewControllerCls, controllerMethods.data(), controllerMethods.size()); -- Gitee