* 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 <array>
#include <iostream>
#ifndef WEBVIEW_UNIT_TEST
#define WEBVIEW_ANI_STATIC static
#else
#define WEBVIEW_ANI_STATIC
#endif
#ifdef WEBVIEW_UNIT_TEST
#include "test_mock_webview_controller.h"
#include "test_mock_ani_business_error.h"
#include "test_mock_ani_parse_utils.h"
#else
#include "webview_controller.h"
#include "ani_webview_controller.h"
#include "ani_business_error.h"
#include "ani_parse_utils.h"
#endif
#include "ani_class_name.h"
#include "nweb_init_params.h"
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <memory>
#include <unordered_map>
#include <cstddef>
#include <cstdint>
#include <securec.h>
#include <regex>
#include <vector>
#ifndef JSON_NOEXCEPTION
#define JSON_NOEXCEPTION
#endif
#include <nlohmann/json.hpp>
#include "application_context.h"
#include "ohos_resource_adapter_impl.h"
#include "native_arkweb_utils.h"
#include "native_interface_arkweb.h"
#include "nweb_log.h"
#include "web_errors.h"
#include "ani_webview_ai_page_command_callback.h"
#include "webview_hasimage_callback.h"
#include "webview_javascript_execute_callback.h"
#include "webview_javascript_result_callback.h"
#include "nweb_precompile_callback.h"
#include "nweb_cache_options_impl.h"
#include "ani_nweb_value_callback_impl.h"
#include "nweb_store_web_archive_callback.h"
#include "nweb_user_agent_brand_version_impl.h"
#include "nweb_user_agent_metadata_impl.h"
#include "ani_user_agent_metadata.h"
#include "bundle_mgr_proxy.h"
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
#include "parameters.h"
#include "system_ability_definition.h"
#include "nweb_c_api.h"
#include "web_download_delegate.h"
#include "web_download_manager.h"
#include "pixel_map.h"
#include "pixel_map_ani.h"
#include "pixel_map_taihe_ani.h"
#include "proxy_config.h"
#include "web_scheme_handler_response.h"
#include "web_download_item.h"
#include "ani_webview_createpdf_execute_callback.h"
#include "ani_web_scheme_handler_request.h"
#include "web_scheme_handler.h"
#include "arkweb_scheme_handler.h"
#include "web_history_list.h"
#include "webview_value.h"
#include "web_message_port.h"
#include "interop_js/arkts_esvalue.h"
#include "interop_js/arkts_interop_js_api.h"
#include "napi_native_mediaplayer_handler_impl.h"
#include "ohos_adapter_helper.h"
#include "nweb_adapter_helper.h"
#include "arkweb_utils.h"
#include "system_properties_adapter_impl.h"
#include "ani_prefetch_options.h"
#include "prefetch_options.h"
#include "webview_value.h"
namespace OHOS {
namespace NWeb {
using namespace NWebError;
using NWebError::NO_ERROR;
ani_boolean g_WebMessagePort = true;
bool g_inWebPageSnapshot = false;
namespace {
constexpr int32_t RESULT_COUNT = 2;
ani_vm *g_vm = nullptr;
ani_vm *g_vmWebMessagePort = nullptr;
constexpr int32_t MIN_SOCKET_IDLE_TIMEOUT = 30;
constexpr int32_t MAX_SOCKET_IDLE_TIMEOUT = 300;
constexpr size_t MAX_URL_TRUST_LIST_STR_LEN = 10 * 1024 * 1024;
constexpr uint32_t SOCKET_MAXIMUM = 6;
constexpr size_t MAX_RESOURCES_COUNT = 30;
constexpr uint32_t URL_MAXIMUM = 2 * 1024 * 1024;
constexpr int32_t BLANKLESS_SUCCESS = 0;
constexpr int32_t BLANKLESS_ERR_UNKNOWN = 1;
constexpr int32_t BLANKLESS_ERR_INVALID_ARGS = 2;
constexpr int32_t BLANKLESS_ERR_NOT_INITED = 3;
constexpr int32_t BLANKLESS_ERR_DURATION_OUT_OF_RANGE = 6;
constexpr int32_t BLANKLESS_ERR_EXPIRATION_TIME_OUT_OF_RANGE = 7;
constexpr uint32_t MAX_KEYS_COUNT = 100;
constexpr size_t MAX_KEY_LENGTH = 2048;
constexpr int32_t MAX_BLANKLESS_DURATION_TIME = 2000;
constexpr int32_t MIN_BLANKLESS_DURATION_TIME = 200;
constexpr int64_t MAX_EXPIRATION_TIME = 30LL * 24 * 3600 * 1000;
constexpr int32_t MAX_DATABASE_SIZE_IN_MB = 100;
constexpr char URL_REGEXPR[] = "^http(s)?:\\/\\/.+";
const char *INVOKE_METHOD_NAME = "invoke";
const int CALLBACK_PARAM_LENGTH = 2;
int32_t g_maxFdNum = -1;
std::atomic<int32_t> usedFd_ { 0 };
constexpr double A4_WIDTH = 8.27;
constexpr double A4_HEIGHT = 11.69;
constexpr double SCALE_MIN = 0.1;
constexpr double SCALE_MAX = 2.0;
constexpr double HALF = 2.0;
constexpr double TEN_MILLIMETER_TO_INCH = 0.39;
const char* ANI_WEB_CUSTOM_SCHEME_CLASS = "@ohos.web.webview.webview.WebCustomScheme";
constexpr size_t BFCACHE_DEFAULT_SIZE = 1;
constexpr size_t BFCACHE_DEFAULT_TIMETOLIVE = 600;
const char* WEB_CONTROLLER_SECURITY_LEVEL_ENUM_NAME = "@ohos.web.webview.webview.SecurityLevel";
constexpr double MINIMAL_ERROR = 0.000001;
using WebPrintWriteResultCallback = std::function<void(const std::string&, uint32_t)>;
bool IsJsonObjectCommand(const std::string& command)
{
nlohmann::json commandJson = nlohmann::json::parse(command, nullptr, false);
return !commandJson.is_discarded() && commandJson.is_object();
}
bool ResolveEmptyStringPromiseIfCallingFromM132(ani_env* env, ani_resolver resolver, const char* funcName)
{
if (!IS_CALLING_FROM_M132()) {
return false;
}
OHOS::ArkWeb::LogForUnsupportedFunc(OHOS::ArkWeb::ArkWebEngineVersion::M132, funcName);
ani_string stringValue = nullptr;
if (env->String_NewUTF8("", 0, &stringValue) != ANI_OK) {
WVLOG_E("String_NewUTF8 failed");
ani_ref jsError = NWebError::AniBusinessError::CreateError(env, NWebError::INIT_ERROR);
if (env->PromiseResolver_Reject(resolver, reinterpret_cast<ani_error>(jsError)) != ANI_OK) {
WVLOG_E("PromiseResolver_Reject failed");
}
return true;
}
if (env->PromiseResolver_Resolve(resolver, static_cast<ani_ref>(stringValue)) != ANI_OK) {
WVLOG_E("PromiseResolver_Resolve failed");
}
return true;
}
struct PDFMarginConfig {
double top = TEN_MILLIMETER_TO_INCH;
double bottom = TEN_MILLIMETER_TO_INCH;
double right = TEN_MILLIMETER_TO_INCH;
double left = TEN_MILLIMETER_TO_INCH;
};
struct SnapshotOptions {
std::string id;
int32_t width = 0;
int32_t height = 0;
PixelUnit widthType = PixelUnit::NONE;
PixelUnit heightType = PixelUnit::NONE;
PixelUnit sizeType = PixelUnit::NONE;
};
struct Scheme {
std::string name;
bool isSupportCORS;
bool isSupportFetch;
bool isStandard;
bool isLocal;
bool isDisplayIsolated;
bool isSecure;
bool isCspBypassing;
bool isCodeCacheSupported;
int32_t option = 0;
};
ani_ref g_intCls {};
ani_method unboxInt {};
template<typename T>
ani_status unbox(ani_env *env, ani_object obj, T *result)
{
return ANI_INVALID_TYPE;
}
template<>
ani_status unbox<ani_int>(ani_env *env, ani_object obj, ani_int *result)
{
if (g_intCls == nullptr) {
ani_class intCls {};
auto status = env->FindClass("std.core.Int", &intCls);
if (status != ANI_OK) {
return status;
}
status = env->GlobalReference_Create(intCls, &g_intCls);
if (status != ANI_OK) {
return status;
}
status = env->Class_FindMethod(intCls, "toInt", ":i", &unboxInt);
if (status != ANI_OK) {
return status;
}
}
return env->Object_CallMethod_Int(obj, unboxInt, result);
}
bool ParsePrepareUrl(ani_env* env, ani_ref urlObj, std::string& url)
{
if (!AniParseUtils::ParseString(env, urlObj, url)) {
WVLOG_E("urlObj convert to string failed");
return false;
}
if (url.size() > URL_MAXIMUM) {
WVLOG_E("The URL exceeds the maximum length of %{public}d", URL_MAXIMUM);
return false;
}
if (!regex_match(url, std::regex(URL_REGEXPR, std::regex_constants::icase))) {
WVLOG_E("ParsePrepareUrl error");
return false;
}
return true;
}
bool ParsePrepareRequestMethod(ani_env* env, ani_ref methodObj, std::string& method)
{
if (AniParseUtils::ParseString(env, methodObj, method)) {
if (method != "POST") {
WVLOG_E("The method %{public}s is not supported.", method.c_str());
return false;
}
return true;
}
WVLOG_E("Unable to parse type from method object.");
return false;
}
bool CheckCacheKey(ani_env* env, const std::string& cacheKey)
{
for (char c : cacheKey) {
if (!isalnum(c)) {
WVLOG_E("AniBusinessError: 401. The character of 'cacheKey' must be number or letters.");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return false;
}
}
return true;
}
bool ParseResourceRawfileUrl(ani_env *env, const ani_object& object, std::string& fileName)
{
ani_ref paramsRef;
if (env->Object_GetPropertyByName_Ref(object, "params", ¶msRef) != ANI_OK) {
return false;
}
ani_boolean isUndefined;
if (env->Reference_IsUndefined(paramsRef, &isUndefined) != ANI_OK || isUndefined) {
return false;
}
ani_object paramsObj = reinterpret_cast<ani_object>(paramsRef);
ani_ref fileNameRef;
if (env->Object_CallMethodByName_Ref(paramsObj, "$_get", "i:Y", &fileNameRef, 0) != ANI_OK) {
return false;
}
if (env->Reference_IsUndefined(fileNameRef, &isUndefined) != ANI_OK || isUndefined) {
return false;
}
if (!AniParseUtils::ParseString(env, fileNameRef, fileName) || fileName.empty()) {
return false;
}
return true;
}
bool ParseResourceUrl(ani_env *env, ani_object urlObject, std::string& url, WebviewController *controller)
{
ani_ref bundleNameRef;
if (env->Object_GetPropertyByName_Ref(urlObject, "bundleName", &bundleNameRef) != ANI_OK) {
return false;
}
ani_ref moduleNameRef;
if (env->Object_GetPropertyByName_Ref(urlObject, "moduleName", &moduleNameRef) != ANI_OK) {
return false;
}
ani_ref typeRef;
if (env->Object_GetPropertyByName_Ref(urlObject, "type", &typeRef) != ANI_OK) {
return false;
}
ani_int typeInt;
if (env->Object_CallMethodByName_Int(static_cast<ani_object>(typeRef), "toInt", ":i",
&typeInt) != ANI_OK) {
return false;
}
std::string bundleName;
std::string moduleName;
if (!AniParseUtils::ParseString(env, bundleNameRef, bundleName) ||
!AniParseUtils::ParseString(env, moduleNameRef, moduleName)) {
return false;
}
int type = static_cast<int>(typeInt);
if (type == static_cast<int>(ResourceType::RAWFILE)) {
std::string fileName;
if (!ParseResourceRawfileUrl(env, urlObject, fileName)) {
return false;
}
if (!controller->GetRawFileUrl(fileName, bundleName, moduleName, url)) {
return false;
}
} else if (type == static_cast<int>(ResourceType::STRING)) {
ani_double idProperty;
if (env->Object_GetPropertyByName_Double(urlObject, "id", &idProperty) != ANI_OK) {
return false;
}
int id = static_cast<int>(std::round(idProperty));
if (!OhosResourceAdapterImpl::GetResourceString(bundleName, moduleName, id, url)) {
return false;
}
} else {
return false;
}
WVLOG_I("ParseResourceUrl url: %{public}s", url.c_str());
return true;
}
std::shared_ptr<NWebPrefetchOptions> GetPrefetchOptions(ani_env *env, ani_object object, ani_object aniOptions)
{
ani_int minTimeBetweenPrefetchesMsObj;
int32_t minTimeBetweenPrefetchesMs = 500;
if (env->Object_GetPropertyByName_Int(aniOptions, "minTimeBetweenPrefetchesMs",
&minTimeBetweenPrefetchesMsObj) == ANI_OK) {
minTimeBetweenPrefetchesMs = static_cast<int32_t>(minTimeBetweenPrefetchesMsObj);
}
ani_boolean ignoreCacheControlNoStoreObj;
bool ignoreCacheControlNoStore = false;
if (env->Object_GetPropertyByName_Boolean(aniOptions, "ignoreCacheControlNoStore",
&ignoreCacheControlNoStoreObj) == ANI_OK) {
ignoreCacheControlNoStore = static_cast<bool>(ignoreCacheControlNoStoreObj);
}
std::shared_ptr<NWebPrefetchOptions> prefetchOptions =
std::make_shared<NWebPrefetchOptionsImpl>(minTimeBetweenPrefetchesMs, ignoreCacheControlNoStore);
return prefetchOptions;
}
}
WEBVIEW_ANI_STATIC void InitializeWebEngine(ani_env *env, ani_object aniClass)
{
WVLOG_D("InitializeWebEngine invoked.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::shared_ptr<AbilityRuntime::ApplicationContext> ctx =
AbilityRuntime::ApplicationContext::GetApplicationContext();
if (!ctx) {
WVLOG_E("Failed to init web engine due to nil application context.");
return;
}
const std::string& bundlePath = ctx->GetBundleCodeDir();
NWebHelper::Instance().SetBundlePath(bundlePath);
if (!NWebHelper::Instance().InitAndRun(true)) {
WVLOG_E("Failed to init web engine due to NWebHelper failure.");
}
}
static void SetNWebId(ani_env *env, ani_object object, ani_int nwebId)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webviewController is nullptr.");
return;
}
auto id = static_cast<int>(nwebId);
WVLOG_I("SetNWebId nwebId: %{public}d", id);
controller->SetWebId(id);
}
static void SetHapPath(ani_env *env, ani_object object, ani_string hapPath)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined;
if (env->Reference_IsUndefined(hapPath, &isUndefined) != ANI_OK || isUndefined) {
WVLOG_E("is undefined");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("Wrap webviewController failed. WebviewController must be associated with a Web component.");
return;
}
std::string hapPathStr;
if (!AniParseUtils::ParseString(env, hapPath, hapPathStr)) {
WVLOG_E("Parse hap path failed.");
return;
}
WVLOG_I("SetHapPath hapPath: %{public}s", hapPathStr.c_str());
controller->InnerSetHapPath(hapPathStr);
}
static bool GetUrl(ani_env *env, ani_object urlObject, std::string& url, WebviewController *controller)
{
ani_boolean isUndefined = true;
if (env->Reference_IsUndefined(urlObject, &isUndefined) != ANI_OK || isUndefined) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_NUMBERS_ERROR_TWO, "one", "two"));
return false;
}
if (AniParseUtils::IsString(env, urlObject)) {
if (!AniParseUtils::ParseString(env, urlObject, url)) {
return false;
}
} else if (AniParseUtils::IsResource(env, urlObject)) {
if (!ParseResourceUrl(env, urlObject, url, controller)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID));
return false;
}
} else {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_TYPE_INVALID, "url"));
return false;
}
return true;
}
static bool GetWebHeaders(ani_env *env, ani_object headersArrayObj, std::map<std::string, std::string>& webHeaders)
{
ani_int headersLength;
if (env->Object_GetPropertyByName_Int(headersArrayObj, "length", &headersLength) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return false;
}
ani_class webHeaderClass;
if (env->FindClass(ANI_CLASS_WEB_HEADER, &webHeaderClass) != ANI_OK) {
WVLOG_E("Find WebHeader Class failed");
return false;
}
for (int i = 0; i < int(headersLength); i++) {
ani_ref webHeaderRef;
if (env->Object_CallMethodByName_Ref(headersArrayObj, "$_get", "i:Y",
&webHeaderRef, (ani_int)i) != ANI_OK) {
return false;
}
ani_object webHeaderObj = reinterpret_cast<ani_object>(webHeaderRef);
ani_boolean isWebHeader = false;
env->Object_InstanceOf(webHeaderObj, webHeaderClass, &isWebHeader);
if (!isWebHeader) {
WVLOG_E("not WebHeader");
return false;
}
ani_ref keyPropertyRef;
if (env->Object_GetPropertyByName_Ref(webHeaderObj, "headerKey", &keyPropertyRef) != ANI_OK) {
continue;
}
ani_ref valuePropertyRef;
if (env->Object_GetPropertyByName_Ref(webHeaderObj, "headerValue", &valuePropertyRef) != ANI_OK) {
continue;
}
std::string keyString;
std::string valueString;
if (!AniParseUtils::ParseString(env, keyPropertyRef, keyString) ||
!AniParseUtils::ParseString(env, valuePropertyRef, valueString)) {
continue;
}
webHeaders[keyString] = valueString;
}
return true;
}
static void LoadUrl(ani_env *env, ani_object object, ani_object urlObject, ani_object headersArrayObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string url;
if (!GetUrl(env, urlObject, url, controller)) {
return;
}
ErrCode ret;
ani_boolean isUndefined = true;
if (env->Reference_IsUndefined(headersArrayObj, &isUndefined) != ANI_OK || isUndefined) {
ret = controller->LoadUrl(url);
} else {
std::map<std::string, std::string> webHeaders;
if (!GetWebHeaders(env, headersArrayObj, webHeaders)) {
return;
}
ret = controller->LoadUrl(url, webHeaders);
}
WVLOG_I("loadUrl ret: %{public}d", ret);
if (ret != NO_ERROR && ret != NWEB_ERROR) {
if (ret == NWebError::INVALID_URL) {
AniBusinessError::ThrowError(env, NWebError::INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID));
} else {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
}
static void Clean(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_long ptr;
ani_status status = env->Object_GetFieldByName_Long(object, "ptr", &ptr);
if (status != ANI_OK) {
WVLOG_E("Clean Object_GetFieldByName_Long status: %{public}d", status);
return;
}
ani_ref nameObj = nullptr;
if ((status = env->Object_GetFieldByName_Ref(object, "name", &nameObj)) != ANI_OK) {
WVLOG_E("Clean Object_GetFieldByName_Ref status: %{public}d", status);
return;
}
std::string clsName = "";
if (!AniParseUtils::ParseString(env, nameObj, clsName)) {
WVLOG_E("Clean ParseString failed.");
return;
}
if (clsName == "WebviewController") {
delete reinterpret_cast<WebviewController *>(ptr);
} else if (clsName == "WebHistoryList") {
WebHistoryList *historyList = reinterpret_cast<WebHistoryList *>(ptr);
if (historyList && historyList->DecRefCount() <= 0) {
delete historyList;
}
} else if (clsName == "NativeMediaPlayerHandlerinner") {
NapiNativeMediaPlayerHandlerImpl *napiNativeMediaPlayerHandlerImpl
= reinterpret_cast<NapiNativeMediaPlayerHandlerImpl *>(ptr);
if (napiNativeMediaPlayerHandlerImpl &&
napiNativeMediaPlayerHandlerImpl->DecRefCount() <= 0) {
delete napiNativeMediaPlayerHandlerImpl;
}
} else if (clsName == "ProxyConfig") {
delete reinterpret_cast<ProxyConfig *>(ptr);
} else if (clsName == "UserAgentMetadata") {
delete reinterpret_cast<NWebUserAgentMetadataImpl *>(ptr);
} else if (clsName == "UserAgentBrandVersion") {
delete reinterpret_cast<NWebUserAgentBrandVersionImpl *>(ptr);
} else if (clsName == "WebSchemeHandlerResponse") {
delete reinterpret_cast<WebSchemeHandlerResponse *>(ptr);
} else if (clsName == "WebDownloadDelegate") {
delete reinterpret_cast<WebDownloadDelegate *>(ptr);
} else if (clsName == "WebMessageExt") {
delete reinterpret_cast<WebMessageExt *>(ptr);
} else if (clsName == "WebDownloadItem") {
delete reinterpret_cast<WebDownloadItem *>(ptr);
} else if (clsName == "WebDownloadManager") {
delete reinterpret_cast<WebDownloadManager *>(ptr);
} else if (clsName == "PdfData") {
delete reinterpret_cast<WebJsArrayBufferExt *>(ptr);
} else if (clsName == "WebMessagePort") {
WebMessagePort *msgPort = reinterpret_cast<WebMessagePort *>(ptr);
if (msgPort && msgPort->DecRefCount() <= 0) {
delete msgPort;
}
} else if (clsName == "WebSchemeHandler") {
delete reinterpret_cast<WebSchemeHandler*>(ptr);
} else if (clsName == "WebSchemeHandlerRequest") {
WebSchemeHandlerRequest *handler = reinterpret_cast<WebSchemeHandlerRequest *>(ptr);
if (handler) {
handler->DecStrongRef(handler);
}
} else if (clsName == "WebResourceHandler") {
WebResourceHandler *handler = reinterpret_cast<WebResourceHandler*>(ptr);
if (handler) {
handler->DecStrongRef(handler);
}
} else if (clsName == "WebHttpBodyStream") {
delete reinterpret_cast<WebHttpBodyStream*>(ptr);
} else if (clsName == "PrintDocumentAdapterInner") {
delete reinterpret_cast<WebPrintDocument*>(ptr);
} else if (clsName == "WebJsMessageExt") {
delete reinterpret_cast<WebJsMessageExt*>(ptr);
} else if (clsName == "JsMessageExt") {
delete reinterpret_cast<WebJsMessageExt*>(ptr);
} else {
WVLOG_E("Clean unsupport className: %{public}s", clsName.c_str());
}
return;
}
static void Constructor(ani_env *env, ani_object object, ani_string webTagObject)
{
WVLOG_D("[DOWNLOAD] AniWebView native Constructor");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined = true;
env->Reference_IsUndefined(webTagObject, &isUndefined);
std::string webTag;
if (isUndefined) {
webTag = WebviewController::GenerateWebTag();
} else {
if (!AniParseUtils::ParseString(env, webTagObject, webTag)) {
return;
}
WVLOG_I("new webview controller webname:%{public}s", webTag.c_str());
std::lock_guard<std::mutex> lock(WebviewController::webTagMtx_);
WebviewController::webTagSet_.insert(webTag);
}
WebviewController* controller = new (std::nothrow) WebviewController(webTag);
if (!controller) {
WVLOG_E("new webview controller failed");
return;
}
if (!AniParseUtils::Wrap(env, object, ANI_CLASS_WEBVIEW_CONTROLLER, reinterpret_cast<ani_long>(controller))) {
WVLOG_E("webview controller wrap failed");
delete controller;
controller = nullptr;
}
}
WEBVIEW_ANI_STATIC void OnActive(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->OnActive();
}
WEBVIEW_ANI_STATIC void OnInactive(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->OnInactive();
}
WEBVIEW_ANI_STATIC ani_int GetWebId(ani_env *env, ani_object object)
{
int32_t webId = -1;
if (!env) {
WVLOG_E("env is nullptr");
return static_cast<ani_int>(webId);
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return static_cast<ani_int>(webId);
}
webId = controller->GetWebId();
return static_cast<ani_int>(webId);
}
WEBVIEW_ANI_STATIC ani_int InnerGetWebId(ani_env *env, ani_object object)
{
int32_t webId = -1;
if (!env) {
WVLOG_E("env is nullptr");
return static_cast<ani_int>(webId);
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
WVLOG_E("conrtroller is nullptr or not init");
return static_cast<ani_int>(webId);
}
webId = controller->GetWebId();
return static_cast<ani_int>(webId);
}
WEBVIEW_ANI_STATIC ani_boolean GetScrollable(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_TRUE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_TRUE;
}
return static_cast<ani_boolean>(controller->GetScrollable());
}
WEBVIEW_ANI_STATIC void RequestFocus(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->RequestFocus();
}
static void clearClientAuthenticationCache(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ClearClientAuthenticationCache();
}
PDFMarginConfig ParsePDFMarginConfigArgs(ani_env *env, ani_object preArgs, double width, double height)
{
ani_double marginTopObj;
double marginTop = TEN_MILLIMETER_TO_INCH;
if (env->Object_GetPropertyByName_Double(preArgs, "marginTop", &marginTopObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "marginTop", "double"));
return PDFMarginConfig();
}
marginTop = static_cast<double>(marginTopObj);
marginTop = (marginTop >= height / HALF || marginTop <= 0.0) ? 0.0 : marginTop;
ani_double marginBottomObj;
double marginBottom = TEN_MILLIMETER_TO_INCH;
if (env->Object_GetPropertyByName_Double(preArgs, "marginBottom", &marginBottomObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "marginBottom", "double"));
return PDFMarginConfig();
}
marginBottom = static_cast<double>(marginBottomObj);
marginBottom = (marginBottom >= height / HALF || marginBottom <= 0.0) ? 0.0 : marginBottom;
ani_double marginRightObj;
double marginRight = TEN_MILLIMETER_TO_INCH;
if (env->Object_GetPropertyByName_Double(preArgs, "marginRight", &marginRightObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "marginRight", "double"));
return PDFMarginConfig();
}
marginRight = static_cast<double>(marginRightObj);
marginRight = (marginRight >= width / HALF || marginRight <= 0.0) ? 0.0 : marginRight;
ani_double marginLeftObj;
double marginLeft = TEN_MILLIMETER_TO_INCH;
if (env->Object_GetPropertyByName_Double(preArgs, "marginLeft", &marginLeftObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "marginLeft", "double"));
return PDFMarginConfig();
}
marginLeft = static_cast<double>(marginLeftObj);
marginLeft = (marginLeft >= width / HALF || marginLeft <= 0.0) ? 0.0 : marginLeft;
return { marginTop, marginBottom, marginRight, marginLeft };
}
bool ParsePDFScale(ani_env *env, ani_object preArgs, double &scale)
{
ani_ref scale_ref;
ani_boolean isUndefined = ANI_TRUE;
if (env->Object_GetPropertyByName_Ref(preArgs, "scale", &scale_ref) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scale", "double"));
return false;
}
if (env->Reference_IsUndefined(scale_ref, &isUndefined) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scale", "double"));
return false;
}
if (!isUndefined && !AniParseUtils::ParseDouble_t(env, scale_ref, scale)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scale", "double"));
return false;
}
scale = scale > SCALE_MAX ? SCALE_MAX : scale < SCALE_MIN ? SCALE_MIN : scale;
return true;
}
bool ParsePDFShouldPrintBackground(ani_env *env, ani_object preArgs, bool &shouldPrintBackground)
{
ani_ref shouldPrintBackground_ref;
ani_boolean isUndefined = ANI_TRUE;
if (env->Object_GetPropertyByName_Ref(preArgs, "shouldPrintBackground", &shouldPrintBackground_ref) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "shouldPrintBackground", "boolean"));
return false;
}
if (env->Reference_IsUndefined(shouldPrintBackground_ref, &isUndefined) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "shouldPrintBackground", "boolean"));
return false;
}
if (!isUndefined && !AniParseUtils::ParseBoolean_t(env, shouldPrintBackground_ref, shouldPrintBackground)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "shouldPrintBackground", "boolean"));
return false;
}
return true;
}
std::shared_ptr<NWebPDFConfigArgs> ParsePDFConfigArgs(ani_env *env, ani_object preArgs)
{
if (!env) {
WVLOG_E("ParsePDFConfigArgs env is nullptr");
return nullptr;
}
ani_double widthObj;
double width = A4_WIDTH;
if (env->Object_GetPropertyByName_Double(preArgs, "width", &widthObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "width", "double"));
return nullptr;
}
width = static_cast<double>(widthObj);
ani_double heightObj;
double height = A4_HEIGHT;
if (env->Object_GetPropertyByName_Double(preArgs, "height", &heightObj) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "height", "double"));
return nullptr;
}
height = static_cast<double>(heightObj);
auto margin = ParsePDFMarginConfigArgs(env, preArgs, width, height);
double scale = 1.0;
if (!ParsePDFScale(env, preArgs, scale)) {
return nullptr;
}
bool shouldPrintBackground = false;
if (!ParsePDFShouldPrintBackground(env, preArgs, shouldPrintBackground)) {
return nullptr;
}
std::shared_ptr<NWebPDFConfigArgs> pdfConfig = std::make_shared<NWebPDFConfigArgsImpl>(
width, height, scale, margin.top, margin.bottom, margin.right, margin.left, shouldPrintBackground);
WVLOG_D("PDFConfig width=%{public}f, height=%{public}f, scale==%{public}f, margin.top==%{public}f, "
"margin.bottom=%{public}f, margin.right=%{public}f, margin.left=%{public}f, shouldPrintBackground=%{public}s",
width, height, scale, margin.top, margin.bottom, margin.right, margin.left,
shouldPrintBackground ? "true" : "false");
return pdfConfig;
}
ani_object CreatePdfData(ani_env *env, const char* result, const long size)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
WebJsArrayBufferExt *webArrayBufferExt = new (std::nothrow) WebJsArrayBufferExt(result, size);
if (!webArrayBufferExt) {
WVLOG_E("[PDFDATA] new WebHistoryList failed");
return nullptr;
}
ani_object pdfDataObj = {};
if (!AniParseUtils::CreateObjectVoid(env, ANI_PDF_DATA_CLASS_NAME, pdfDataObj)) {
WVLOG_E("[PDFDATA] CreateObjectVoid failed");
delete webArrayBufferExt;
webArrayBufferExt = nullptr;
return nullptr;
}
if (!AniParseUtils::Wrap(env, pdfDataObj, ANI_PDF_DATA_CLASS_NAME,
reinterpret_cast<ani_long>(webArrayBufferExt))) {
WVLOG_E("[PDFDATA] CreatePdf wrap failed");
delete webArrayBufferExt;
webArrayBufferExt = nullptr;
return nullptr;
}
return pdfDataObj;
}
bool AsyncCallback(ani_env *env, ani_ref call, ani_object stsErrCode, ani_object retObj)
{
ani_status status = ANI_ERROR;
ani_class clsCall {};
if ((status = env->FindClass("@ohos.web.webview.webview.AsyncCallbackWrapper", &clsCall)) != ANI_OK) {
WVLOG_E("FindClass fail, status: %{public}d", status);
return false;
}
ani_method method = {};
if ((status = env->Class_FindMethod(clsCall, INVOKE_METHOD_NAME,
"X{C{@ohos.base.BusinessError}C{std.core.Null}}C{std.core.Object}:", &method)) != ANI_OK) {
WVLOG_E("Class_FindMethod fail, status: %{public}d", status);
return false;
}
if (!stsErrCode) {
ani_ref nullRef = nullptr;
if (ANI_OK != env->GetNull(&nullRef)) {
WVLOG_E("GetNull failed");
}
stsErrCode = reinterpret_cast<ani_object>(nullRef);
}
if (!retObj) {
ani_ref undefinedRef = nullptr;
if (env->GetUndefined(&undefinedRef)) {
WVLOG_E("GetUndefined failed");
}
retObj = reinterpret_cast<ani_object>(undefinedRef);
}
if ((status = env->Object_CallMethod_Void(static_cast<ani_object>(call), method, stsErrCode, retObj)) != ANI_OK) {
WVLOG_E("Object_CallMethod_Void fail, status: %{public}d", status);
return false;
}
return true;
}
static void CreatePdfNative(ani_env *env, ani_object object, ani_object pdfConfigObject, ani_object callbackObject)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::shared_ptr<NWebPDFConfigArgs> pdfConfig = ParsePDFConfigArgs(env, pdfConfigObject);
if (!pdfConfig) {
WVLOG_E("ParsePDFConfigArgs failed");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
auto callback = [](ani_env *env, const char* result, const long size, ani_ref callbackRef) -> void {
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_ref jsError = NWebError::AniBusinessError::CreateError(env, NWebError::NO_ERROR);
ani_object resolution = CreatePdfData(env, result, size);
if (!resolution) {
jsError = NWebError::AniBusinessError::CreateError(env, NWebError::PARAM_CHECK_ERROR);
AsyncCallback(env, callbackRef, static_cast<ani_object>(jsError), nullptr);
return;
}
AsyncCallback(env, callbackRef, static_cast<ani_object>(jsError), resolution);
};
std::shared_ptr<NWebArrayBufferValueCallback> callbackImpl =
std::make_shared<WebviewCreatePDFExecuteCallback>(env, callback, callbackObject);
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->CreatePDFExt(pdfConfig, callbackImpl);
return;
}
static ani_boolean ScrollByWithResult(ani_env *env, ani_object object, ani_double deltaX, ani_double deltaY)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
return static_cast<ani_boolean>(
controller->ScrollByWithResult(static_cast<float>(deltaX), static_cast<float>(deltaY)));
}
static void SetScrollable(ani_env *env, ani_object object, ani_boolean enable, ani_enum_item type)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
int32_t scrollType = -1;
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(type, &isUndefined);
if (isUndefined == ANI_FALSE) {
ani_int iType;
if (env->EnumItem_GetValue_Int(type, &iType) != ANI_OK) {
WVLOG_E("BusinessError: 401. The character of 'scrollType' must be int32.");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
scrollType = static_cast<int32_t>(iType);
}
controller->SetScrollable(static_cast<bool>(enable), scrollType);
}
static void ScrollTo(ani_env *env, ani_object object, ani_double x, ani_double y, ani_object durationObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(durationObj, &isUndefined);
if (isUndefined == ANI_TRUE) {
controller->ScrollTo(static_cast<float>(x), static_cast<float>(y));
} else {
ani_int duration;
if (env->Object_CallMethodByName_Int(durationObj, "toInt", nullptr, &duration) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "duration", "int"));
return;
}
controller->ScrollToWithAnime(
static_cast<float>(x), static_cast<float>(y), static_cast<int32_t>(duration));
}
}
WEBVIEW_ANI_STATIC void ScrollBy(ani_env *env, ani_object object, ani_double deltaX, ani_double deltaY,
ani_object durationObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(durationObj, &isUndefined);
if (isUndefined == ANI_TRUE) {
controller->ScrollBy(static_cast<float>(deltaX), static_cast<float>(deltaY));
} else {
ani_int duration;
if (env->Object_CallMethodByName_Int(durationObj, "toInt", nullptr, &duration) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "duration", "int"));
return;
}
controller->ScrollByWithAnime(
static_cast<float>(deltaX), static_cast<float>(deltaY), static_cast<int32_t>(duration));
}
}
WEBVIEW_ANI_STATIC ani_object GetScrollOffset(ani_env *env, ani_object object)
{
ani_object offset = {};
if (!env) {
WVLOG_E("env is nullptr");
return offset;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return offset;
}
float offsetX = 0;
float offsetY = 0;
controller->GetScrollOffset(&offsetX, &offsetY);
if (AniParseUtils::CreateObjectVoid(env, ANI_CLASS_SCROLL_OFFSET_INNER, offset)) {
env->Object_SetPropertyByName_Double(offset, "x", static_cast<ani_double>(offsetX));
env->Object_SetPropertyByName_Double(offset, "y", static_cast<ani_double>(offsetY));
}
return offset;
}
WEBVIEW_ANI_STATIC ani_object GetPageOffset(ani_env *env, ani_object object)
{
if (IS_CALLING_FROM_M114()) {
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return nullptr;
}
ani_object offset = {};
if (env == nullptr) {
WVLOG_E("env is nullptr");
return offset;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return offset;
}
float offsetX = 0;
float offsetY = 0;
controller->GetPageOffset(&offsetX, &offsetY);
if (AniParseUtils::CreateObjectVoid(env, ANI_CLASS_SCROLL_OFFSET_INNER, offset)) {
if (env->Object_SetPropertyByName_Double(offset, "x", static_cast<ani_double>(offsetX)) != ANI_OK) {
WVLOG_E("setProperty x failed");
return nullptr;
}
if (env->Object_SetPropertyByName_Double(offset, "y", static_cast<ani_double>(offsetY)) != ANI_OK) {
WVLOG_E("setProperty y failed");
return nullptr;
}
}
return offset;
}
WEBVIEW_ANI_STATIC void SlideScroll(ani_env *env, ani_object object, ani_double vx, ani_double vy)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->SlideScroll(static_cast<float>(vx), static_cast<float>(vy));
}
WEBVIEW_ANI_STATIC void PageDown(ani_env *env, ani_object object, ani_boolean bottom)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ScrollPageDown(static_cast<bool>(bottom));
}
WEBVIEW_ANI_STATIC void PageUp(ani_env *env, ani_object object, ani_boolean top)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ScrollPageUp(static_cast<bool>(top));
}
static ani_boolean IsAdsBlockEnabledForCurPage(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
return ANI_FALSE;
}
if (!controller->IsAdsBlockEnabledForCurPage()) {
WVLOG_E("IsAdsBlockEnabledForCurPage failed.");
return ANI_FALSE;
}
return ANI_TRUE;
}
static ani_boolean IsIntelligentTrackingPreventionEnabled(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->IsIntelligentTrackingPreventionEnabled()) {
WVLOG_E("IsIntelligentTrackingPreventionEnabled failed.");
return ANI_FALSE;
}
return ANI_TRUE;
}
static void AddIntelligentTrackingPreventionBypassingList(ani_env *env, ani_object object, ani_object stringArrayObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::vector<std::string> hosts;
if (!AniParseUtils::GetStringList(env, stringArrayObj, hosts)) {
WVLOG_E("GetStringList failed.");
return;
}
NWebHelper::Instance().AddIntelligentTrackingPreventionBypassingList(hosts);
return;
}
static void RemoveIntelligentTrackingPreventionBypassingList(ani_env *env, ani_object object,
ani_object stringArrayObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::vector<std::string> hosts;
if (!AniParseUtils::GetStringList(env, stringArrayObj, hosts)) {
WVLOG_E("GetStringList failed.");
return;
}
NWebHelper::Instance().RemoveIntelligentTrackingPreventionBypassingList(hosts);
return;
}
static void ClearIntelligentTrackingPreventionBypassingList(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_I("Clear intelligent tracking prevention bypassing list.");
NWebHelper::Instance().ClearIntelligentTrackingPreventionBypassingList();
return;
}
static void SetHostIP(ani_env *env, ani_object object, ani_object hostNameObj, ani_object addressObj,
ani_int aliveTime)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string hostName;
if (!AniParseUtils::ParseString(env, hostNameObj, hostName)) {
WVLOG_E("Parse host name failed.");
return;
}
std::string address;
if (!AniParseUtils::ParseIP(env, addressObj, address)) {
WVLOG_E("Parse address failed.");
return;
}
int aliveTimeInt = static_cast<int32_t>(aliveTime);
if (aliveTimeInt <= 0) {
WVLOG_E("aliveTime must be greater than 0, aliveTime: %{public}d", aliveTimeInt);
return;
}
NWebHelper::Instance().SetHostIP(hostName, address, aliveTimeInt);
return;
}
static void ClearHostIP(ani_env *env, ani_object object, ani_object hostNameObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string hostName;
if (!AniParseUtils::ParseString(env, hostNameObj, hostName)) {
WVLOG_E("Parse host name failed.");
return;
}
WVLOG_I("Clear host ip: %{public}s", hostName.c_str());
NWebHelper::Instance().ClearHostIP(hostName);
return;
}
static void WarmupServiceWorker(ani_env *env, ani_object object, ani_object urlObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string url;
if (!ParsePrepareUrl(env, urlObj, url)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return;
}
WVLOG_I("Warm up Service Worker: %{public}s", url.c_str());
NWebHelper::Instance().WarmupServiceWorker(url);
return;
}
static void SetUrlTrustList(ani_env *env, ani_object object, ani_object urlTrustListObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webview controller is null or not init");
return;
}
std::string urlTrustList;
if (!AniParseUtils::ParseString(env, urlTrustListObj, urlTrustList)) {
return;
}
if (urlTrustList.size() > MAX_URL_TRUST_LIST_STR_LEN) {
WVLOG_E("EnableAdsBlock: url trust list len is too large.");
return;
}
std::string detailMsg;
ErrCode ret = controller->SetUrlTrustList(urlTrustList, detailMsg);
if (ret != NO_ERROR) {
WVLOG_E("Set Url Trust List failed, detailMsg: %{public}s", detailMsg.c_str());
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void SetUrlTrustListWithWildcard(ani_env *env, ani_object object, ani_object urlTrustListObj,
ani_boolean aniAllowOpaqueOrigin, ani_boolean aniSupportWildcard)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webview controller is null or not init");
return;
}
std::string urlTrustList;
if (!AniParseUtils::ParseString(env, urlTrustListObj, urlTrustList)) {
return;
}
if (urlTrustList.size() > MAX_URL_TRUST_LIST_STR_LEN) {
WVLOG_E("EnableAdsBlock: url trust list len is too large.");
return;
}
std::string detailMsg;
bool allowOpaqueOrigin = static_cast<bool>(aniAllowOpaqueOrigin);
bool supportWildcard = static_cast<bool>(aniSupportWildcard);
ErrCode ret = controller->SetUrlTrustList(urlTrustList, allowOpaqueOrigin, supportWildcard, detailMsg);
if (ret != NO_ERROR) {
WVLOG_E("Set Url Trust List failed, detailMsg: %{public}s", detailMsg.c_str());
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void EnableIntelligentTrackingPrevention(ani_env *env, ani_object object, ani_boolean enable)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
WVLOG_E("controller is nullptr or not init");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
WVLOG_I("enable/disable intelligent tracking prevention.");
controller->EnableIntelligentTrackingPrevention(static_cast<bool>(enable));
return;
}
static void SearchNext(ani_env *env, ani_object object, ani_boolean forward)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->SearchNext(static_cast<bool>(forward));
return;
}
static ani_string GetDefaultUserAgent(ani_env *env, ani_object object)
{
ani_string userAgent = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return userAgent;
}
WVLOG_I("Get the default user agent.");
std::string result = NWebHelper::Instance().GetDefaultUserAgent();
env->String_NewUTF8(result.c_str(), result.size(), &userAgent);
return userAgent;
}
static ani_boolean IsSafeBrowsingEnabled(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->IsSafeBrowsingEnabled()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static void PrepareForPageLoad(
ani_env* env, ani_object object, ani_string aniUrl, ani_boolean preconnectable, ani_int aniNumSockets)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string url;
if (!ParsePrepareUrl(env, aniUrl, url)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return;
}
int32_t numSockets = static_cast<int32_t>(aniNumSockets);
if (numSockets <= 0 || static_cast<uint32_t>(numSockets) > SOCKET_MAXIMUM) {
AniBusinessError::ThrowErrorByErrCode(env, INVALID_SOCKET_NUMBER);
return;
}
NWebHelper::Instance().PrepareForPageLoad(url, preconnectable, numSockets);
return;
}
WEBVIEW_ANI_STATIC void Zoom(ani_env *env, ani_object object, ani_double factor)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->Zoom(static_cast<float>(factor));
if (ret != NO_ERROR) {
if (ret == NWEB_ERROR) {
WVLOG_E("Zoom failed.");
return;
}
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
WEBVIEW_ANI_STATIC void ZoomOut(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->ZoomOut();
if (ret != NO_ERROR) {
if (ret == NWEB_ERROR) {
WVLOG_E("ZoomOut failed.");
return;
}
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
WEBVIEW_ANI_STATIC void ZoomIn(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->ZoomIn();
if (ret != NO_ERROR) {
if (ret == NWEB_ERROR) {
WVLOG_E("ZoomIn failed.");
return;
}
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
WEBVIEW_ANI_STATIC ani_object GetLastHitTest(ani_env *env, ani_object object)
{
ani_object hitTestValue = {};
if (!env) {
WVLOG_E("env is nullptr");
return hitTestValue;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return hitTestValue;
}
std::shared_ptr<HitTestResult> nwebResult = controller->GetLastHitTest();
if (!AniParseUtils::CreateObjectVoid(env, ANI_CLASS_HIT_TEST_VALUE_INNER, hitTestValue) || !nwebResult) {
return hitTestValue;
}
ani_enum_item eType;
if (AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_HIT_TEST_TYPE, nwebResult->GetType(), eType)) {
env->Object_SetPropertyByName_Ref(hitTestValue, "type", eType);
}
auto extra = nwebResult->GetExtra();
ani_string aniExtra;
if (env->String_NewUTF8(extra.c_str(), extra.size(), &aniExtra) == ANI_OK) {
env->Object_SetPropertyByName_Ref(hitTestValue, "extra", aniExtra);
}
return hitTestValue;
}
static void Stop(ani_env *env, ani_object object)
{
WVLOG_D("[WebviewCotr] Stop");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->Stop();
}
static void clearSslCache(ani_env *env, ani_object object)
{
WVLOG_D("[WebviewCotr] clearSslCache");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ClearSslCache();
}
static void clearMatches(ani_env *env, ani_object object)
{
WVLOG_D("[WebviewCotr] clearMatches");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ClearMatches();
}
static void Refresh(ani_env *env, ani_object object)
{
WVLOG_D("[WebviewCotr] Refresh");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->Refresh();
}
static void ReloadIgnoreCache(ani_env *env, ani_object object, ani_boolean aniIgnoreCache)
{
WVLOG_D("[WebviewCotr] ReloadIgnoreCache");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
WVLOG_E("reload failed, ani unwrap webviewController failed");
return;
}
bool ignoreCache = static_cast<bool>(aniIgnoreCache);
if (ignoreCache) {
controller->ReloadIgnoreCache();
} else {
controller->Refresh();
}
}
static void StartDownload(ani_env *env, ani_object object, ani_object urlObj)
{
WVLOG_D("[WebviewCotr] StartDownload");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string urlStr;
if (!ParsePrepareUrl(env, urlObj, urlStr)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return;
}
WVLOG_I("StartDownload url: %{public}s", urlStr.c_str());
int32_t nwebId = controller->GetWebId();
NWebHelper::Instance().LoadNWebSDK();
WebDownloader_StartDownload(nwebId, urlStr.c_str());
}
static void SetDownloadDelegate(ani_env *env, ani_object object, ani_object aniDelegate)
{
WVLOG_D("[WebviewCotr] SetDownloadDelegate");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
NWebHelper::Instance().LoadNWebSDK();
WebDownloadDelegate* delegate = nullptr;
ani_long thisVar;
ani_status status = env->Object_GetFieldByName_Long(aniDelegate, "nativePtr", &thisVar);
if (status != ANI_OK) {
WVLOG_E("AniUtils_Unwrap Object_GetFieldByName_Long status: %{public}d", status);
return;
}
delegate = reinterpret_cast<WebDownloadDelegate *>(thisVar);
if (!delegate) {
WVLOG_E("WebDownloadDelegate is null.");
return;
}
int32_t nwebId = controller->GetWebId();
WebDownloadManager::AddDownloadDelegateForWeb(nwebId, delegate);
}
Media::PixelFormat getColorType(ImageColorType colorType)
{
Media::PixelFormat pixelFormat_;
switch (colorType) {
case ImageColorType::COLOR_TYPE_UNKNOWN:
pixelFormat_ = Media::PixelFormat::UNKNOWN;
break;
case ImageColorType::COLOR_TYPE_RGBA_8888:
pixelFormat_ = Media::PixelFormat::RGBA_8888;
break;
case ImageColorType::COLOR_TYPE_BGRA_8888:
pixelFormat_ = Media::PixelFormat::BGRA_8888;
break;
default:
pixelFormat_ = Media::PixelFormat::UNKNOWN;
break;
}
return pixelFormat_;
}
Media::AlphaType getAlphaType(ImageAlphaType alphaType)
{
Media::AlphaType alphaType_;
switch (alphaType) {
case ImageAlphaType::ALPHA_TYPE_UNKNOWN:
alphaType_ = Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
break;
case ImageAlphaType::ALPHA_TYPE_OPAQUE:
alphaType_ = Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
break;
case ImageAlphaType::ALPHA_TYPE_PREMULTIPLIED:
alphaType_ = Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
break;
case ImageAlphaType::ALPHA_TYPE_POSTMULTIPLIED:
alphaType_ = Media::AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
break;
default:
alphaType_ = Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
break;
}
return alphaType_;
}
static ani_ref GetFaviconByHistoryItem(ani_env *env, std::shared_ptr<NWebHistoryItem> item)
{
if (!env || !item) {
WVLOG_E("[PIXELMAP] env or NWebHistoryItem is nullptr");
return nullptr;
}
ani_ref result = nullptr;
void *data = nullptr;
int width = 0;
int height = 0;
ImageColorType colorType = ImageColorType::COLOR_TYPE_UNKNOWN;
ImageAlphaType alphaType = ImageAlphaType::ALPHA_TYPE_UNKNOWN;
bool isGetFavicon = item->GetFavicon(&data, width, height, colorType, alphaType);
if (env->GetNull(&result) != ANI_OK) {
WVLOG_E("[PIXELMAP] GetNull fail");
return nullptr;
}
if (!isGetFavicon) {
WVLOG_E("[PIXELMAP] isGetFavicon is false");
return result;
}
Media::InitializationOptions opt;
opt.size.width = width;
opt.size.height = height;
opt.pixelFormat = getColorType(colorType);
opt.alphaType = getAlphaType(alphaType);
opt.editable = true;
auto pixelMap = Media::PixelMap::Create(opt);
if (!pixelMap) {
WVLOG_E("[PIXELMAP] pixelMap is null");
return result;
}
uint64_t stride = static_cast<uint64_t>(width) << 2;
uint64_t bufferSize = stride * static_cast<uint64_t>(height);
pixelMap->WritePixels(static_cast<const uint8_t *>(data), bufferSize);
std::shared_ptr<Media::PixelMap> pixelMapToJs(pixelMap.release());
ani_object jsPixelMap = OHOS::Media::PixelMapTaiheAni::CreateEtsPixelMap(env, pixelMapToJs);
return jsPixelMap;
}
static ani_ref GetFavicon(ani_env* env, ani_object object)
{
ani_ref result = nullptr;
if (!env) {
WVLOG_E("[PIXELMAP] env is nullptr");
return result;
}
auto *controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
const void *data = nullptr;
size_t width = 0;
size_t height = 0;
ImageColorType colorType = ImageColorType::COLOR_TYPE_UNKNOWN;
ImageAlphaType alphaType = ImageAlphaType::ALPHA_TYPE_UNKNOWN;
bool isGetFavicon = controller->GetFavicon(&data, width, height, colorType, alphaType);
if (!isGetFavicon) {
return result;
}
Media::InitializationOptions opt;
opt.size.width = static_cast<int>(width);
opt.size.height = static_cast<int>(height);
opt.pixelFormat = getColorType(colorType);
opt.alphaType = getAlphaType(alphaType);
opt.editable = true;
auto pixelMap = Media::PixelMap::Create(opt);
if (!pixelMap) {
return result;
}
uint64_t stride = static_cast<uint64_t>(width) << 2;
uint64_t bufferSize = stride * static_cast<uint64_t>(height);
pixelMap->WritePixels(static_cast<const uint8_t *>(data), bufferSize);
std::shared_ptr<Media::PixelMap> pixelMapToJs(pixelMap.release());
ani_object jsPixelMap = OHOS::Media::PixelMapTaiheAni::CreateEtsPixelMap(env, pixelMapToJs);
return jsPixelMap;
}
static ani_ref GetBackForwardEntries(ani_env *env, ani_object object)
{
WVLOG_D("[BACKFORWARD] GetBackForwardEntries");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
std::shared_ptr<NWebHistoryList> list = controller->GetHistoryList();
if (!list) {
return nullptr;
}
int32_t currentIndex = list->GetCurrentIndex();
int32_t size = list->GetListSize();
WebHistoryList *webHistoryList = new (std::nothrow) WebHistoryList(list);
if (!webHistoryList) {
WVLOG_E("[BACKFORWARD] new WebHistoryList failed");
return nullptr;
}
ani_object backForwardObj = {};
if (AniParseUtils::CreateObjectVoid(env, ANI_BACK_FORWARD_LIST_INNER_CLASS_NAME, backForwardObj) == false) {
WVLOG_E("[BACKFORWARD] CreateObjectVoid failed");
delete webHistoryList;
webHistoryList = nullptr;
return nullptr;
}
if (!AniParseUtils::Wrap(env, backForwardObj, ANI_BACK_FORWARD_LIST_INNER_CLASS_NAME,
reinterpret_cast<ani_long>(webHistoryList))) {
WVLOG_E("[BACKFORWARD] WebDownloadDelegate wrap failed");
delete webHistoryList;
webHistoryList = nullptr;
return nullptr;
}
webHistoryList->IncRefCount();
if (env->Object_SetPropertyByName_Int(backForwardObj, "currentIndex", static_cast<ani_int>(currentIndex))
!= ANI_OK) {
return nullptr;
}
if (env->Object_SetPropertyByName_Int(backForwardObj, "size", static_cast<ani_int>(size)) != ANI_OK) {
return nullptr;
}
return backForwardObj;
}
static void RemoveAllCache(ani_env *env, ani_object object, ani_boolean clearRom)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
NWebHelper::Instance().RemoveAllCache(static_cast<bool>(clearRom));
return;
}
static void PostUrl(ani_env *env, ani_object object, ani_object urlObj, ani_object arrayBufferObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string url;
if (!GetUrl(env, urlObj, url, controller)) {
return;
}
char *arrayBuffer = nullptr;
size_t byteLength = 0;
if (env->ArrayBuffer_GetInfo(reinterpret_cast<ani_arraybuffer>(arrayBufferObj),
reinterpret_cast<void **>(&arrayBuffer), &byteLength) != ANI_OK) {
WVLOG_E("ArrayBuffer_GetInfo failed");
return;
}
std::vector<char> postData(arrayBuffer, arrayBuffer + byteLength);
ErrCode ret = controller->PostUrl(url, postData);
if (ret != NO_ERROR) {
if (ret == NWEB_ERROR) {
WVLOG_E("PostUrl failed");
return;
} else if (ret == NWebError::INVALID_URL) {
AniBusinessError::ThrowError(env, NWebError::INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID));
return;
} else {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
}
bool GetSendPorts(ani_env* env, ani_object portsArrayObj, std::vector<std::string>& sendPorts)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
ani_int arrayLen = 0;
if (env->Object_GetPropertyByName_Int(portsArrayObj, "length", &arrayLen) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return false;
}
ani_class webMessagePortClass;
if (env->FindClass(ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME, &webMessagePortClass) != ANI_OK) {
WVLOG_E("Find WebMessagePort Class failed");
return false;
}
for (uint32_t i = 0; i < static_cast<uint32_t>(arrayLen); i++) {
ani_ref webMessagePortRef;
if (env->Object_CallMethodByName_Ref(
portsArrayObj, "$_get", "i:Y", &webMessagePortRef, (ani_int)i) != ANI_OK) {
WVLOG_E("Object_CallMethodByName_Ref failed");
return false;
}
ani_object portsObj = reinterpret_cast<ani_object>(webMessagePortRef);
ani_boolean isWebMessagePort = false;
env->Object_InstanceOf(portsObj, webMessagePortClass, &isWebMessagePort);
if (!isWebMessagePort) {
WVLOG_E("not WebMessagePort");
return false;
}
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, portsObj));
if ((!msgPort)) {
WVLOG_E("post port to html failed");
return false;
}
std::string portHandle = msgPort->GetPortHandle();
sendPorts.emplace_back(portHandle);
}
return true;
}
static void PostMessage(
ani_env* env, ani_object object, ani_object nameObj, ani_object portsArrayObj, ani_object uriObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string portName;
if (!AniParseUtils::ParseString(env, nameObj, portName)) {
return;
}
std::vector<std::string> sendPorts;
if (!GetSendPorts(env, portsArrayObj, sendPorts)) {
WVLOG_E("post port to html failed, getSendPorts fail");
return;
}
std::string uriStr;
if (!AniParseUtils::ParseString(env, uriObj, uriStr)) {
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
WVLOG_E("post port to html failed, napi unwrap webviewController failed");
return;
}
controller->PostWebMessage(portName, sendPorts, uriStr);
return;
}
static ani_string GetUrlAni(ani_env *env, ani_object object)
{
ani_string url = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return url;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return url;
}
std::string result = controller->GetUrl();
env->String_NewUTF8(result.c_str(), result.size(), &url);
return url;
}
static ani_string GetTitle(ani_env *env, ani_object object)
{
ani_string title = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return title;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return title;
}
std::string result = controller->GetTitle();
env->String_NewUTF8(result.c_str(), result.size(), &title);
return title;
}
static ani_int GetProgress(ani_env* env, ani_object object)
{
ani_int progress = 0;
if (IS_CALLING_FROM_M114()) {
WVLOG_E("GetProgress unsupported engine version: M114");
return progress;
}
if (!env) {
WVLOG_E("env is nullptr");
return progress;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
WVLOG_E("GetProgress: get controller failed");
return progress;
}
return static_cast<ani_int>(controller->GetProgress());
}
static ani_string GetOriginalUrl(ani_env *env, ani_object object)
{
ani_string originUrl = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return originUrl;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return originUrl;
}
std::string result = controller->GetOriginalUrl();
env->String_NewUTF8(result.c_str(), result.size(), &originUrl);
return originUrl;
}
static ani_string GetUserAgent(ani_env *env, ani_object object)
{
ani_string userAgent = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return userAgent;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return userAgent;
}
std::string result = controller->GetUserAgent();
env->String_NewUTF8(result.c_str(), result.size(), &userAgent);
return userAgent;
}
static ani_string GetCustomUserAgent(ani_env *env, ani_object object)
{
ani_string customUserAgent = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return customUserAgent;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return customUserAgent;
}
std::string result = controller->GetCustomUserAgent();
env->String_NewUTF8(result.c_str(), result.size(), &customUserAgent);
return customUserAgent;
}
static ani_string GetLastJavascriptProxyCallingFrameUrl(ani_env *env, ani_object object)
{
ani_string lastCallingFrameUrl = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return lastCallingFrameUrl;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return lastCallingFrameUrl;
}
std::string result = controller->GetLastJavascriptProxyCallingFrameUrl();
env->String_NewUTF8(result.c_str(), result.size(), &lastCallingFrameUrl);
return lastCallingFrameUrl;
}
static void SearchAllAsync(ani_env *env, ani_object object, ani_object searchStringObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string searchString;
if (!AniParseUtils::ParseString(env, searchStringObj, searchString)) {
return;
}
controller->SearchAllAsync(searchString);
return;
}
static void ClearServiceWorkerWebSchemeHandler(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
int32_t ret = WebviewController::ClearWebServiceWorkerSchemeHandler();
if (ret != 0) {
WVLOG_E("ClearServiceWorkerWebSchemeHandler ret=%{public}d", ret);
return;
}
return;
}
static void Forward(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->Forward();
}
static void Backward(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->Backward();
}
static ani_boolean AccessForward(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->AccessForward()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static ani_boolean AccessBackward(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->AccessBackward()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static ani_boolean AccessStep(ani_env *env, ani_object object, ani_int step)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if ((!controller)|| !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->AccessStep(static_cast<int32_t>(step))) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static ani_boolean IsAdsBlockEnabled(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return ANI_FALSE;
}
if (!controller->IsAdsBlockEnabled()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static void EnableAdsBlock(ani_env *env, ani_object object, ani_boolean enable)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return;
}
controller->EnableAdsBlock(static_cast<bool>(enable));
return;
}
static void LoadData(ani_env *env, ani_object object, ani_object urlObj, ani_object mimeTypeObj,
ani_object encodingObj, ani_object baseUrlObj, ani_object historyUrlObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string url;
if (!GetUrl(env, urlObj, url, controller)) {
return;
}
std::string mimeType;
if (!AniParseUtils::ParseString(env, mimeTypeObj, mimeType)) {
return;
}
std::string encoding;
if (!AniParseUtils::ParseString(env, encodingObj, encoding)) {
return;
}
std::string baseUrl;
ani_boolean isUndefined = ANI_TRUE;
if (env->Reference_IsUndefined(baseUrlObj, &isUndefined) != ANI_OK) {
return;
}
if (!isUndefined && !AniParseUtils::ParseString(env, baseUrlObj, baseUrl)) {
return;
}
std::string historyUrl;
if (env->Reference_IsUndefined(historyUrlObj, &isUndefined) != ANI_OK) {
return;
}
if (!isUndefined && !AniParseUtils::ParseString(env, historyUrlObj, historyUrl)) {
return;
}
ErrCode ret = controller->LoadData(url, mimeType, encoding, baseUrl, historyUrl);
if (ret != NO_ERROR) {
if (ret == NWEB_ERROR) {
WVLOG_E("LoadData failed");
return;
}
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void ClearHistory(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ClearHistory();
}
void SetWebSchemeHandler(ani_env* env, ani_object object, ani_string scheme, ani_object handlerObject)
{
WVLOG_D("setWebSchemeHandler start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string schemeStr = "";
if (!AniParseUtils::ParseString(env, scheme, schemeStr)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scheme", "string"));
return;
}
WebSchemeHandler* handler = nullptr;
ani_long thisVar;
ani_status status = env->Object_GetFieldByName_Long(handlerObject, "nativePtr", &thisVar);
if (status != ANI_OK) {
WVLOG_E("AniUtils_Unwrap Object_GetFieldByName_Long status: %{public}d", status);
return;
}
handler = reinterpret_cast<WebSchemeHandler*>(thisVar);
if (!handler) {
WVLOG_E("AniWebviewController::SetWebSchemeHandler handler is null");
return;
}
if (!controller->SetWebSchemeHandler(schemeStr.c_str(), handler)) {
WVLOG_E("AniWebviewController::SetWebSchemeHandler failed");
}
return;
}
static void SetServiceWorkerWebSchemeHandler(
ani_env* env, ani_object object, ani_string scheme, ani_object handlerObject)
{
WVLOG_D("setServiceWorkerWebSchemeHandler start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string schemePtr = "";
if (!AniParseUtils::ParseString(env, scheme, schemePtr)) {
WVLOG_E("AniWebviewController::SetWebSchemeHandler parse scheme failed");
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "scheme", "string"));
return;
}
WebSchemeHandler* handler = nullptr;
ani_long thisVar;
ani_status status = env->Object_GetFieldByName_Long(handlerObject, "nativePtr", &thisVar);
if (status != ANI_OK) {
WVLOG_E("AniUtils_Unwrap Object_GetFieldByName_Long status: %{public}d", status);
return;
}
handler = reinterpret_cast<WebSchemeHandler*>(thisVar);
if (!handler) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
WVLOG_E("Unwrap WebSchemeHandler failed");
return;
}
if (ANI_OK != env->GlobalReference_Create(handlerObject, &handler->delegate_)) {
WVLOG_E("SetServiceWorkerWebSchemeHandler failed to create reference for callback");
return;
}
if (!WebviewController::SetWebServiveWorkerSchemeHandler(schemePtr.c_str(), handler)) {
WVLOG_E("AniWebviewController::SetWebSchemeHandler failed");
}
return;
}
bool CheckSchemeName(const std::string& schemeName)
{
if (schemeName.empty() || schemeName.size() > MAX_CUSTOM_SCHEME_NAME_LENGTH) {
WVLOG_E("Invalid scheme name length");
return false;
}
for (auto it = schemeName.begin(); it != schemeName.end(); it++) {
char chr = *it;
if (!((chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9') || (chr == '.') || (chr == '+') ||
(chr == '-'))) {
WVLOG_E("invalid character %{public}c", chr);
return false;
}
}
return true;
}
void SetCustomizeSchemeOption(Scheme& scheme)
{
std::map<int, std::function<bool(const Scheme&)>> schemeProperties = {
{ 0, [](const Scheme& scheme) { return scheme.isStandard; } },
{ 1, [](const Scheme& scheme) { return scheme.isLocal; } },
{ 2, [](const Scheme& scheme) { return scheme.isDisplayIsolated; } },
{ 3, [](const Scheme& scheme) { return scheme.isSecure; } },
{ 4, [](const Scheme& scheme) { return scheme.isSupportCORS; } },
{ 5, [](const Scheme& scheme) { return scheme.isCspBypassing; } },
{ 6, [](const Scheme& scheme) { return scheme.isSupportFetch; } },
{ 7, [](const Scheme& scheme) { return scheme.isCodeCacheSupported; } }
};
for (const auto& property : schemeProperties) {
if (property.second(scheme)) {
scheme.option += 1 << property.first;
}
}
}
bool SetCustomizeScheme(ani_env* env, ani_object WebCustomSchemeObj, Scheme& scheme)
{
std::map<std::string, std::function<void(Scheme&, bool)>> schemeBooleanProperties = {
{ "isSupportCORS", [](Scheme& scheme, bool value) { scheme.isSupportCORS = value; } },
{ "isSupportFetch", [](Scheme& scheme, bool value) { scheme.isSupportFetch = value; } },
{ "isStandard", [](Scheme& scheme, bool value) { scheme.isStandard = value; } },
{ "isLocal", [](Scheme& scheme, bool value) { scheme.isLocal = value; } },
{ "isDisplayIsolated", [](Scheme& scheme, bool value) { scheme.isDisplayIsolated = value; } },
{ "isSecure", [](Scheme& scheme, bool value) { scheme.isSecure = value; } },
{ "isCspBypassing", [](Scheme& scheme, bool value) { scheme.isCspBypassing = value; } },
{ "isCodeCacheSupported", [](Scheme& scheme, bool value) { scheme.isCodeCacheSupported = value; } }
};
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
for (const auto& property : schemeBooleanProperties) {
ani_status status = ANI_OK;
ani_boolean schemeProperty;
bool schemePropertyBool;
if (property.first == "isSupportCORS" || property.first == "isSupportFetch") {
status = env->Object_GetPropertyByName_Boolean(WebCustomSchemeObj, property.first.c_str(), &schemeProperty);
if (status != ANI_OK) {
WVLOG_E("Object_GetPropertyByName_Boolean status != ANI_OK : %{public}d", status);
return false;
}
schemePropertyBool = static_cast<bool>(schemeProperty);
WVLOG_D("schemePropertyBool : %{public}s %{public}d", property.first.c_str(), schemePropertyBool);
property.second(scheme, schemePropertyBool);
} else {
ani_ref schemePropertyRef = nullptr;
status = env->Object_GetPropertyByName_Ref(WebCustomSchemeObj, property.first.c_str(), &schemePropertyRef);
if (status != ANI_OK) {
WVLOG_E("Object_GetPropertyByName_Ref status != ANI_OK : %{public}s %{public}d", property.first.c_str(),
status);
return false;
}
ani_object schemePropertyObj = static_cast<ani_object>(schemePropertyRef);
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(schemePropertyObj, &isUndefined);
if (isUndefined == ANI_FALSE) {
status = env->Object_CallMethodByName_Boolean(schemePropertyObj, "toBoolean", nullptr, &schemeProperty);
if (status != ANI_OK) {
WVLOG_E("Object_CallMethodByName_Boolean status != ANI_OK : %{public}d", status);
return false;
}
schemePropertyBool = static_cast<bool>(schemeProperty);
WVLOG_D("schemePropertyBool : %{public}s %{public}d", property.first.c_str(), schemePropertyBool);
property.second(scheme, schemePropertyBool);
}
}
}
ani_ref schemeNameRef = nullptr;
if (env->Object_GetPropertyByName_Ref(WebCustomSchemeObj, "schemeName", &schemeNameRef) != ANI_OK) {
return false;
}
if (!AniParseUtils::ParseString(env, schemeNameRef, scheme.name)) {
return false;
}
if (!CheckSchemeName(scheme.name)) {
return false;
}
SetCustomizeSchemeOption(scheme);
return true;
}
int32_t CustomizeSchemesArrayDataHandler(ani_env* env, ani_object schemes, bool lazyInitWebEngine = false)
{
if (!env) {
return PARAM_CHECK_ERROR;
}
ani_int schemesLength = 0;
if (env->Object_GetPropertyByName_Int(schemes, "length", &schemesLength) != ANI_OK) {
return PARAM_CHECK_ERROR;
}
if (schemesLength > MAX_CUSTOM_SCHEME_SIZE) {
return PARAM_CHECK_ERROR;
}
ani_class WebCustomSchemeClass;
if (env->FindClass(ANI_WEB_CUSTOM_SCHEME_CLASS, &WebCustomSchemeClass) != ANI_OK) {
WVLOG_E("Find WebCustomScheme Class failed");
return PARAM_CHECK_ERROR;
}
std::vector<Scheme> schemeVector;
for (int i = 0; i < int(schemesLength); i++) {
ani_ref WebCustomSchemeRef;
if (env->Object_CallMethodByName_Ref(
schemes, "$_get", "i:Y", &WebCustomSchemeRef, (ani_int)i) != ANI_OK) {
WVLOG_E("Object_CallMethodByName_Ref failed");
return PARAM_CHECK_ERROR;
}
ani_object WebCustomSchemeObj = reinterpret_cast<ani_object>(WebCustomSchemeRef);
ani_boolean isWebCustomScheme = false;
env->Object_InstanceOf(WebCustomSchemeObj, WebCustomSchemeClass, &isWebCustomScheme);
if (!isWebCustomScheme) {
return PARAM_CHECK_ERROR;
}
Scheme scheme;
bool result = SetCustomizeScheme(env, WebCustomSchemeObj, scheme);
if (!result) {
return PARAM_CHECK_ERROR;
}
schemeVector.push_back(scheme);
}
int32_t registerResult;
for (auto it = schemeVector.begin(); it != schemeVector.end(); ++it) {
if (lazyInitWebEngine && OHOS::NWeb::NWebHelper::Instance().HasLoadWebEngine() == false) {
OHOS::NWeb::NWebHelper::Instance().SaveSchemeVector(it->name.c_str(), it->option);
} else {
registerResult = OH_ArkWeb_RegisterCustomSchemes(it->name.c_str(), it->option);
if (registerResult != NO_ERROR) {
return registerResult;
}
}
}
return NO_ERROR;
}
static void CustomizeSchemes(ani_env* env, ani_object object, ani_object schemes)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (WebviewController::existNweb_) {
WVLOG_E("There exist web component which has been already created.");
}
int32_t registerResult = CustomizeSchemesArrayDataHandler(env, schemes);
if (registerResult == NO_ERROR) {
return;
}
if (registerResult == PARAM_CHECK_ERROR) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "schemeName", "string"));
return;
}
AniBusinessError::ThrowErrorByErrCode(env, REGISTER_CUSTOM_SCHEME_FAILED);
return;
}
static void CustomizeSchemesLazyInit(ani_env* env, ani_object object, ani_object schemes, ani_boolean lazyInitWebEngine)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (WebviewController::existNweb_) {
WVLOG_E("There exist web component which has been already created.");
}
int32_t registerResult = CustomizeSchemesArrayDataHandler(env, schemes, static_cast<bool>(lazyInitWebEngine));
if (registerResult == NO_ERROR) {
return;
}
if (registerResult == PARAM_CHECK_ERROR) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "schemeName", "string"));
return;
}
AniBusinessError::ThrowErrorByErrCode(env, REGISTER_CUSTOM_SCHEME_FAILED);
return;
}
static ani_enum_item GetSecurityLevel(ani_env* env, ani_object object)
{
ani_enum_item result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
return result;
}
ani_enum enumType;
if (env->FindEnum(WEB_CONTROLLER_SECURITY_LEVEL_ENUM_NAME, &enumType) != ANI_OK) {
WVLOG_E("find enum object failed");
return result;
}
ani_int securityLevel = controller->GetSecurityLevel(env);
env->Enum_GetEnumItemByIndex(enumType, securityLevel, &result);
return result;
}
static void SetHttpDns(ani_env* env, ani_object object, ani_enum_item secureDnsMode, ani_string secureDnsConfig)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(secureDnsMode, &isUndefined) != ANI_OK || isUndefined) {
return;
}
ani_int dohMode;
if (env->EnumItem_GetValue_Int(secureDnsMode, &dohMode) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (dohMode < static_cast<int>(SecureDnsModeType::OFF) ||
dohMode > static_cast<int>(SecureDnsModeType::SECURE_ONLY)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
std::string dohConfig;
if (!AniParseUtils::ParseString(env, secureDnsConfig, dohConfig)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (dohConfig.rfind("https", 0) != 0 && dohConfig.rfind("HTTPS", 0) != 0) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
std::shared_ptr<NWebDOHConfigImpl> config = std::make_shared<NWebDOHConfigImpl>();
config->SetMode(dohMode);
config->SetConfig(dohConfig);
WVLOG_I("set http dns mode:%{public}d doh_config:%{public}s", dohMode, dohConfig.c_str());
NWebHelper::Instance().SetHttpDns(config);
return;
}
static void ClearWebSchemeHandler(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (controller->ClearWebSchemeHandler() != 0) {
WVLOG_E("AniWebviewController::ClearWebSchemeHandler failed");
}
WVLOG_D("AniWebviewController::ClearWebSchemeHandler successful");
}
static ani_ref GetItemAtIndex(ani_env *env, ani_object object, ani_int aniIndex)
{
if (!env) {
WVLOG_E("[BACKFORWARD] env is nullptr");
return nullptr;
}
int32_t index = static_cast<int32_t>(aniIndex);
WebHistoryList *historyList = reinterpret_cast<WebHistoryList *>(AniParseUtils::Unwrap(env, object));
if (!historyList) {
WVLOG_E("[BACKFORWARD] Unwrap failed");
return nullptr;
}
if (index >= historyList->GetListSize() || index < 0) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
"BusinessError 401: Parameter error. The value of index must be greater than or equal to 0");
return nullptr;
}
std::shared_ptr<NWebHistoryItem> item = historyList->GetItem(index);
if (!item) {
return nullptr;
}
std::string historyUrl = item->GetHistoryUrl();
std::string historyRawUrl = item->GetHistoryRawUrl();
std::string title = item->GetHistoryTitle();
ani_object historyItemListObj = {};
if (AniParseUtils::CreateObjectVoid(env, ANI_HISTORY_ITEM_INNER_CLASS_NAME, historyItemListObj) == false) {
WVLOG_E("[BACKFORWARD] CreateObjectVoid failed");
return nullptr;
}
if (AniParseUtils::SetPropertyByName_String(env, historyItemListObj, "historyUrl", historyUrl) != ANI_OK) {
WVLOG_E("[BACKFORWARD] SetPropertyByName_String failed! key=historyUrl, value=%{public}s.", historyUrl.c_str());
return historyItemListObj;
}
if (AniParseUtils::SetPropertyByName_String(env, historyItemListObj, "historyRawUrl", historyRawUrl) != ANI_OK) {
WVLOG_E("[BACKFORWARD] SetPropertyByName_String failed! key=historyRawUrl, value=%{public}s.",
historyRawUrl.c_str());
return historyItemListObj;
}
if (AniParseUtils::SetPropertyByName_String(env, historyItemListObj, "title", title) != ANI_OK) {
WVLOG_E("[BACKFORWARD] SetPropertyByName_String failed! key=title, value=%{public}s.", title.c_str());
return historyItemListObj;
}
ani_ref iconRef = GetFaviconByHistoryItem(env, item);
if (env->Object_SetPropertyByName_Ref(historyItemListObj, "icon", iconRef) != ANI_OK) {
WVLOG_E("[BACKFORWARD] SetPropertyByName_String failed! key=icon.");
return historyItemListObj;
}
return historyItemListObj;
}
static ani_boolean TransferBackForwardListToStaticInner(
ani_env* env, ani_class aniClass, ani_object output, ani_object input)
{
if (!env) {
return ANI_FALSE;
}
void* nativePtr = nullptr;
if (!arkts_esvalue_unwrap(env, input, &nativePtr) || !nativePtr) {
WVLOG_E("[TRANSFER] arkts_esvalue_unwrap failed");
return ANI_FALSE;
}
WebHistoryList *webHistoryList = reinterpret_cast<WebHistoryList *>(nativePtr);
if (!AniParseUtils::Wrap(env, output, ANI_BACK_FORWARD_LIST_INNER_CLASS_NAME,
reinterpret_cast<ani_long>(webHistoryList))) {
WVLOG_E("[TRANSFER] BackForwardList wrap failed");
return ANI_FALSE;
}
webHistoryList->IncRefCount();
return ANI_TRUE;
}
ani_status StsBackForwardListInit(ani_env *env)
{
ani_class backForwardListCls = nullptr;
ani_status status = env->FindClass(ANI_BACK_FORWARD_LIST_INNER_CLASS_NAME, &backForwardListCls);
if (status != ANI_OK || !backForwardListCls) {
WVLOG_E("find %{public}s class failed, status: %{public}d", ANI_BACK_FORWARD_LIST_INNER_CLASS_NAME, status);
return ANI_ERROR;
}
std::array instanceMethods = {
ani_native_function { "getItemAtIndex", nullptr, reinterpret_cast<void *>(GetItemAtIndex) },
};
status = env->Class_BindNativeMethods(backForwardListCls, instanceMethods.data(), instanceMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindNativeMethods failed status: %{public}d", status);
return status;
}
std::array staticMethods = {
ani_native_function { "transferBackForwardListToStaticInner", nullptr,
reinterpret_cast<void *>(TransferBackForwardListToStaticInner) },
};
status = env->Class_BindStaticNativeMethods(backForwardListCls, staticMethods.data(), staticMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindStaticNativeMethods failed status: %{public}d", status);
}
return status;
}
static void Close(ani_env* env, ani_object object)
{
WVLOG_D("[WebMessagePort] close message port");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, object));
if (!msgPort) {
WVLOG_E("close message port failed, napi unwrap msg port failed");
return;
}
ErrCode ret = msgPort->ClosePort();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
return;
}
static ani_boolean TransferWebMessagePortToStaticInner(ani_env* env, ani_class aniClass, ani_object output,
ani_object input, ani_boolean extType)
{
if (!env) {
WVLOG_E("[TRANSFER] env is nullptr");
return ANI_FALSE;
}
void* nativePtr = nullptr;
if (!arkts_esvalue_unwrap(env, input, &nativePtr) || !nativePtr) {
WVLOG_E("[TRANSFER] arkts_esvalue_unwrap failed");
return ANI_FALSE;
}
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort *>(nativePtr);
if (!AniParseUtils::Wrap(env, output, ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME,
reinterpret_cast<ani_long>(msgPort))) {
WVLOG_E("[TRANSFER] WebMessagePort wrap failed");
return ANI_FALSE;
}
msgPort->IncRefCount();
bool isExtentionType = static_cast<bool>(extType);
ani_object jsType = {};
if (!AniParseUtils::CreateBoolean(env, isExtentionType, jsType)) {
return ANI_FALSE;
}
if (env->Object_SetPropertyByName_Ref(output, "isExtentionType", static_cast<ani_ref>(jsType)) != ANI_OK) {
WVLOG_E("[TRANSFER] set isExtentionType failed");
return ANI_FALSE;
}
return ANI_TRUE;
}
bool PostMessageEventMsgHandler(
ani_env* env, ani_object messageObj, bool isString, bool isArrayBuffer,
std::shared_ptr<NWebMessage> webMsg, std::shared_ptr<NWebRomValue> romMsg)
{
WVLOG_D("[WebMessagePort] PostMessageEventMsgHandler");
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
if (isString) {
std::string message;
if (!AniParseUtils::ParseString(env, messageObj, message)) {
WVLOG_E("ParseString failed");
return false;
}
webMsg->SetType(NWebValue::Type::STRING);
webMsg->SetString(message);
romMsg->SetType(NWebRomValue::Type::STRING);
romMsg->SetString(message);
} else if (isArrayBuffer) {
size_t byteLength = 0;
uint8_t* arrayBuffer = nullptr;
auto status = env->ArrayBuffer_GetInfo(reinterpret_cast<ani_arraybuffer>(messageObj), (void**)&arrayBuffer,
&byteLength);
if (status != ANI_OK) {
WVLOG_E("[WebMessagePort] ArrayBuffer_GetInfo failed, status is : %{public}d", status);
return false;
}
std::vector<uint8_t> vecData(arrayBuffer, arrayBuffer + byteLength);
webMsg->SetType(NWebValue::Type::BINARY);
webMsg->SetBinary(vecData);
romMsg->SetType(NWebRomValue::Type::BINARY);
romMsg->SetBinary(vecData);
}
return true;
}
static void PostMessageEvent(ani_env* env, ani_object object, ani_object messageObj)
{
WVLOG_D("[WebMessagePort] (PostMessageEvent) Start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_class arrayBufferClass;
if (auto status = env->FindClass("std.core.Array", &arrayBufferClass) != ANI_OK) {
WVLOG_E("[WebMessagePort] Find class %{public}s failed, status is %{public}d.", "ArrayBuffer", status);
return;
}
ani_boolean isArrayBuffer;
auto stat = env->Object_InstanceOf(messageObj, arrayBufferClass, &isArrayBuffer);
if (stat != ANI_OK) {
WVLOG_E("[WebMessagePort] Find type %{public}s failed, status is %{public}d.", "ArrayBuffer", stat);
return;
}
bool isString = AniParseUtils::IsString(env, messageObj);
if (!isString && !isArrayBuffer) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("[WebMessagePort] (PostMessageEvent) Type Error");
return;
}
auto webMsg = std::make_shared<OHOS::NWeb::NWebMessage>(NWebValue::Type::NONE);
auto romMsg = std::make_shared<OHOS::NWeb::WebViewValue>(NWebRomValue::Type::NONE);
if (!PostMessageEventMsgHandler(env, messageObj, isString, isArrayBuffer, webMsg, romMsg)) {
WVLOG_E("[WebMessagePort] PostMessageEventMsgHandler failed");
return;
}
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, object));
if (!msgPort) {
WVLOG_E("[WebMessagePort] WebMessagePort failed");
return;
}
ErrCode ret = msgPort->PostPortMessage(webMsg, romMsg);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void PostMessageEventExt(ani_env* env, ani_object object, ani_object messageObj)
{
WVLOG_D("[WebMessagePort] (PostMessageEventExt) Start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_class cls;
auto status = env->FindClass("@ohos.web.webview.webview.WebMessageExt", &cls);
if (status != ANI_OK) {
WVLOG_E("[WebMessagePort] Find class %{public}s failed, status is %{public}d.", "WebMessageExt", status);
return;
}
ani_boolean isWebMessageExt;
auto stat = env->Object_InstanceOf(messageObj, cls, &isWebMessageExt);
if (stat != ANI_OK) {
WVLOG_E("[WebMessagePort] Find type %{public}s failed, status is %{public}d.", "WebMessageExt", stat);
return;
}
if (!isWebMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("[WebMessagePort] (PostMessageEventExt) Type Error");
return;
}
WebMessageExt* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, messageObj));
if (!webMessageExt) {
WVLOG_E("[WebMessagePort] WebMessageExt failed");
return;
}
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, object));
if (!msgPort) {
WVLOG_E("[WebMessagePort] WebMessagePort failed");
return;
}
if (!msgPort->IsExtentionType()) {
AniBusinessError::ThrowError(
env, PARAM_CHECK_ERROR, NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_TYPE_INVALID, "message"));
return;
}
ErrCode ret = msgPort->PostPortMessage(webMessageExt->GetData(), webMessageExt->GetValue());
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void OnMessageEvent(ani_env* env, ani_object object, ani_fn_object callback)
{
WVLOG_D("[WebMessagePort] (OnMessageEvent) callback");
if (!env) {
WVLOG_E("[WebMessagePort] env is nullptr");
return;
}
auto callbackImpl = std::make_shared<NWebValueCallbackImpl>(g_vmWebMessagePort, callback, false);
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, object));
if (!msgPort) {
WVLOG_E("[WebMessagePort] Onmessage Unwrap failed");
return;
}
ErrCode ret = msgPort->SetPortMessageCallback(callbackImpl);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void OnMessageEventExt(ani_env* env, ani_object object, ani_fn_object callback)
{
WVLOG_D("[WebMessagePort] (OnMessageEventExt) callback");
if (!env) {
WVLOG_E("[WebMessagePort] env is nullptr");
return;
}
auto callbackImpl = std::make_shared<NWebValueCallbackImpl>(g_vmWebMessagePort, callback, true);
WebMessagePort* msgPort = reinterpret_cast<WebMessagePort*>(AniParseUtils::Unwrap(env, object));
if (!msgPort) {
WVLOG_E("[WebMessagePort] OnMessage Unwrap failed");
return;
}
ErrCode ret = msgPort->SetPortMessageCallback(callbackImpl);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
ani_status StsWebMessagePortInit(ani_env* env)
{
WVLOG_D("[WebMessagePort] StsWebMessagePortInit");
if (!env) {
WVLOG_E("[WebMessagePort] env is nullptr");
return ANI_ERROR;
}
ani_vm* vm = nullptr;
env->GetVM(&vm);
g_vmWebMessagePort = vm;
ani_class webMessagePortCls = nullptr;
ani_status status = env->FindClass(ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME, &webMessagePortCls);
if (status != ANI_OK || !webMessagePortCls) {
WVLOG_E("find %{public}s class failed, status: %{public}d", ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME, status);
return ANI_ERROR;
}
std::array instanceMethods = {
ani_native_function { "close", nullptr, reinterpret_cast<void*>(Close) },
ani_native_function { "postMessageEvent", nullptr, reinterpret_cast<void*>(PostMessageEvent) },
ani_native_function { "onMessageEvent", nullptr, reinterpret_cast<void*>(OnMessageEvent) },
ani_native_function { "postMessageEventExt", nullptr, reinterpret_cast<void*>(PostMessageEventExt) },
ani_native_function { "onMessageEventExt", nullptr, reinterpret_cast<void*>(OnMessageEventExt) },
};
status = env->Class_BindNativeMethods(webMessagePortCls, instanceMethods.data(), instanceMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindNativeMethods failed status: %{public}d", status);
return status;
}
std::array staticMethods = {
ani_native_function { "transferWebMessagePortToStaticInner", nullptr,
reinterpret_cast<void *>(TransferWebMessagePortToStaticInner) },
};
status = env->Class_BindStaticNativeMethods(webMessagePortCls, staticMethods.data(), staticMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindStaticNativeMethods failed status: %{public}d", status);
}
return status;
}
ani_status StsCleanerInit(ani_env *env)
{
ani_class cleanerCls = nullptr;
ani_status status = env->FindClass(ANI_CLASS_CLEANER, &cleanerCls);
if (status != ANI_OK || !cleanerCls) {
WVLOG_E("find %{public}s class failed, status: %{public}d", ANI_CLASS_CLEANER, status);
return status;
}
std::array cleanerMethods = {
ani_native_function { "clean", nullptr, reinterpret_cast<void *>(Clean) },
};
status = env->Class_BindNativeMethods(cleanerCls, cleanerMethods.data(), cleanerMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindNativeMethods failed status: %{public}d", status);
}
return status;
}
static bool CreateWebMessagePortObj(
ani_env* env, ani_object& obj, int32_t nwebId, std::string& port, bool bIsExtentionType)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
if (!AniParseUtils::CreateObjectVoid(env, ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME, obj)) {
WVLOG_E("CreateObjectVoid failed");
return false;
}
WebMessagePort* webMessagePort = new (std::nothrow) WebMessagePort(nwebId, port, bIsExtentionType);
if (!webMessagePort) {
WVLOG_E("new WebMessagePort failed");
return false;
}
if (!AniParseUtils::Wrap(env, obj, ANI_WEB_MESSAGE_PORT_INNER_CLASS_NAME,
reinterpret_cast<ani_long>(webMessagePort))) {
WVLOG_E("WebMessagePort wrap failed");
delete webMessagePort;
webMessagePort = nullptr;
return false;
}
webMessagePort->IncRefCount();
return true;
}
ani_object CreateWebMessagePortsObjOfBoolean(ani_env* env, ani_boolean tempExtentionType)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_class bool_cls;
ani_status status;
if ((status = env->FindClass("std.core.Boolean", &bool_cls)) != ANI_OK) {
WVLOG_E("error in FindClass status : %{public}d", status);
return nullptr;
}
ani_method boolInfoCtor;
if ((status = env->Class_FindMethod(bool_cls, "<ctor>", "z:", &boolInfoCtor)) != ANI_OK) {
WVLOG_E("error in FindMethod status : %{public}d", status);
return nullptr;
}
ani_object boolInfoObj;
if (env->Object_New(bool_cls, boolInfoCtor, &boolInfoObj, tempExtentionType) != ANI_OK) {
WVLOG_E("error in Object_New status : %{public}d", status);
return nullptr;
}
return boolInfoObj;
}
static ani_object CreateWebMessagePortsObj(
ani_env* env, ani_object isExtentionType, int32_t nwebId, std::vector<std::string>& ports)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_boolean isUndefined = ANI_TRUE;
ani_boolean bIsExtentionType = ANI_FALSE;
env->Reference_IsUndefined(isExtentionType, &isUndefined);
if (isUndefined != ANI_TRUE) {
if (env->Object_CallMethodByName_Boolean(isExtentionType, "toBoolean", nullptr,
&bIsExtentionType) != ANI_OK) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "isExtentionType", "boolean"));
return nullptr;
}
}
ani_object arrayObj = nullptr;
ani_class arrayCls = nullptr;
if (env->FindClass("std.core.Array", &arrayCls) != ANI_OK) {
return nullptr;
}
ani_method arrayCtor;
if (env->Class_FindMethod(arrayCls, "<ctor>", "i:", &arrayCtor) != ANI_OK) {
return nullptr;
}
if (env->Object_New(arrayCls, arrayCtor, &arrayObj, ports.size()) != ANI_OK) {
return nullptr;
}
for (size_t i = 0; i < ports.size(); ++i) {
ani_object obj = {};
if (!CreateWebMessagePortObj(env, obj, nwebId, ports[i], static_cast<bool>(bIsExtentionType))) {
return nullptr;
}
if (isUndefined != ANI_TRUE) {
if (env->Object_SetPropertyByName_Ref(obj, "isExtentionType", isExtentionType) != ANI_OK) {
return nullptr;
}
} else {
ani_boolean tempExtentionType = ANI_FALSE;
ani_object boolInfoObj = CreateWebMessagePortsObjOfBoolean(env, tempExtentionType);
env->Object_SetPropertyByName_Ref(obj, "isExtentionType", boolInfoObj);
}
if (env->Object_CallMethodByName_Void(arrayObj, "$_set", "iY:", i, obj) != ANI_OK) {
WVLOG_E("Object_CallMethodByName_Void failed");
return nullptr;
}
}
return arrayObj;
}
static ani_object CreateWebMessagePorts(ani_env* env, ani_object object, ani_object isExtentionType)
{
ani_object result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
WVLOG_E("create message port failed, napi unwrap webviewController failed");
return result;
}
int32_t nwebId = controller->GetWebId();
std::vector<std::string> ports = controller->CreateWebMessagePorts();
if (ports.size() != INTEGER_TWO) {
WVLOG_E("create web message port failed");
return result;
}
return CreateWebMessagePortsObj(env, isExtentionType, nwebId, ports);
}
static void SetConnectionTimeout(ani_env* env, ani_object object, ani_int aniTimeout)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
int32_t timeout = static_cast<int32_t>(aniTimeout);
if (timeout <= 0) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
NWebHelper::Instance().SetConnectionTimeout(timeout);
return;
}
static void BackOrForward(ani_env* env, ani_object object, ani_int step)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->BackOrForward(static_cast<int32_t>(step));
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
return;
}
static void SetWebDebuggingAccess(ani_env* env, ani_object object, ani_boolean aniDebugAccess)
{
WVLOG_D(" SetWebDebuggingAccess start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
bool webDebuggingAccess = static_cast<bool>(aniDebugAccess);
int32_t webDebuggingPort = 0;
if (WebviewController::webDebuggingAccess_ != webDebuggingAccess ||
WebviewController::webDebuggingPort_ != webDebuggingPort) {
NWebHelper::Instance().SetWebDebuggingAccess(webDebuggingAccess);
}
WebviewController::webDebuggingAccess_ = webDebuggingAccess;
WebviewController::webDebuggingPort_ = webDebuggingPort;
return;
}
static void SetWebDebuggingAccessAndPort(
ani_env* env, ani_object object, ani_boolean aniDebugAccess, ani_int aniDebugPort)
{
WVLOG_D(" SetWebDebuggingAccess start");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
bool webDebuggingAccess = static_cast<bool>(aniDebugAccess);
int32_t webDebuggingPort = static_cast<int32_t>(aniDebugPort);
const int32_t kValidPortRangeStart = 1025;
const int32_t kValidPortRangeEnd = 65535;
if (webDebuggingPort < kValidPortRangeStart ||
webDebuggingPort > kValidPortRangeEnd) {
AniBusinessError::ThrowErrorByErrCode(env, NOT_ALLOWED_PORT);
return;
}
if (WebviewController::webDebuggingAccess_ != webDebuggingAccess ||
WebviewController::webDebuggingPort_ != webDebuggingPort) {
NWebHelper::Instance().SetWebDebuggingAccessAndPort(webDebuggingAccess, webDebuggingPort);
}
WebviewController::webDebuggingAccess_ = webDebuggingAccess;
WebviewController::webDebuggingPort_ = webDebuggingPort;
return;
}
static void EnableSafeBrowsing(ani_env* env, ani_object object, ani_boolean enable)
{
WVLOG_D("[WebviewCotr] EnableSafeBrowsing");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->EnableSafeBrowsing(enable);
return;
}
static ani_int GetPageHeight(ani_env *env, ani_object object)
{
int32_t pageHeight = 0;
if (!env) {
WVLOG_E("env is nullptr");
return static_cast<ani_int>(pageHeight);
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return static_cast<ani_int>(pageHeight);
}
pageHeight = controller->GetPageHeight();
return static_cast<ani_int>(pageHeight);
}
WEBVIEW_ANI_STATIC ani_boolean TerminateRenderProcess(ani_env* env, ani_object object)
{
WVLOG_D("TerminateRenderProcess");
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->TerminateRenderProcess()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
WEBVIEW_ANI_STATIC void SetRenderProcessMode(ani_env* env, ani_object object, ani_enum_item mode)
{
WVLOG_D("[WebviewCotr] SetRenderProcessMode");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(mode, &isUndefined) != ANI_OK || isUndefined) {
return;
}
ani_int iMode;
if (env->EnumItem_GetValue_Int(mode, &iMode) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
int32_t renderProcessMode = static_cast<int32_t>(iMode);
WVLOG_I("SetRenderProcessMode mode: %{public}d", renderProcessMode);
NWebHelper::Instance().SetRenderProcessMode(static_cast<RenderProcessMode>(renderProcessMode));
}
WEBVIEW_ANI_STATIC ani_enum_item GetRenderProcessMode(ani_env* env, ani_object object)
{
ani_int renderProcessMode = 0;
ani_enum enumType;
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
if (env->FindEnum("@ohos.web.webview.webview.RenderProcessMode", &enumType) != ANI_OK) {
WVLOG_E("env find enum failed");
return nullptr;
}
renderProcessMode = static_cast<ani_int>(NWebHelper::Instance().GetRenderProcessMode());
WVLOG_D("getRenderProcessMode mode = %{public}d", static_cast<int32_t>(renderProcessMode));
ani_enum_item mode;
if (env->Enum_GetEnumItemByIndex(enumType, renderProcessMode, &mode) != ANI_OK) {
WVLOG_E("env enum_GetEnumItemByIndex failed");
return nullptr;
}
return mode;
}
WEBVIEW_ANI_STATIC void PauseAllTimers(ani_env* env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("PauseAllTimers");
NWebHelper::Instance().PauseAllTimers();
return;
}
WEBVIEW_ANI_STATIC void ResumeAllTimers(ani_env* env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_I("ResumeAllTimers");
NWebHelper::Instance().ResumeAllTimers();
return;
}
static void SetCustomUserAgent(ani_env* env, ani_object object, ani_object userAgentObj)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string userAgent;
if (!AniParseUtils::ParseString(env, userAgentObj, userAgent)) {
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->SetCustomUserAgent(userAgent);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
static void RemoveCache(ani_env* env, ani_object object, ani_boolean clearRom)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->RemoveCache(clearRom);
return;
}
static void SetNetworkAvailable(ani_env* env, ani_object object, ani_boolean enable)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->PutNetworkAvailable(enable);
return;
}
static ani_boolean IsIncognitoMode(ani_env *env, ani_object object)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->IsIncognitoMode()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
WEBVIEW_ANI_STATIC ani_object SerializeWebState(ani_env* env, ani_object object)
{
ani_object result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
void* data = nullptr;
ani_arraybuffer buffer = nullptr;
auto webState = controller->SerializeWebState();
size_t length = webState.size();
if (env->CreateArrayBuffer(length, &data, &buffer) != ANI_OK) {
WVLOG_E("createArrayBuffer failed");
return result;
}
int retCode = memcpy_s(data, length, webState.data(), length);
if (retCode != 0) {
return result;
}
return buffer;
}
static void RestoreWebState(ani_env* env, ani_object object, ani_object value)
{
WVLOG_D("WebviewController RestoreWebState start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webviewController = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!webviewController || !webviewController->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
char* data = nullptr;
size_t total = 0;
size_t offset = 0;
size_t length = 0;
if (env->ArrayBuffer_GetInfo(reinterpret_cast<ani_arraybuffer>(value), reinterpret_cast<void**>(&data), &total) !=
ANI_OK) {
WVLOG_E("ArrayBuffer_GetInfo failed");
return;
}
length = std::min<size_t>(length, total - offset);
std::vector<uint8_t> state(length);
int retCode = memcpy_s(state.data(), state.size(), &data[offset], length);
if (retCode != 0) {
return;
}
webviewController->RestoreWebState(state);
}
static void TrimMemoryByPressureLevel(ani_env *env, ani_object object, ani_double level)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
int32_t memoryLevel = static_cast<int32_t>(level) == 1 ? 0 : static_cast<int32_t>(level);
NWebHelper::Instance().TrimMemoryByPressureLevel(memoryLevel);
return;
}
static void SetPathAllowingUniversalAccess(ani_env* env, ani_object object, ani_object pathList)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::vector<std::string> pathListArr;
if (!AniParseUtils::ParseStringArray(env, pathList, pathListArr)) {
WVLOG_E("SetPathAllowingUniversalAccess ParseStringArray fail");
return;
}
std::string errorPath;
controller->SetPathAllowingUniversalAccess(pathListArr, errorPath);
if (!errorPath.empty()) {
WVLOG_E("%{public}s is invalid.", errorPath.c_str());
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString("BusinessError 401: Parameter error. Path: '%s' is invalid", errorPath.c_str()));
return;
}
}
static void EnableWholeWebPageDrawing(ani_env* env, ani_object object)
{
NWebHelper::Instance().EnableWholeWebPageDrawing();
}
static ani_string GetSurfaceId(ani_env* env, ani_object object)
{
ani_string result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
std::string surfaceId = controller->GetSurfaceId();
if (env->String_NewUTF8(surfaceId.c_str(), surfaceId.size(), &result) != ANI_OK) {
WVLOG_E("create ani_string failed");
return result;
}
return result;
}
static void SetPrintBackground(ani_env* env, ani_object object, ani_boolean enable)
{
bool printBackgroundEnabled = static_cast<bool>(enable);
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->SetPrintBackground(printBackgroundEnabled);
return;
}
static ani_boolean GetPrintBackground(ani_env* env, ani_object object, ani_boolean enable)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (!controller->GetPrintBackground()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static void AddResourceToMemoryCache(ani_env* env, ani_object object, OfflineResourceValueAni resourceValue)
{
WVLOG_D("AddResourceToMemoryCache begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::vector<std::string> urlList;
ani_size byteLength;
uint8_t* arrayBufferUint8 = nullptr;
std::map<std::string, std::string> responseHeaders;
ani_int type = 0;
ani_object urlListObject = static_cast<ani_object>(resourceValue.urlListArray);
if (!AniParseUtils::ParseStringArray(env, urlListObject, urlList)) {
WVLOG_E("InjectOfflineResources ParseStringArray fail");
return;
}
if (env->ArrayBuffer_GetInfo(reinterpret_cast<ani_arraybuffer>(resourceValue.resourceArrayBuffer),
reinterpret_cast<void**>(&arrayBufferUint8), &byteLength) != ANI_OK) {
WVLOG_E("ArrayBuffer_GetInfo failed");
return;
}
std::vector<uint8_t> postData(arrayBufferUint8, arrayBufferUint8 + byteLength);
if (!AniParseUtils::ParseStringArrayMap(env, static_cast<ani_object>(resourceValue.responseHeadersArray),
responseHeaders)) {
WVLOG_E("InjectOfflineResources ParseStringArrayMap fail");
return;
}
env->EnumItem_GetValue_Int(static_cast<ani_enum_item>(resourceValue.typeRef), &type);
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (!controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->InjectOfflineResource(urlList, postData, responseHeaders, type);
}
static void AddResourcesToMemoryCache(
ani_env* env, ani_object object, ani_int resourceMapsCount, ani_object resourceMaps)
{
ani_array resourceMapsRef;
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!object) {
WVLOG_E("object is nullptr");
return;
}
resourceMapsRef = static_cast<ani_array>(resourceMaps);
for (ani_int i = 0; i < resourceMapsCount; i++) {
ani_ref resourceMapItem = nullptr;
env->Array_Get(resourceMapsRef, i, &resourceMapItem);
ani_ref urlListArray = nullptr;
ani_ref resourceArrayBuffer = nullptr;
ani_ref responseHeadersArray = nullptr;
ani_ref typeRef = nullptr;
if (env->Object_GetPropertyByName_Ref(static_cast<ani_object>(resourceMapItem), "urlList", &urlListArray) !=
ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("urlList error");
continue;
}
if (env->Object_GetPropertyByName_Ref(static_cast<ani_object>(resourceMapItem), "resource",
&resourceArrayBuffer) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("resource error");
continue;
}
if (env->Object_GetPropertyByName_Ref(
static_cast<ani_object>(resourceMapItem), "responseHeaders", &responseHeadersArray) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("responseHeaders error");
continue;
}
if (env->Object_GetPropertyByName_Ref(static_cast<ani_object>(resourceMapItem), "type", &typeRef) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
WVLOG_E("type error");
continue;
}
OfflineResourceValueAni resourceValue;
resourceValue.urlListArray = urlListArray;
resourceValue.resourceArrayBuffer = resourceArrayBuffer;
resourceValue.responseHeadersArray = responseHeadersArray;
resourceValue.typeRef = typeRef;
AddResourceToMemoryCache(env, object, resourceValue);
}
}
static void InjectOfflineResources(ani_env* env, ani_object object, ani_object resourceMaps)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!object) {
WVLOG_E("object is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller null");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_int resourceMapsCount;
if (env->Object_GetPropertyByName_Int(resourceMaps, "length", &resourceMapsCount) != ANI_OK) {
WVLOG_E("get resourceMaps length error");
return;
}
size_t resourceMapsCountInt = static_cast<size_t>(resourceMapsCount);
if (resourceMapsCountInt > MAX_RESOURCES_COUNT || resourceMapsCountInt == 0) {
WVLOG_E("BusinessError: 401. The size of 'resourceMaps' must less than %{public}zu and not 0",
MAX_RESOURCES_COUNT);
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
AddResourcesToMemoryCache(env, object, resourceMapsCount, resourceMaps);
}
static void ClearPrefetchedResource(ani_env* env, ani_object aniClass, ani_object cacheKey)
{
WVLOG_D("ClearPrefetchedResource invoked.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_array cacheKeyStr = nullptr;
cacheKeyStr = static_cast<ani_array>(cacheKey);
ani_int cacheKeyCount;
if (env->Object_GetPropertyByName_Int(cacheKey, "length", &cacheKeyCount) != ANI_OK) {
WVLOG_E("get cacheKey length error");
return;
}
std::vector<std::string> cacheKeyList;
for (ani_int i = 0; i < cacheKeyCount; i++) {
ani_ref pathItem = nullptr;
env->Array_Get(cacheKeyStr, i, &pathItem);
std::string path;
if (!AniParseUtils::ParseString(env, pathItem, path)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "cacheKey", "Array<string>"));
return;
}
if (path.empty()) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString("BusinessError 401: Parameter error. Path: '%s' is invalid", path.c_str()));
return;
}
cacheKeyList.emplace_back(path);
}
NWebHelper::Instance().ClearPrefetchedResource(cacheKeyList);
}
static std::shared_ptr<NWebEnginePrefetchArgs> ParsePrefetchArgs(ani_env* env, ani_object object, ani_object request)
{
if (!env) {
return nullptr;
}
ani_ref urlObj = nullptr;
std::string url;
if (env->Object_GetPropertyByName_Ref(request, "url", &urlObj) != ANI_OK) {
return nullptr;
}
if (!ParsePrepareUrl(env, urlObj, url)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return nullptr;
}
ani_ref methodObj = nullptr;
std::string method;
if (env->Object_GetPropertyByName_Ref(request, "method", &methodObj) != ANI_OK) {
return nullptr;
}
if (!ParsePrepareRequestMethod(env, methodObj, method)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return nullptr;
}
ani_ref formDataObj = nullptr;
std::string formData;
if (env->Object_GetPropertyByName_Ref(request, "formData", &formDataObj) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return nullptr;
}
if (!AniParseUtils::ParseString(env, formDataObj, formData)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return nullptr;
}
std::shared_ptr<NWebEnginePrefetchArgs> prefetchArgs =
std::make_shared<NWebEnginePrefetchArgsImpl>(url, method, formData);
return prefetchArgs;
}
static void PrefetchResource(ani_env* env, ani_object object, ani_object request, ani_object additionalHeaders,
ani_object cacheKey, ani_object cacheValidTime)
{
if (!env) {
return;
}
std::shared_ptr<NWebEnginePrefetchArgs> prefetchArgs = ParsePrefetchArgs(env, object, request);
if (!prefetchArgs) {
return;
}
ani_boolean isUndefined = ANI_TRUE;
std::map<std::string, std::string> additionalHttpHeadersObj;
env->Reference_IsUndefined(additionalHeaders, &isUndefined);
if (!isUndefined && !GetWebHeaders(env, additionalHeaders, additionalHttpHeadersObj)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
std::string cacheKeyObj;
if (env->Reference_IsUndefined(cacheKey, &isUndefined) != ANI_OK) {
return;
}
if (!isUndefined && !AniParseUtils::ParseString(env, cacheKey, cacheKeyObj)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (cacheKeyObj.empty()) {
cacheKeyObj = prefetchArgs->GetUrl();
} else {
if (!CheckCacheKey(env, cacheKeyObj)) {
return;
}
}
if (env->Reference_IsUndefined(cacheValidTime, &isUndefined) != ANI_OK) {
return;
}
ani_int cacheValidTimeTemp = 300;
if (!isUndefined &&
(env->Object_CallMethodByName_Int(cacheValidTime, "toInt", ":i", &cacheValidTimeTemp) != ANI_OK)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "duration", "number"));
return;
}
int32_t cacheValidTimeObj = static_cast<int32_t>(cacheValidTimeTemp);
if (cacheValidTimeObj <= 0 || cacheValidTimeObj > INT_MAX) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
NWebHelper::Instance().PrefetchResource(prefetchArgs, additionalHttpHeadersObj, cacheKeyObj, cacheValidTimeObj);
}
static void StartCamera(ani_env* env, ani_object object)
{
WVLOG_D("StartCamera begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->StartCamera();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void CloseAllMediaPresentations(ani_env* env, ani_object object)
{
WVLOG_D("CloseAllMediaPresentations begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->CloseAllMediaPresentations();
return;
}
static void StopAllMedia(ani_env* env, ani_object object)
{
WVLOG_D("StopAllMedia begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->StopAllMedia();
}
static void StopCamera(ani_env* env, ani_object object)
{
WVLOG_D("StopCamera begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->StopCamera();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void CloseCamera(ani_env* env, ani_object object)
{
WVLOG_D("CloseCamera begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->CloseCamera();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void ResumeMicrophone(ani_env* env, ani_object object)
{
WVLOG_D("ResumeMicrophone begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->ResumeMicrophone();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void StopMicrophone(ani_env* env, ani_object object)
{
WVLOG_D("StopMicrophone begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->StopMicrophone();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void PauseMicrophone(ani_env* env, ani_object object)
{
WVLOG_D("PauseMicrophone begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->PauseMicrophone();
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static void PauseAllMedia(ani_env* env, ani_object object)
{
WVLOG_D("PauseAllMedia begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->PauseAllMedia();
}
static void ResumeAllMedia(ani_env* env, ani_object object)
{
WVLOG_D("ResumeAllMedia begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->ResumeAllMedia();
}
static void SetAudioMuted(ani_env* env, ani_object object, ani_boolean mute)
{
WVLOG_D("SetAudioMuted begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->SetAudioMuted(mute);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
static ani_enum_item GetMediaPlaybackState(ani_env* env, ani_object object)
{
WVLOG_D("GetMediaPlaybackState begin");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_int mediaPlaybackState = 0;
ani_enum enumType;
if ((env->FindEnum(ANI_ENUM_MEDIA_PLAY_BACK_STATE, &enumType)) != ANI_OK) {
WVLOG_E("findEnum is error");
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
mediaPlaybackState = static_cast<ani_int>(controller->GetMediaPlaybackState());
ani_enum_item state;
if ((env->Enum_GetEnumItemByIndex(enumType, mediaPlaybackState, &state)) != ANI_OK) {
WVLOG_E("getEnum is error");
return nullptr;
}
return state;
}
void OnCreateNativeMediaPlayer(ani_env* env, ani_object object, ani_fn_object callback)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_vm *vm = nullptr;
if (env->GetVM(&vm) != ANI_OK) {
WVLOG_E("Failed to get VM from env");
return;
}
g_vm = vm;
WVLOG_D("put on_create_native_media_player callback");
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->OnCreateNativeMediaPlayer(g_vm, callback);
}
static void AvoidVisibleViewportBottom(ani_env* env, ani_object object, ani_int avoidHeight)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->AvoidVisibleViewportBottom(avoidHeight);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
return;
}
bool ParseJsLengthDoubleToInt(ani_env* env, ani_ref ref, int32_t& outValue)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
ani_double value = 0;
ani_status status = env->Object_CallMethodByName_Double(static_cast<ani_object>(ref), "toDouble", ":d", &value);
if (status != ANI_OK) {
WVLOG_E("ParseJsLengthDoubleToInt failed status: %{public}d ", status);
return false;
}
outValue = static_cast<int32_t>(value);
return true;
}
bool ParseJsLengthResourceToInt(ani_env* env, ani_object jsLength, PixelUnit& type, int32_t& result)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
ani_double resIdDouble;
if ((env->Object_GetPropertyByName_Double(jsLength, "id", &resIdDouble) != ANI_OK)) {
WVLOG_E("Object_GetPropertyByName_Double failed");
return false;
}
int32_t resId = static_cast<int32_t>(resIdDouble);
std::shared_ptr<AbilityRuntime::ApplicationContext> context =
AbilityRuntime::ApplicationContext::GetApplicationContext();
if (!context) {
WVLOG_E("WebPageSnapshot Failed to get application context.");
return false;
}
auto resourceManager = context->GetResourceManager();
if (!resourceManager) {
WVLOG_E("WebPageSnapshot Failed to get resource manager.");
return false;
}
ani_ref jsResourceType = nullptr;
if (env->Object_GetPropertyByName_Ref(jsLength, "type", &jsResourceType) != ANI_OK) {
return false;
}
if (AniParseUtils::IsDouble(env, static_cast<ani_object>(jsResourceType))) {
int32_t resourceTypeNum;
ParseJsLengthDoubleToInt(env, jsResourceType, resourceTypeNum);
std::string resourceString;
switch (resourceTypeNum) {
case static_cast<int>(ResourceType::INTEGER):
if (resourceManager->GetIntegerById(resId, result) == Global::Resource::SUCCESS) {
type = PixelUnit::VP;
return true;
}
break;
case static_cast<int>(ResourceType::STRING):
if (resourceManager->GetStringById(resId, resourceString) == Global::Resource::SUCCESS) {
return AniParseUtils::ParseJsLengthStringToInt(resourceString, type, result);
}
break;
default:
WVLOG_E("WebPageSnapshot resource type not support");
break;
}
return false;
}
return false;
}
bool ParseJsLengthToInt(ani_env* env, ani_object jsLength, PixelUnit& type, int32_t& result)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
if ((!AniParseUtils::IsResource(env, jsLength)) && (!AniParseUtils::IsString(env, jsLength)) &&
(!AniParseUtils::IsDouble(env, jsLength))) {
WVLOG_E("WebPageSnapshot Unable to parse js length object.");
return false;
}
if (AniParseUtils::IsDouble(env, jsLength)) {
ParseJsLengthDoubleToInt(env, jsLength, result);
type = PixelUnit::VP;
return true;
}
if (AniParseUtils::IsString(env, jsLength)) {
std::string nativeString;
AniParseUtils::ParseString(env, jsLength, nativeString);
if (!AniParseUtils::ParseJsLengthStringToInt(nativeString, type, result)) {
return false;
}
return true;
}
if (AniParseUtils::IsResource(env, jsLength)) {
return ParseJsLengthResourceToInt(env, jsLength, type, result);
}
return false;
}
static void JsErrorCallback(ani_env* env, ani_ref jsCallback, int32_t err)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_object jsResult = {};
ani_ref jsError = AniBusinessError::CreateError(env, err);
ani_fn_object callbackFn = static_cast<ani_fn_object>(jsCallback);
std::vector<ani_ref> vec;
vec.push_back(jsError);
vec.push_back(jsResult);
ani_ref fnReturnVal;
if (env->FunctionalObject_Call(callbackFn, ani_size(RESULT_COUNT), vec.data(), &fnReturnVal) != ANI_OK) {
WVLOG_E("FunctionalObject_Call failed");
}
}
bool CreateSizeObject(ani_env* env, const char* className, ani_object& object, ani_int size)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
ani_class cls;
ani_status status = env->FindClass(className, &cls);
if (status != ANI_OK) {
WVLOG_E("find %{public}s class failed, status: %{public}d", className, status);
return false;
}
ani_method ctor;
if ((status = env->Class_FindMethod(cls, "<ctor>", "i:", &ctor)) != ANI_OK) {
WVLOG_E("get %{public}s ctor method failed, status: %{public}d", className, status);
return false;
}
if ((status = env->Object_New(cls, ctor, &object, size)) != ANI_OK) {
WVLOG_E("new %{public}s failed, status: %{public}d", className, status);
return false;
}
return true;
}
WebSnapshotCallback CreateWebPageSnapshotResultCallback(
ani_env* env, ani_ref jsCallback, bool check, int32_t inputWidth, int32_t inputHeight)
{
return [env, jCallback = std::move(jsCallback), check, inputWidth, inputHeight](const char* returnId,
bool returnStatus, float radio, void* returnData, int returnWidth, int returnHeight) {
WVLOG_I("WebPageSnapshot return ani callback");
ani_object jsResult = {};
if (AniParseUtils::CreateObjectVoid(env, ANI_SNAPSHOT_RESULT_CLASS_NAME, jsResult) == false) {
WVLOG_E("jsResult CreateObjectVoid failed");
return;
}
ani_object jsPixelMap = nullptr;
Media::InitializationOptions opt;
opt.size.width = static_cast<int32_t>(returnWidth);
opt.size.height = static_cast<int32_t>(returnHeight);
opt.pixelFormat = Media::PixelFormat::RGBA_8888;
opt.alphaType = Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
opt.editable = true;
auto pixelMap = Media::PixelMap::Create(opt);
if (pixelMap != nullptr) {
uint64_t stride = static_cast<uint64_t>(returnWidth) << 2;
uint64_t bufferSize = stride * static_cast<uint64_t>(returnHeight);
pixelMap->WritePixels(static_cast<const uint8_t*>(returnData), bufferSize);
std::shared_ptr<Media::PixelMap> pixelMapToJs(pixelMap.release());
jsPixelMap = OHOS::Media::PixelMapTaiheAni::CreateEtsPixelMap(env, pixelMapToJs);
} else {
WVLOG_E("WebPageSnapshot create pixel map error");
}
if (env->Object_SetPropertyByName_Ref(jsResult, "imagePixelMap", jsPixelMap) != ANI_OK) {
WVLOG_E("Object_SetPropertyByName_Ref failed");
return;
}
int returnJsWidth = 0;
int returnJsHeight = 0;
if (radio > 0) {
returnJsWidth = returnWidth / radio;
returnJsHeight = returnHeight / radio;
}
if (check) {
if (std::abs(returnJsWidth - inputWidth) < INTEGER_THREE) {
returnJsWidth = inputWidth;
}
if (std::abs(returnJsHeight - inputHeight) < INTEGER_THREE) {
returnJsHeight = inputHeight;
}
}
ani_object jsSzieObj = {};
if (AniParseUtils::CreateObjectVoid(env, ANI_SIZE_OPTIONS_CLASS_NAME, jsSzieObj) == false) {
WVLOG_E("jsResult CreateObjectVoid failed");
return;
}
ani_object jsWidthObj = {};
if (CreateSizeObject(env, "std.core.Int", jsWidthObj, static_cast<ani_int>(returnJsWidth)) == false) {
WVLOG_E("jsWidthObj CreateSizeObject failed");
return;
}
ani_object jsHeightObj = {};
if (CreateSizeObject(env, "std.core.Int", jsHeightObj, static_cast<ani_int>(returnJsHeight)) == false) {
WVLOG_E("jsHeightObj CreateSizeObject failed");
return;
}
auto status = env->Object_SetPropertyByName_Ref(jsSzieObj, "width", static_cast<ani_ref>(jsWidthObj));
if (status != ANI_OK) {
WVLOG_E("returnJsWidth set failed : %{public}d", status);
return;
}
if (env->Object_SetPropertyByName_Ref(jsSzieObj, "height", static_cast<ani_ref>(jsHeightObj)) != ANI_OK) {
WVLOG_E("returnJsHeight set failed");
return;
}
if (env->Object_SetPropertyByName_Ref(jsResult, "size", jsSzieObj) != ANI_OK) {
WVLOG_E("jsSzieObj set failed");
return;
}
ani_string jsId = nullptr;
if (env->String_NewUTF8(returnId, strlen(returnId), &jsId) != ANI_OK) {
WVLOG_E("String_NewUTF8 failed");
return;
}
env->Object_SetPropertyByName_Ref(jsResult, "id", jsId);
ani_object jsStatus = {};
if (!AniParseUtils::CreateBoolean(env, returnStatus, jsStatus)) {
WVLOG_E("CreateBoolean failed");
return;
}
env->Object_SetPropertyByName_Ref(jsResult, "status", jsStatus);
ani_object jsError = {};
ani_ref callbackResult;
std::vector<ani_ref> vec;
vec.push_back(jsError);
vec.push_back(jsResult);
ani_fn_object callbackFn = static_cast<ani_fn_object>(jCallback);
if (env->FunctionalObject_Call(callbackFn, ani_size(RESULT_COUNT), vec.data(), &callbackResult) != ANI_OK) {
WVLOG_E("execute callFunction failed");
}
if (env->GlobalReference_Delete(jCallback) != ANI_OK) {
WVLOG_E("delete global Ref failed");
return;
}
g_inWebPageSnapshot = false;
};
}
bool ParseSnapshotOptions(ani_env* env, ani_object info, SnapshotOptions& options)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
ani_ref snapshotId = nullptr;
ani_ref snapshotSize = nullptr;
ani_ref snapshotSizeWidth = nullptr;
ani_ref snapshotSizeHeight = nullptr;
if (env->Object_GetPropertyByName_Ref(info, "id", &snapshotId) == ANI_OK) {
if (!AniParseUtils::ParseString(env, snapshotId, options.id)) {
WVLOG_E("ParseString failed");
return false;
}
}
if (env->Object_GetPropertyByName_Ref(info, "size", &snapshotSize) == ANI_OK) {
ani_object snapshotSizeObj = static_cast<ani_object>(snapshotSize);
if (env->Object_GetPropertyByName_Ref(snapshotSizeObj, "width", &snapshotSizeWidth) == ANI_OK) {
ani_object snapshotSizeWidthObj = static_cast<ani_object>(snapshotSizeWidth);
if (!ParseJsLengthToInt(env, snapshotSizeWidthObj, options.widthType, options.width)) {
return false;
}
}
if (env->Object_GetPropertyByName_Ref(snapshotSizeObj, "height", &snapshotSizeHeight) == ANI_OK) {
ani_object snapshotSizeHeightObj = static_cast<ani_object>(snapshotSizeHeight);
if (!ParseJsLengthToInt(env, snapshotSizeHeightObj, options.heightType, options.height)) {
return false;
}
}
}
if (options.widthType != PixelUnit::NONE && options.heightType != PixelUnit::NONE &&
options.widthType != options.heightType) {
WVLOG_E("WebPageSnapshot input different pixel unit");
return false;
}
if (options.widthType != PixelUnit::NONE) {
options.sizeType = options.widthType;
} else if (options.heightType != PixelUnit::NONE) {
options.sizeType = options.heightType;
}
if (options.width < 0 || options.height < 0) {
WVLOG_E("WebPageSnapshot input pixel length less than 0");
return false;
}
return true;
}
static void WebPageSnapshot(ani_env* env, ani_object object, ani_object info, ani_object callback)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!AniParseUtils::IsFunction(env, callback)) {
WVLOG_E("callback is not function");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (g_inWebPageSnapshot) {
JsErrorCallback(env, std::move(callback), FUNCTION_NOT_ENABLE);
return;
}
g_inWebPageSnapshot = true;
SnapshotOptions options;
if (!ParseSnapshotOptions(env, info, options)) {
WVLOG_E("ParseSnapshotOptions failed");
JsErrorCallback(env, std::move(callback), PARAM_CHECK_ERROR);
g_inWebPageSnapshot = false;
return;
}
bool pixelCheck = (options.sizeType == PixelUnit::VP);
WVLOG_I("WebPageSnapshot pixel type :%{public}d", static_cast<int>(options.sizeType));
ani_ref callbackRef;
if (ANI_OK != env->GlobalReference_Create(callback, &callbackRef)) {
WVLOG_E("WebPageSnapshot failed to create reference for callback");
return;
}
auto resultCallback =
CreateWebPageSnapshotResultCallback(env, std::move(callbackRef), pixelCheck, options.width, options.height);
ErrCode ret = controller->WebPageSnapshot(
options.id.c_str(), options.sizeType, options.width, options.height, std::move(resultCallback));
if (ret != NO_ERROR) {
g_inWebPageSnapshot = false;
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
static void InnerCompleteWindowNew(ani_env* env, ani_object object, ani_int parentNWebId)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("InnerCompleteWindow webviewController is nullptr");
return;
}
controller->InnerCompleteWindowNew(parentNWebId);
}
ani_object PrecompileJavaScriptPromise(ani_env* env, ani_object object, std::string url, std::string script,
std::shared_ptr<OHOS::NWeb::CacheOptions> cacheOptions)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
WVLOG_D("PrecompileJavaScript Begin");
ani_resolver resolver {};
ani_object promise {};
ani_status status = env->Promise_New(&resolver, &promise);
if (status != ANI_OK) {
WVLOG_E("promise_new failed");
return nullptr;
}
auto callbackImpl = std::make_shared<OHOS::NWeb::NWebPrecompileCallback>();
callbackImpl->SetCallback([env, resolver](int64_t result) -> void {
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_object resolution = AniParseUtils::CreateInt(env, result);
if (result == static_cast<int64_t>(PrecompileError::OK)) {
if (env->PromiseResolver_Resolve(resolver, resolution) != ANI_OK) {
WVLOG_E("PromiseResolver_Resolve fail");
}
} else {
if (env->PromiseResolver_Reject(resolver, static_cast<ani_error>(resolution)) != ANI_OK) {
WVLOG_E("PromiseResolver_Reject fail");
}
}
});
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("PrecompileJavaScript controller fail");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
controller->PrecompileJavaScript(url, script, cacheOptions, callbackImpl);
return promise;
}
ani_object PrecompileJavaScript(
ani_env* env, ani_object object, ani_object url, ani_object script, ani_object cacheOptions)
{
ani_object result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
std::string urlStr;
if (!AniParseUtils::ParseString(env, url, urlStr)) {
WVLOG_E("Parse url failed.");
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "url", "string"));
return result;
}
auto cacheOptionsPtr = AniParseUtils::ParseCacheOptions(env, cacheOptions);
ani_class ArrayBufferCls;
env->FindClass("std.core.ArrayBuffer", &ArrayBufferCls);
ani_boolean isArrayBuffer;
std::string scriptStr;
ani_status res = env->Object_InstanceOf(script, ArrayBufferCls, &isArrayBuffer);
if (res != ANI_OK) {
WVLOG_E("Object_InstanceOf failed");
return result;
}
if (isArrayBuffer) {
uint8_t* arrayBuffer = nullptr;
ani_size byteLength;
if (env->ArrayBuffer_GetInfo(reinterpret_cast<ani_arraybuffer>(script), reinterpret_cast<void**>(&arrayBuffer),
&byteLength) != ANI_OK) {
WVLOG_E("ArrayBuffer_GetInfo failed");
AniBusinessError::ThrowErrorByErrCode(env, NWebError::PARAM_CHECK_ERROR);
return result;
}
std::vector<uint8_t> postData(arrayBuffer, arrayBuffer + byteLength);
scriptStr = std::string(postData.begin(), postData.end());
} else {
if (!AniParseUtils::ParseString(env, script, scriptStr)) {
WVLOG_E("PrecompileJavaScript :script must be string or Uint8Array");
return result;
}
}
return PrecompileJavaScriptPromise(env, object, urlStr, scriptStr, cacheOptionsPtr);
}
static void ConstructorExt(ani_env* env, ani_object object)
{
if (g_WebMessagePort) {
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto webMsg = std::make_shared<OHOS::NWeb::NWebMessage>(NWebValue::Type::NONE);
auto romMsg = std::make_shared<OHOS::NWeb::WebViewValue>(NWebRomValue::Type::NONE);
WebMessageExt* webMessageExt = new (std::nothrow) WebMessageExt(webMsg, romMsg);
if (!webMessageExt) {
WVLOG_E("new webMessageExt failed");
return;
}
if (!AniParseUtils::Wrap(env, object, ANI_WEB_MESSAGE_EXT_NAME, reinterpret_cast<ani_long>(webMessageExt))) {
WVLOG_E("webview webMessageExt wrap failed");
delete webMessageExt;
webMessageExt = nullptr;
}
}
}
static void SetType(ani_env* env, ani_object object, ani_enum_item value)
{
WVLOG_D("WebMessageExt SetType start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_int iValue;
if (env->EnumItem_GetValue_Int(value, &iValue) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
int32_t typeValue = static_cast<int32_t>(iValue);
webMessageExt->SetType(typeValue);
}
static void SetString(ani_env* env, ani_object object, ani_string aniValue)
{
WVLOG_D("WebMessageExt SetString start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string value;
if (!AniParseUtils::ParseString(env, aniValue, value)) {
WVLOG_E("Parse url failed.");
return;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::STRING)) {
WVLOG_E("web message SetString error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
webMessageExt->SetString(value);
}
static void SetNumber(ani_env* env, ani_object object, ani_double value)
{
WVLOG_D("WebMessageExt SetNumber start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::NUMBER)) {
WVLOG_E("web message SetNumber error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
webMessageExt->SetNumber(static_cast<double>(value));
}
static void SetBoolean(ani_env* env, ani_object object, ani_boolean value)
{
WVLOG_D("WebMessageExt SetBoolean start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::BOOLEAN)) {
WVLOG_E("web message SetBoolean error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
webMessageExt->SetBoolean(static_cast<bool>(value));
}
static void SetArrayBuffer(ani_env* env, ani_object object, ani_object value)
{
WVLOG_D("WebMessageExt SetArrayBuffer start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
char* arrayBuffer = nullptr;
size_t byteLength = 0;
if (env->ArrayBuffer_GetInfo(
reinterpret_cast<ani_arraybuffer>(value), reinterpret_cast<void**>(&arrayBuffer), &byteLength) != ANI_OK) {
WVLOG_E("ArrayBuffer_GetInfo failed");
return;
}
std::vector<uint8_t> vecData(arrayBuffer, arrayBuffer + byteLength);
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ARRAYBUFFER)) {
WVLOG_E("web message SetArrayBuffer error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
webMessageExt->SetArrayBuffer(vecData);
}
static void HandleStringArray(ani_env* env, ani_object array, WebMessageExt* webMessageExt)
{
std::vector<std::string> strVec;
if (!AniParseUtils::ParseStringArray(env, array, strVec)) {
WVLOG_E("WebMessageExt ParseStringArray error");
return;
}
webMessageExt->SetStringArray(strVec);
}
static void HandleBooleanArray(ani_env* env, ani_object array, WebMessageExt* webMessageExt)
{
std::vector<bool> boolVec;
if (!AniParseUtils::ParseBooleanArray(env, array, boolVec)) {
WVLOG_E("WebMessageExt ParseBooleanArray error");
return;
}
webMessageExt->SetBooleanArray(boolVec);
}
static void HandleDoubleArray(ani_env* env, ani_object array, WebMessageExt* webMessageExt)
{
std::vector<double> doubleVec;
if (!AniParseUtils::ParseDoubleArray(env, array, doubleVec)) {
WVLOG_E("WebMessageExt ParseDoubleArray error");
return;
}
webMessageExt->SetDoubleArray(doubleVec);
}
static void HandleInt64Array(ani_env* env, ani_object array, WebMessageExt* webMessageExt)
{
std::vector<int64_t> intVec;
if (!AniParseUtils::ParseInt64Array(env, array, intVec)) {
WVLOG_E("WebMessageExt ParseInt64Array error");
return;
}
webMessageExt->SetInt64Array(intVec);
}
bool UseDouble(ani_env* env, const ani_ref& element, bool& isDouble)
{
if (!env) {
WVLOG_E("env is null");
return false;
}
int elementInt = 0;
double elementDouble = 0.0;
if (env->Object_CallMethodByName_Int(static_cast<ani_object>(element), "toInt", ":i", &elementInt) != ANI_OK) {
WVLOG_E("to int value failed");
return false;
}
if (env->Object_CallMethodByName_Double(static_cast<ani_object>(element), "toDouble", ":d", &elementDouble) !=
ANI_OK) {
WVLOG_E("to double value failed");
return false;
}
isDouble = abs(elementDouble - elementInt * 1.0) > MINIMAL_ERROR;
return true;
}
static void SetArray(ani_env* env, ani_object object, ani_object array)
{
WVLOG_D("WebMessageExt SetArray start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ARRAY)) {
WVLOG_E("web message SetArray error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
ani_ref element = nullptr;
if (env->Array_Get(static_cast<ani_array>(array), 0, &element) != ANI_OK) {
WVLOG_E("WebMessageExt get element from array error");
return;
}
ani_object elementObj = static_cast<ani_object>(element);
bool isDouble = false;
if (AniParseUtils::IsString(env, elementObj)) {
HandleStringArray(env, array, webMessageExt);
} else if (AniParseUtils::IsBoolean(env, elementObj)) {
HandleBooleanArray(env, array, webMessageExt);
} else if (AniParseUtils::IsDouble(env, elementObj)) {
HandleDoubleArray(env, array, webMessageExt);
} else if (AniParseUtils::IsInteger(env, elementObj)) {
if (!UseDouble(env, element, isDouble)) {
WVLOG_E("UseDouble execute failed");
return;
}
if (isDouble) {
HandleDoubleArray(env, array, webMessageExt);
} else {
HandleInt64Array(env, array, webMessageExt);
}
} else {
WVLOG_E("Unsupported array element type");
}
}
static void SetError(ani_env* env, ani_object object, ani_object errorMsg)
{
WVLOG_D("WebMessageExt setError start.");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_ref aniName;
if (env->Object_GetPropertyByName_Ref(errorMsg, "name", &aniName) != ANI_OK) {
return;
}
ani_ref aniMessage;
if (env->Object_GetPropertyByName_Ref(errorMsg, "message", &aniMessage) != ANI_OK) {
return;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ERROR)) {
WVLOG_E("web message setError error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return;
}
std::string name;
if (!AniParseUtils::ParseString(env, aniName, name)) {
return;
}
std::string message;
if (!AniParseUtils::ParseString(env, aniMessage, message)) {
return;
}
webMessageExt->SetError(name, message);
}
static ani_enum_item GetType(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetType.");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
WVLOG_D("WebMessageExt GetType.");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
ani_int typeMode = 0;
ani_enum enumType;
env->FindEnum("@ohos.web.webview.webview.WebMessageType", &enumType);
typeMode = static_cast<ani_int>(webMessageExt->GetType());
WVLOG_D("WebMessageExt mode = %{public}d", static_cast<int32_t>(typeMode));
ani_enum_item mode;
env->Enum_GetEnumItemByIndex(enumType, typeMode, &mode);
return mode;
}
static ani_string GetString(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetString.");
ani_string result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::STRING)) {
WVLOG_E("web message setError error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return result;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("message data is nullptr");
return result;
}
std::string stringMsg = message->GetString();
env->String_NewUTF8(stringMsg.c_str(), stringMsg.size(), &result);
return result;
}
static ani_object GetNumber(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetNumber.");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::NUMBER)) {
WVLOG_E("web message GetNumber error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return nullptr;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("message data is nullptr");
return nullptr;
}
return static_cast<ani_object>(AniParseUtils::ConvertNWebToAniValue(env, message));
}
static ani_boolean GetBoolean(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetBoolean.");
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::BOOLEAN)) {
WVLOG_E("web message GetBoolean error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return ANI_FALSE;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("message data is nullptr");
return ANI_FALSE;
}
return static_cast<ani_boolean>(message->GetBoolean());
}
static ani_object GetArrayBuffer(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetArrayBuffer.");
ani_object result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ARRAYBUFFER)) {
WVLOG_E("web message GetArrayBuffer error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return result;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("message data is nullptr");
return result;
}
auto getArrayBuffer = message->GetBinary();
void* arrayData = nullptr;
ani_arraybuffer arraybuffer;
ani_status status = env->CreateArrayBuffer(getArrayBuffer.size(), &arrayData, &arraybuffer);
if (status != ANI_OK) {
WVLOG_E("Create arraybuffer failed");
return arraybuffer;
}
for (size_t i = 0; i < getArrayBuffer.size(); ++i) {
*(uint8_t*)((uint8_t*)arrayData + i) = getArrayBuffer[i];
}
return arraybuffer;
}
ani_object ConvertToAniHandlerOfStringArray(ani_env* env, std::shared_ptr<NWebMessage> src)
{
if (!src) {
WVLOG_E("src is nullptr");
return nullptr;
}
std::vector<std::string> values = src->GetStringArray();
ani_ref undefinedRef = nullptr;
if (ANI_OK != env->GetUndefined(&undefinedRef)) {
WVLOG_E("WebMessageExt GetUndefined Failed.");
return nullptr;
}
ani_array array = nullptr;
if (ANI_OK != env->Array_New(values.size(), undefinedRef, &array)) {
WVLOG_E("WebMessageExt new array ref error.");
return array;
}
for (size_t i = 0; i < values.size(); ++i) {
ani_string result {};
if (ANI_OK != env->String_NewUTF8(values[i].c_str(), values[i].size(), &result)) {
continue;
}
if (ANI_OK != env->Array_Set(array, i, result)) {
return array;
}
}
return array;
}
ani_object ConvertToAniHandlerOfBooleanArray(ani_env* env, std::shared_ptr<NWebMessage> src)
{
if (!src) {
WVLOG_E("src is nullptr");
return nullptr;
}
std::vector<bool> values = src->GetBooleanArray();
size_t valueSize = values.size();
ani_ref undefinedRef = nullptr;
if (ANI_OK != env->GetUndefined(&undefinedRef)) {
WVLOG_E("WebMessageExt GetUndefined Failed.");
return nullptr;
}
ani_array array = nullptr;
if (ANI_OK != env->Array_New(values.size(), undefinedRef, &array)) {
WVLOG_E("WebMessageExt new array ref error.");
return array;
}
ani_class booleanCls {};
if (ANI_OK != env->FindClass("std.core.Boolean", &booleanCls)) {
return nullptr;
}
ani_method ctor {};
if (ANI_OK != env->Class_FindMethod(booleanCls, "<ctor>", "z:", &ctor)) {
return nullptr;
}
for (size_t i = 0; i < valueSize; i++) {
ani_boolean item = static_cast<ani_boolean>(values[i]);
ani_object obj {};
if (env->Object_New(booleanCls, ctor, &obj, item) != ANI_OK) {
return nullptr;
}
if (ANI_OK != env->Array_Set(array, i, obj)) {
return array;
}
}
return array;
}
ani_object ConvertToAniHandlerOfDoubleArray(ani_env* env, std::shared_ptr<NWebMessage> src)
{
if (!src) {
WVLOG_E("src is nullptr");
return nullptr;
}
std::vector<double> values = src->GetDoubleArray();
size_t valueSize = values.size();
ani_ref undefinedRef = nullptr;
if (ANI_OK != env->GetUndefined(&undefinedRef)) {
WVLOG_E("WebMessageExt GetUndefined Failed.");
return nullptr;
}
ani_array array = nullptr;
if (ANI_OK != env->Array_New(values.size(), undefinedRef, &array)) {
WVLOG_E("WebMessageExt new array ref error.");
return array;
}
ani_class cls {};
if (ANI_OK != env->FindClass("std.core.Double", &cls)) {
return nullptr;
}
ani_method ctor {};
if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "d:", &ctor)) {
return nullptr;
}
for (size_t i = 0; i < valueSize; i++) {
ani_double item = static_cast<ani_double>(values[i]);
ani_object obj {};
if (env->Object_New(cls, ctor, &obj, item) != ANI_OK) {
return nullptr;
}
if (ANI_OK != env->Array_Set(array, i, obj)) {
return array;
}
}
return array;
}
ani_object ConvertToAniHandlerOfInt64Array(ani_env* env, std::shared_ptr<NWebMessage> src)
{
if (!src) {
WVLOG_E("src is nullptr");
return nullptr;
}
std::vector<int64_t> values = src->GetInt64Array();
size_t valueSize = values.size();
ani_ref undefinedRef = nullptr;
if (ANI_OK != env->GetUndefined(&undefinedRef)) {
WVLOG_E("WebMessageExt GetUndefined Failed.");
return nullptr;
}
ani_array array = nullptr;
if (ANI_OK != env->Array_New(values.size(), undefinedRef, &array)) {
WVLOG_E("WebMessageExt new array ref error.");
return array;
}
ani_class cls {};
if (ANI_OK != env->FindClass("std.core.Long", &cls)) {
return nullptr;
}
ani_method ctor {};
if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "l:", &ctor)) {
return nullptr;
}
for (size_t i = 0; i < valueSize; i++) {
ani_long item = static_cast<ani_long>(values[i]);
ani_object obj {};
if (env->Object_New(cls, ctor, &obj, item) != ANI_OK) {
return nullptr;
}
if (ANI_OK != env->Array_Set(array, i, obj)) {
return array;
}
}
return array;
}
static ani_object GetArray(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetArray Start.");
ani_object result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ARRAY)) {
WVLOG_E("web message GetArray error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return result;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("web message failed.");
return result;
}
NWebValue::Type type = message->GetType();
if (type == NWebValue::Type::STRINGARRAY) {
result = ConvertToAniHandlerOfStringArray(env, message);
return result;
}
if (type == NWebValue::Type::BOOLEANARRAY) {
result = ConvertToAniHandlerOfBooleanArray(env, message);
return result;
}
if (type == NWebValue::Type::DOUBLEARRAY) {
result = ConvertToAniHandlerOfDoubleArray(env, message);
return result;
}
if (type == NWebValue::Type::INT64ARRAY) {
result = ConvertToAniHandlerOfInt64Array(env, message);
return result;
}
return result;
}
static ani_string GetError(ani_env* env, ani_object object)
{
WVLOG_D("WebMessageExt GetError Start.");
ani_string result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto* webMessageExt = reinterpret_cast<WebMessageExt*>(AniParseUtils::Unwrap(env, object));
if (!webMessageExt) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return result;
}
if (webMessageExt->GetType() != static_cast<int32_t>(WebMessageType::ERROR)) {
WVLOG_E("web message GetError error type:%{public}d", webMessageExt->GetType());
AniBusinessError::ThrowErrorByErrCode(env, TYPE_NOT_MATCH_WITCH_VALUE);
return result;
}
auto message = webMessageExt->GetData();
if (!message) {
WVLOG_E("message data is nullptr");
return result;
}
std::string errMsg = message->GetErrName() + ": " + message->GetErrMsg();
env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &result);
return result;
}
ani_status StsWebMessageExtInit(ani_env* env)
{
if (!env) {
WVLOG_E("env is nullptr");
return ANI_ERROR;
}
ani_class webMessageExtCls = nullptr;
ani_status status = env->FindClass(ANI_WEB_MESSAGE_EXT_NAME, &webMessageExtCls);
if (status != ANI_OK || !webMessageExtCls) {
WVLOG_E("find %{public}s class failed, status: %{public}d", ANI_WEB_MESSAGE_EXT_NAME, status);
return status;
}
std::array webMessageExtMethods = {
ani_native_function { "<ctor>", nullptr, reinterpret_cast<void*>(ConstructorExt) },
ani_native_function { "setType", nullptr, reinterpret_cast<void*>(SetType) },
ani_native_function { "setString", nullptr, reinterpret_cast<void*>(SetString) },
ani_native_function { "setNumber", nullptr, reinterpret_cast<void*>(SetNumber) },
ani_native_function { "setBoolean", nullptr, reinterpret_cast<void*>(SetBoolean) },
ani_native_function { "setArrayBuffer", nullptr, reinterpret_cast<void*>(SetArrayBuffer) },
ani_native_function { "setArray", nullptr, reinterpret_cast<void *>(SetArray) },
ani_native_function { "setError", nullptr, reinterpret_cast<void*>(SetError) },
ani_native_function { "getType", nullptr, reinterpret_cast<void*>(GetType) },
ani_native_function { "getString", nullptr, reinterpret_cast<void*>(GetString) },
ani_native_function { "getNumber", nullptr, reinterpret_cast<void*>(GetNumber) },
ani_native_function { "getBoolean", nullptr, reinterpret_cast<void*>(GetBoolean) },
ani_native_function { "getArrayBuffer", nullptr, reinterpret_cast<void*>(GetArrayBuffer) },
ani_native_function { "getArray", nullptr, reinterpret_cast<void *>(GetArray) },
ani_native_function { "getError", nullptr, reinterpret_cast<void*>(GetError) },
};
status = env->Class_BindNativeMethods(webMessageExtCls, webMessageExtMethods.data(), webMessageExtMethods.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindNativeMethods failed status: %{public}d", status);
}
return status;
}
static void InnerJsProxy(ani_env* env, ani_object object, ani_object obj, ani_string name, ani_array methodList,
ani_object asyncMethodList, ani_object permission)
{
if (env == nullptr) {
return;
}
ani_vm* vm = nullptr;
if (env->GetVM(&vm) != ANI_OK) {
return;
}
ani_ref webviewObj;
if (env->GlobalReference_Create(reinterpret_cast<ani_ref>(object), &webviewObj) != ANI_OK) {
return;
}
ani_ref saveObj;
if (env->GlobalReference_Create(reinterpret_cast<ani_ref>(obj), &saveObj) != ANI_OK) {
return;
}
std::string nameStr;
if (!AniParseUtils::ParseString(env, name, nameStr)) {
return;
}
std::vector<std::string> methodListStr;
if (!AniParseUtils::ParseStringArray(env, methodList, methodListStr)) {
return;
}
ani_boolean isUndefined = true;
std::vector<std::string> asyncMethodListStr;
if (env->Reference_IsUndefined(asyncMethodList, &isUndefined) == ANI_OK && !isUndefined) {
if (!AniParseUtils::ParseStringArray(env, asyncMethodList, asyncMethodListStr)) {
return;
}
}
isUndefined = true;
std::string permissionStr;
if (env->Reference_IsUndefined(permission, &isUndefined) == ANI_OK && !isUndefined) {
if (!AniParseUtils::ParseString(env, permission, permissionStr)) {
return;
}
}
WebviewController* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
controller->SetNWebJavaScriptResultCallBack();
AniRegisterJavaScriptProxyParam param;
param.env = env;
param.obj = reinterpret_cast<ani_object>(saveObj);
param.objName = nameStr;
param.syncMethodList = methodListStr;
param.asyncMethodList = asyncMethodListStr;
param.permission = permissionStr;
param.webviewObj = reinterpret_cast<ani_object>(webviewObj);
controller->RegisterJavaScriptProxy(param);
}
static void RegisterJavaScriptProxy(ani_env* env, ani_object object, ani_object jsObject, ani_string name,
ani_object methodList, ani_object asyncMethodList, ani_object permission)
{
InnerJsProxy(env, object, jsObject, name, static_cast<ani_array>(methodList), asyncMethodList, permission);
}
static void DeleteJavaScriptRegister(ani_env* env, ani_object object, ani_string name)
{
std::string objName;
if (!AniParseUtils::ParseString(env, name, objName)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ErrCode ret = controller->DeleteJavaScriptRegister(objName, {});
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
WVLOG_I("DeleteJavaScriptRegister successful!");
return;
}
ErrCode ConstructFlowbuf(ani_env* env, ani_object script, int& fd, size_t& scriptLength)
{
auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
if (!flowbufferAdapter) {
return NWebError::NEW_OOM;
}
flowbufferAdapter->StartPerformanceBoost();
std::string scriptStr;
if (AniParseUtils::IsString(env, script)) {
if (AniParseUtils::ParseString(env, script, scriptStr)) {
WVLOG_I("script is string constructstringflowbuf");
return AniParseUtils::ConstructStringFlowbuf(env, scriptStr, fd, scriptLength);
}
}
return AniParseUtils::ConstructArrayBufFlowbuf(env, script, fd, scriptLength);
}
static void RunJavaScriptInternal(
ani_env* env, ani_object object, const std::string& script, ani_object callback, bool extention)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("enter RunJavaScriptInternal");
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_class functionClass;
env->FindClass("std.core.Function", &functionClass);
ani_boolean isFunction = false;
if (env->Object_InstanceOf(callback, functionClass, &isFunction) != ANI_OK || !isFunction) {
WVLOG_E("callback is not fountion");
return;
}
int32_t nwebId = controller->GetNWebId();
auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId);
if (!nweb_ptr) {
WVLOG_I("nweb_ptr is null");
ani_status status;
std::vector<ani_ref> resultRef(CALLBACK_PARAM_LENGTH);
resultRef[0] = NWebError::AniBusinessError::CreateError(env, NWebError::INIT_ERROR);
env->GetUndefined(&resultRef[1]);
ani_ref jsCallback = nullptr;
env->GlobalReference_Create(callback, &jsCallback);
if (jsCallback) {
ani_ref fnReturnVal;
if ((status = env->FunctionalObject_Call(static_cast<ani_fn_object>(jsCallback), resultRef.size(),
resultRef.data(), &fnReturnVal)) != ANI_OK) {
WVLOG_E("error callback FunctionalObject_Call Failed status : %{public}d!", status);
}
}
env->GlobalReference_Delete(jsCallback);
return;
}
if (callback) {
auto callbackImpl = std::make_shared<WebviewJavaScriptExecuteCallback>(env, callback, nullptr, extention);
nweb_ptr->ExecuteJavaScript(script, callbackImpl, extention);
}
return;
}
static ani_object RunJavaScriptInternalPromise(
ani_env* env, ani_object object, const std::string& script, bool extention)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
WVLOG_D("enter RunJavaScriptInternal");
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
ani_object promise;
ani_resolver resolver;
if (env->Promise_New(&resolver, &promise) != ANI_OK) {
WVLOG_E("create promise object error");
return nullptr;
}
int32_t nwebId = controller->GetNWebId();
auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId);
if (!nweb_ptr) {
ani_ref JsResult = NWebError::AniBusinessError::CreateError(env, NWebError::INIT_ERROR);
if (env->PromiseResolver_Reject(resolver, reinterpret_cast<ani_error>(JsResult)) != ANI_OK) {
WVLOG_E("reject promise error");
} else {
WVLOG_E("PromiseResolver_Reject error");
}
return nullptr;
}
auto callbackImpl = std::make_shared<WebviewJavaScriptExecuteCallback>(env, nullptr, resolver, extention);
nweb_ptr->ExecuteJavaScript(script, callbackImpl, extention);
return promise;
}
static void RunJSBackToOriginal(ani_env* env, ani_object object, ani_object script, ani_object callback, bool extention)
{
std::string scriptStr;
bool parseResult = false;
if (AniParseUtils::IsString(env, script)) {
parseResult = AniParseUtils::ParseString(env, script, scriptStr);
} else {
parseResult = AniParseUtils::ParseArrayBuffer(env, script, scriptStr);
}
if (!parseResult) {
WVLOG_E("parseResult is false");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
return RunJavaScriptInternal(env, object, scriptStr, callback, extention);
}
static ani_object RunJSBackToOriginal(ani_env* env, ani_object object, ani_object script, bool extention)
{
std::string scriptStr;
bool parseResult = false;
if (AniParseUtils::IsString(env, script)) {
parseResult = AniParseUtils::ParseString(env, script, scriptStr);
} else {
parseResult = AniParseUtils::ParseArrayBuffer(env, script, scriptStr);
}
if (!parseResult) {
WVLOG_E("parseResult is false");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return nullptr;
}
return RunJavaScriptInternalPromise(env, object, scriptStr, extention);
}
static void RunJavaScriptInternalExt(
ani_env* env, ani_object object, ani_object script, ani_object callbackObj, bool extention)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
int fd;
size_t scriptLength;
ErrCode constructResult = ConstructFlowbuf(env, script, fd, scriptLength);
if (constructResult != NO_ERROR) {
return RunJSBackToOriginal(env, object, script, callbackObj, extention);
}
usedFd_++;
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
close(fd);
usedFd_--;
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
int32_t nwebId = controller->GetNWebId();
auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId);
if (!nweb_ptr) {
std::vector<ani_ref> resultRef(CALLBACK_PARAM_LENGTH);
resultRef[0] = OHOS::NWeb::CreateStsError(
env, static_cast<ani_int>(NWebError::INIT_ERROR), GetErrMsgByErrCode(INIT_ERROR));
env->GetNull(&resultRef[1]);
ani_ref jsCallback = nullptr;
env->GlobalReference_Create(callbackObj, &jsCallback);
if (jsCallback) {
ani_ref fnReturnVal;
env->FunctionalObject_Call(
static_cast<ani_fn_object>(jsCallback), resultRef.size(), resultRef.data(), &fnReturnVal);
}
env->GlobalReference_Delete(jsCallback);
close(fd);
usedFd_--;
return;
}
if (callbackObj) {
auto callbackImpl = std::make_shared<WebviewJavaScriptExecuteCallback>(env, callbackObj, nullptr, extention);
nweb_ptr->ExecuteJavaScriptExt(fd, scriptLength, callbackImpl, extention);
} else {
close(fd);
}
usedFd_--;
return;
}
static ani_object RunJavaScriptInternalPromiseExt(ani_env* env, ani_object object, ani_object script, bool extention)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
int fd;
size_t scriptLength;
ErrCode constructResult = ConstructFlowbuf(env, script, fd, scriptLength);
if (constructResult != NO_ERROR) {
return RunJSBackToOriginal(env, object, script, extention);
}
usedFd_++;
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
close(fd);
usedFd_--;
WVLOG_E("controller is nullptr or not init");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
ani_object promise;
ani_resolver resolver;
if (env->Promise_New(&resolver, &promise) != ANI_OK) {
WVLOG_E("create promise object error");
close(fd);
usedFd_--;
return nullptr;
}
int32_t nwebId = controller->GetNWebId();
auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId);
if (!nweb_ptr) {
ani_ref JsResult = OHOS::NWeb::CreateStsError(
env, static_cast<ani_int>(NWebError::INIT_ERROR), GetErrMsgByErrCode(INIT_ERROR));
if (env->PromiseResolver_Reject(resolver, reinterpret_cast<ani_error>(JsResult)) != ANI_OK) {
WVLOG_E("rejecct promise errpr");
}
close(fd);
usedFd_--;
return nullptr;
}
auto callbackImpl = std::make_shared<WebviewJavaScriptExecuteCallback>(env, nullptr, resolver, extention);
nweb_ptr->ExecuteJavaScriptExt(fd, scriptLength, callbackImpl, extention);
usedFd_--;
return promise;
}
static void RunJSCallback(ani_env* env, ani_object object, ani_object script, ani_object callbackObj, bool extention)
{
WVLOG_D("enter RunJSCallback");
if (g_maxFdNum == -1) {
g_maxFdNum =
std::atoi(NWebAdapterHelper::Instance().ParsePerfConfig("flowBufferConfig", "maxFdNumber").c_str());
}
if (usedFd_.load() < g_maxFdNum) {
WVLOG_I("enter RunJavaScriptInternalExt in RunJSCallback");
return RunJavaScriptInternalExt(env, object, script, callbackObj, extention);
}
std::string scriptStr;
bool parseResult = (AniParseUtils::IsString(env, script)) ? AniParseUtils::ParseString(env, script, scriptStr)
: AniParseUtils::ParseArrayBuffer(env, script, scriptStr);
if (!parseResult) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "script", "string"));
return;
}
WVLOG_I("enter RunJavaScriptInternal in RunJSCallback");
return RunJavaScriptInternal(env, object, scriptStr, callbackObj, extention);
}
static ani_object RunJSPromise(ani_env* env, ani_object object, ani_object script, bool extention)
{
WVLOG_D("enter RunJSPromise");
if (g_maxFdNum == -1) {
g_maxFdNum =
std::atoi(NWebAdapterHelper::Instance().ParsePerfConfig("flowBufferConfig", "maxFdNumber").c_str());
}
if (usedFd_.load() < g_maxFdNum) {
WVLOG_I("enter RunJavaScriptInternalPromiseExt in RunJSCallback");
return RunJavaScriptInternalPromiseExt(env, object, script, extention);
}
std::string scriptStr;
bool parseResult = (AniParseUtils::IsString(env, script)) ? AniParseUtils::ParseString(env, script, scriptStr)
: AniParseUtils::ParseArrayBuffer(env, script, scriptStr);
if (!parseResult) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "script", "string"));
return nullptr;
}
WVLOG_I("enter RunJavaScriptInternalPromise in RunJSPromise");
return RunJavaScriptInternalPromise(env, object, scriptStr, extention);
}
static void RunJavaScriptCallback(ani_env* env, ani_object object, ani_object script, ani_object callbackObj)
{
WVLOG_D("start RunJavaScriptCallback");
return RunJSCallback(env, object, script, callbackObj, false);
}
static ani_object RunJavaScriptPromise(ani_env* env, ani_object object, ani_object script)
{
WVLOG_D("start RunJavaScriptPromise");
return RunJSPromise(env, object, script, false);
}
static ani_object ExecuteAIPageCommand(ani_env* env, ani_object object, ani_object commandObj)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return nullptr;
}
std::string command;
if (!AniParseUtils::ParseString(env, commandObj, command)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "command", "string"));
return nullptr;
}
if (!IsJsonObjectCommand(command)) {
AniBusinessError::ThrowErrorByErrCode(env, COMMAND_FORMAT_ERROR);
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
ani_object promise = nullptr;
ani_resolver resolver = nullptr;
if (env->Promise_New(&resolver, &promise) != ANI_OK) {
WVLOG_E("create promise object error");
return nullptr;
}
if (ResolveEmptyStringPromiseIfCallingFromM132(env, resolver, __func__)) {
return promise;
}
auto nweb = NWebHelper::Instance().GetNWeb(controller->GetNWebId());
if (!nweb) {
ani_ref jsError = NWebError::AniBusinessError::CreateError(env, NWebError::INIT_ERROR);
if (env->PromiseResolver_Reject(resolver, reinterpret_cast<ani_error>(jsError)) != ANI_OK) {
WVLOG_E("PromiseResolver_Reject failed");
}
return promise;
}
auto callback = std::make_shared<AniWebviewAIPageCommandCallback>(env, resolver);
nweb->ExecuteAIPageCommand(command, callback);
return promise;
}
static void RunJavaScriptCallbackExt(ani_env* env, ani_object object, ani_object script, ani_object callbackObj)
{
WVLOG_D("start RunJavaScriptCallback");
return RunJSCallback(env, object, script, callbackObj, true);
}
static ani_object RunJavaScriptPromiseExt(ani_env* env, ani_object object, ani_object script)
{
WVLOG_D("start RunJavaScriptPromiseExt");
return RunJSPromise(env, object, script, true);
}
static void EnableBackForwardCache(ani_env *env, ani_object object, ani_object featuresObject)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
bool nativeEmbed = false;
bool mediaTakeOver = false;
ani_boolean embedObj = ANI_FALSE;
ani_boolean mediaObj = ANI_FALSE;
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(featuresObject, &isUndefined);
if (isUndefined != ANI_TRUE) {
if (env->Object_GetFieldByName_Boolean(featuresObject, "nativeEmbed", &embedObj) == ANI_OK) {
nativeEmbed = static_cast<bool>(embedObj);
}
if (env->Object_GetFieldByName_Boolean(featuresObject, "mediaTakeOver", &mediaObj) == ANI_OK) {
mediaTakeOver = static_cast<bool>(mediaObj);
}
}
NWebHelper::Instance().EnableBackForwardCache(nativeEmbed, mediaTakeOver);
return;
}
static void SetBackForwardCacheOptions(ani_env *env, ani_object object, ani_object optionsObject)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("SetBackForwardCacheOptions: Init webview controller error.");
return;
}
int32_t size = BFCACHE_DEFAULT_SIZE;
int32_t timeToLive = BFCACHE_DEFAULT_TIMETOLIVE;
ani_int sizeObj = static_cast<ani_int>(size);
ani_int timeToLiveObj = static_cast<ani_int>(timeToLive);
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(optionsObject, &isUndefined);
if (isUndefined != ANI_TRUE) {
if (env->Object_GetPropertyByName_Int(optionsObject, "size", &sizeObj) == ANI_OK) {
size = static_cast<int32_t>(sizeObj);
}
if (env->Object_GetPropertyByName_Int(optionsObject, "timeToLive", &timeToLiveObj) == ANI_OK) {
timeToLive = static_cast<int32_t>(timeToLiveObj);
}
}
WVLOG_D("SetBackForwardCacheOptions size:%{public}d, timeToLive:%{public}d", size, timeToLive);
controller->SetBackForwardCacheOptions(size, timeToLive);
return;
}
static void SetAppCustomUserAgent(ani_env* env, ani_object object, ani_object aniUA)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_E("SetAppCustomUserAgent unsupported engine version: M114");
return;
}
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string userAgent;
if (!AniParseUtils::ParseString(env, aniUA, userAgent)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "userAgent", "string"));
return;
}
NWebHelper::Instance().SetAppCustomUserAgent(userAgent);
}
static void SetUserAgentForHosts(ani_env* env, ani_object object, ani_object aniUA, ani_object aniHosts)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_E("SetUserAgentForHosts unsupported engine version: M114");
return;
}
if (!env) {
WVLOG_E("env is nullptr");
return;
}
std::string userAgent;
if (!AniParseUtils::ParseString(env, aniUA, userAgent)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "userAgent", "string"));
return;
}
std::vector<std::string> hosts;
if (!AniParseUtils::ParseStringArray(env, aniHosts, hosts)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "hosts", "array"));
return;
}
NWebHelper::Instance().SetUserAgentForHosts(userAgent, hosts);
}
static void StoreWebArchiveCallbackInternal(
ani_env* env, std::string baseNameStr, bool autoNameStr, ani_ref& jsCallback, int32_t nwebId)
{
if (!env) {
return;
}
if (!jsCallback) {
return;
}
auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId);
if (!nweb_ptr) {
std::vector<ani_ref> resultRef;
ani_ref tmp = NWebError::AniBusinessError::CreateError(env, INIT_ERROR);
resultRef.push_back(tmp);
ani_ref tempData = nullptr;
env->GetUndefined(&tempData);
resultRef.push_back(tempData);
ani_ref fnReturnVal;
env->FunctionalObject_Call(
static_cast<ani_fn_object>(jsCallback), resultRef.size(), resultRef.data(), &fnReturnVal);
env->GlobalReference_Delete(jsCallback);
return;
}
auto callbackImpl = std::make_shared<OHOS::NWeb::NWebStoreWebArchiveCallback>();
callbackImpl->SetCallBack([env, jCallback = std::move(jsCallback)](std::string result) {
if (!env) {
return;
}
std::vector<ani_ref> 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);
ani_ref tempData = nullptr;
env->GetUndefined(&tempData);
resultRef.push_back(tempData);
}
ani_ref fnReturnVal;
env->FunctionalObject_Call(
static_cast<ani_fn_object>(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) {
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<bool>(autoName);
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is null");
return;
}
int32_t nwebId = controller->GetWebId();
ani_ref jsCallback = nullptr;
env->GlobalReference_Create(callbackObj, &jsCallback);
return StoreWebArchiveCallbackInternal(env, baseNameStr, autoNameStr, jsCallback, nwebId);
}
static void StoreWebArchivePromiseInternal(
ani_env* env, std::string baseNameStr, bool autoNameStr, ani_resolver deferred, int32_t nwebId)
{
if (!env) {
return;
}
if (!deferred) {
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<ani_error>(jsResult));
return;
}
auto callbackImpl = std::make_shared<OHOS::NWeb::NWebStoreWebArchiveCallback>();
callbackImpl->SetCallBack([env, deferred](std::string result) {
if (!env) {
return;
}
std::vector<ani_ref> resultRef(RESULT_COUNT);
resultRef[0] = NWebError::AniBusinessError::CreateError(env, INVALID_RESOURCE);
ani_string str {};
if (env->String_NewUTF8(result.c_str(), result.size(), &str) != ANI_OK) {
WVLOG_E("create string object failed");
return;
}
resultRef[1] = static_cast<ani_ref>(str);
if (!result.empty()) {
if (env->PromiseResolver_Resolve(deferred, resultRef[1]) != ANI_OK) {
WVLOG_E("PromiseResolver_Resolve fail");
}
} else {
env->PromiseResolver_Reject(deferred, reinterpret_cast<ani_error>(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) {
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<bool>(autoName);
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is null");
return nullptr;
}
int32_t nwebId = controller->GetWebId();
ani_object promise;
ani_resolver deferred;
if (env->Promise_New(&deferred, &promise) != ANI_OK) {
WVLOG_E("cretae promise object failed");
return nullptr;
}
StoreWebArchivePromiseInternal(env, baseNameStr, autoNameStr, deferred, nwebId);
return promise;
}
static void HasImageCallback(ani_env* env, ani_object object, ani_fn_object callback)
{
WVLOG_D("HasImageCallback begin");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_vm* vm = nullptr;
if (env->GetVM(&vm) != ANI_OK) {
WVLOG_E("Failed to get VM from env");
return;
}
if (!vm) {
WVLOG_E("vm is nullptr");
return;
}
WebviewController* webviewController = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!webviewController || !webviewController->IsInit()) {
WVLOG_E("Unwrap failed");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_ref jsCallback = nullptr;
auto status = env->GlobalReference_Create(callback, &jsCallback);
if (status != ANI_OK) {
WVLOG_E("GlobalReference_Create failed, status is : %{public}d", status);
return;
}
if (jsCallback) {
ErrCode ret = webviewController->HasImagesCallback(vm, jsCallback);
if (ret == NWEB_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
} else if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return;
}
}
}
ani_object HasImagePromise(ani_env* env, ani_object object)
{
WVLOG_D("HasImagePromise begin");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_vm* vm = nullptr;
if (env->GetVM(&vm) != ANI_OK) {
WVLOG_E("Failed to get VM from env");
return nullptr;
}
if (!vm) {
WVLOG_E("vm is nullptr");
return nullptr;
}
WebviewController* webviewController = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!webviewController || !webviewController->IsInit()) {
WVLOG_E("Unwrap failed");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
ani_resolver deferred = nullptr;
ani_object promise = nullptr;
auto status = env->Promise_New(&deferred, &promise);
if (status != ANI_OK) {
WVLOG_E("Promise_New failed, status is : %{public}d", status);
return nullptr;
}
if (promise && deferred) {
ErrCode ret = webviewController->HasImagesPromise(vm, deferred);
if (ret == NWEB_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return nullptr;
} else if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
return nullptr;
}
}
return promise;
}
static ani_object GetCertificateSync(ani_env* env, ani_object object)
{
ani_object certificateObj = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return certificateObj;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return certificateObj;
}
std::vector<std::string> certChainDerData;
if (!controller->GetCertChainDerData(certChainDerData)) {
WVLOG_E("GetCertificateSync failed");
return certificateObj;
}
ani_class cls;
if (env->FindClass("std.core.Array", &cls) != ANI_OK) {
return certificateObj;
}
ani_method arrayCtor;
if (env->Class_FindMethod(cls, "<ctor>", "i:", &arrayCtor) != ANI_OK) {
return certificateObj;
}
if (env->Object_New(cls, arrayCtor, &certificateObj, certChainDerData.size()) != ANI_OK) {
return certificateObj;
}
ani_status status;
for (uint8_t i = 0; i < certChainDerData.size(); ++i) {
if (i == UINT8_MAX) {
WVLOG_E("error, cert chain data array reach max");
break;
}
void* data = nullptr;
ani_arraybuffer buffer = nullptr;
if (env->CreateArrayBuffer(certChainDerData[i].size(), &data, &buffer) != ANI_OK) {
return certificateObj;
}
int retCode =
memcpy_s(data, certChainDerData[i].size(), certChainDerData[i].data(), certChainDerData[i].size());
if (retCode != 0) {
return certificateObj;
}
if ((status = env->Array_Set(static_cast<ani_array>(certificateObj), i,
static_cast<ani_ref>(buffer))) != ANI_OK) {
return certificateObj;
}
}
return certificateObj;
}
static ani_ref CreateWebPrintDocumentAdapter(ani_env* env, ani_object object, ani_string jobName)
{
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
std::string jobNameString;
if (!AniParseUtils::ParseString(env, jobName, jobNameString)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "jopName", "string"));
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
void* webPrintDocument = controller->CreateWebPrintDocumentAdapter(jobNameString);
if (!webPrintDocument) {
WVLOG_E("failed to Unwrap webPrintDocument");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return nullptr;
}
WebPrintDocument* webPrintDoc = new (std::nothrow) WebPrintDocument(webPrintDocument);
if (!webPrintDoc) {
WVLOG_E("new web print failed");
delete static_cast<PrintDocumentAdapterAdapter*>(webPrintDocument);
return nullptr;
}
ani_object printDocumentAdapterObj = {};
if (AniParseUtils::CreateObjectVoid(env, "@ohos.web.webview.webview.PrintDocumentAdapterInner",
printDocumentAdapterObj) == false) {
WVLOG_E("[printDocumentAdapter] CreateObjectVoid failed");
delete webPrintDoc;
webPrintDoc = nullptr;
return nullptr;
}
if (!AniParseUtils::Wrap(env, printDocumentAdapterObj, "@ohos.web.webview.webview.PrintDocumentAdapterInner",
reinterpret_cast<ani_long>(webPrintDoc))) {
WVLOG_E("[printDocumentAdapter] WebDownloadDelegate wrap failed");
delete webPrintDoc;
webPrintDoc = nullptr;
return nullptr;
}
return printDocumentAdapterObj;
}
static void OnJobStateChanged(ani_env* env, ani_object object, ani_string jobId, ani_enum_item state)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WebPrintDocument* webPrintDocument = reinterpret_cast<WebPrintDocument*>(AniParseUtils::Unwrap(env, object));
if (!webPrintDocument) {
WVLOG_E("failed to Unwrap webPrintDocument");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string jobIDString;
if (!AniParseUtils::ParseString(env, jobId, jobIDString)) {
WVLOG_E("failed to parse jobId");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
int32_t stateInt = 0;
if (!AniParseUtils::EnumParseInt32_t(env, state, stateInt)) {
WVLOG_E("failed to parse state");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
webPrintDocument->OnJobStateChanged(jobIDString, stateInt);
return;
}
WebPrintWriteResultCallback ParseWebPrintWriteResultCallback(ani_env* env, ani_object object, ani_fn_object callback)
{
WVLOG_D("ParseWebPrintWriteResultCallback");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_ref callbackRef = nullptr;
if (env->GlobalReference_Create(static_cast<ani_ref>(callback), &callbackRef) != ANI_OK) {
WVLOG_E("failed to create reference for callback");
return nullptr;
}
auto pCallback = [env, cbRef = std::move(callbackRef)](std::string jobId, uint32_t state) {
std::vector<ani_ref> argv;
ani_string jobIdString = nullptr;
if (env->String_NewUTF8(jobId.c_str(), jobId.size(), &jobIdString) == ANI_OK) {
argv.push_back(static_cast<ani_ref>(jobIdString));
}
ani_enum_item stateEnum = nullptr;
if (AniParseUtils::GetEnumItemByIndex(env, "@ohos.print.print.PrintFileCreationState",
static_cast<int32_t>(state), stateEnum)) {
argv.push_back(static_cast<ani_ref>(stateEnum));
}
ani_ref fnReturnVal = nullptr;
env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cbRef), argv.size(), argv.data(), &fnReturnVal);
env->GlobalReference_Delete(cbRef);
};
return pCallback;
}
static void ParsePrintRangeAdapter(ani_env* env, ani_object pageRange, PrintAttributesAdapter& printAttr)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!pageRange) {
WVLOG_E("ParsePrintRangeAdapter failed.");
return;
}
int startPage = 0;
int endPage = 0;
ani_ref pages = nullptr;
if (env->Object_GetPropertyByName_Int(pageRange, "startPage", &startPage) != ANI_OK) {
WVLOG_E("ParsePrintRangeAdapter failed to get startPage");
}
if (env->Object_GetPropertyByName_Int(pageRange, "endPage", &endPage) != ANI_OK) {
WVLOG_E("ParsePrintRangeAdapter failed to get endPage");
}
if (env->Object_GetPropertyByName_Ref(pageRange, "pages", &pages) != ANI_OK) {
WVLOG_E("ParsePrintRangeAdapter failed to get pages");
}
ani_array pagesArrayInt = static_cast<ani_array>(pages);
printAttr.pageRange.startPage = startPage > 0 ? static_cast<uint32_t>(startPage) : 0;
printAttr.pageRange.endPage = endPage > 0 ? static_cast<uint32_t>(endPage) : 0;
WVLOG_D("printAttr.pageRange.startPage is %{public}d,printAttr.pageRange.endPage is %{public}d",
printAttr.pageRange.startPage, printAttr.pageRange.endPage);
ani_size length = 0;
if (env->Array_GetLength(pagesArrayInt, &length) != ANI_OK) {
WVLOG_E("get array length failed");
return;
}
for (uint32_t i = 0; i < length; ++i) {
ani_int pagesInt = 0;
ani_ref intRef {};
auto status = env->Array_Get(pagesArrayInt, i, &intRef);
if (status != ANI_OK) {
WVLOG_E("Array_Get failed, status: %{public}d", status);
}
status = unbox(env, static_cast<ani_object>(intRef), &pagesInt);
if (status != ANI_OK) {
WVLOG_E("Unbox failed, status: %{public}d", status);
}
int pagesNum = static_cast<int>(pagesInt);
printAttr.pageRange.pages.push_back(pagesNum);
}
}
static void ParsePrintPageSizeAdapter(ani_env* env, ani_object pageSize, PrintAttributesAdapter& printAttr)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!pageSize) {
WVLOG_E("ParsePrintPageSizeAdapter failed.");
return;
}
int width = 0;
int height = 0;
if (env->Object_GetPropertyByName_Int(pageSize, "width", &width) != ANI_OK) {
WVLOG_E("ParsePrintPageSizeAdapter failed to get width");
}
if (env->Object_GetPropertyByName_Int(pageSize, "height", &height) != ANI_OK) {
WVLOG_E("ParsePrintPageSizeAdapter failed to get height");
}
printAttr.pageSize.width = width > 0 ? static_cast<uint32_t>(width) : 0;
printAttr.pageSize.height = height > 0 ? static_cast<uint32_t>(height) : 0;
WVLOG_D("width is %{public}d,height is %{public}d", printAttr.pageSize.width, printAttr.pageSize.height);
}
static void ParsePrintMarginAdapter(ani_env* env, ani_object margin, PrintAttributesAdapter& printAttr)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (!margin) {
WVLOG_E("ParsePrintMarginAdapter failed.");
return;
}
int top = 0;
int bottom = 0;
int left = 0;
int right = 0;
if (env->Object_GetPropertyByName_Int(margin, "top", &top) != ANI_OK) {
WVLOG_D("ParsePrintMarginAdapter failed to get top");
}
if (env->Object_GetPropertyByName_Int(margin, "bottom", &bottom) != ANI_OK) {
WVLOG_D("ParsePrintMarginAdapter failed to get bottom");
}
if (env->Object_GetPropertyByName_Int(margin, "left", &left) != ANI_OK) {
WVLOG_D("ParsePrintMarginAdapter failed to get left");
}
if (env->Object_GetPropertyByName_Int(margin, "right", &right) != ANI_OK) {
WVLOG_D("ParsePrintMarginAdapter failed to get right");
}
printAttr.margin.top = top > 0 ? static_cast<uint32_t>(top) : 0;
printAttr.margin.bottom = bottom > 0 ? static_cast<uint32_t>(bottom) : 0;
printAttr.margin.left = left > 0 ? static_cast<uint32_t>(left) : 0;
printAttr.margin.right = right > 0 ? static_cast<uint32_t>(right) : 0;
WVLOG_D("top is %{public}d,bottom is %{public}d,left is %{public}d,right is %{public}d", printAttr.margin.top,
printAttr.margin.bottom, printAttr.margin.left, printAttr.margin.right);
}
static void ParseBasicParams(ani_env* env, ani_object obj, PrintAttributesAdapter& printAttr)
{
ani_ref copyNumber_ref = nullptr;
ani_ref isSequential_ref = nullptr;
ani_ref isLandscape_ref = nullptr;
ani_ref colorMode_ref = nullptr;
ani_ref duplexMode_ref = nullptr;
int32_t copyNumber = 0;
if (AniParseUtils::GetRefProperty(env, obj, "copyNumber", copyNumber_ref)) {
AniParseUtils::ParseInt32(env, copyNumber_ref, copyNumber);
}
bool isSequential = false;
if (AniParseUtils::GetRefProperty(env, obj, "isSequential", isSequential_ref)) {
AniParseUtils::ParseBoolean(env, isSequential_ref, isSequential);
}
bool isLandscape = false;
if (AniParseUtils::GetRefProperty(env, obj, "isLandscape", isLandscape_ref)) {
AniParseUtils::ParseBoolean(env, isLandscape_ref, isLandscape);
}
int32_t colorMode = 0;
if (AniParseUtils::GetRefProperty(env, obj, "colorMode", colorMode_ref)) {
AniParseUtils::ParseInt32(env, colorMode_ref, colorMode);
}
int32_t duplexMode = 0;
if (AniParseUtils::GetRefProperty(env, obj, "duplexMode", duplexMode_ref)) {
AniParseUtils::ParseInt32(env, duplexMode_ref, duplexMode);
}
printAttr.copyNumber = static_cast<uint32_t>(copyNumber);
printAttr.isSequential = static_cast<bool>(isSequential);
printAttr.isLandscape = static_cast<bool>(isLandscape);
printAttr.colorMode = static_cast<uint32_t>(colorMode);
printAttr.duplexMode = static_cast<uint32_t>(duplexMode);
WVLOG_D("copyNumber is %{public}d,isSequential is %{public}d,isLandscape is %{public}d,colorMode is "
"%{public}d,duplexMode is %{public}d",
printAttr.copyNumber, printAttr.isSequential, printAttr.isLandscape, printAttr.colorMode, printAttr.duplexMode);
}
static bool ParseWebPrintAttrParams(ani_env* env, ani_object obj, PrintAttributesAdapter& printAttr)
{
if (!env) {
WVLOG_E("env is nullptr");
return false;
}
if (!obj) {
WVLOG_E("ParseWebPrintAttrParams failed.");
return false;
}
ani_ref pageRange_ref = nullptr;
ani_ref pageSize_ref = nullptr;
ani_ref margin = nullptr;
ParseBasicParams(env, obj, printAttr);
if (AniParseUtils::GetRefProperty(env, obj, "pageRange", pageRange_ref)) {
ParsePrintRangeAdapter(env, static_cast<ani_object>(pageRange_ref), printAttr);
}
if (AniParseUtils::GetRefProperty(env, obj, "pageSize", pageSize_ref)) {
ParsePrintPageSizeAdapter(env, static_cast<ani_object>(pageSize_ref), printAttr);
}
if (AniParseUtils::GetRefProperty(env, obj, "margin", margin)) {
ParsePrintMarginAdapter(env, static_cast<ani_object>(margin), printAttr);
}
printAttr.print_backgrounds = UINT32_MAX;
printAttr.display_header_footer = UINT32_MAX;
return true;
}
static void OnStartLayoutWrite(ani_env* env, ani_object object, ani_string jobId, ani_object oldPrintAttr,
ani_object newPrintAttr, ani_int fd, ani_fn_object callback)
{
if (!env) {
WVLOG_E("env is nullptr");
return;
}
WebPrintDocument* webPrintDocument = reinterpret_cast<WebPrintDocument*>(AniParseUtils::Unwrap(env, object));
if (!webPrintDocument) {
WVLOG_E("failed to Unwrap webPrintDocument");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string jobIDString;
if (!AniParseUtils::ParseString(env, jobId, jobIDString)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (fd < 0) {
WVLOG_E("invalid file descriptor: %d", fd);
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
uint32_t fdUint = static_cast<uint32_t>(fd);
PrintAttributesAdapter oldPA;
if (!ParseWebPrintAttrParams(env, oldPrintAttr, oldPA)) {
WVLOG_E("failed to ParseWebPrintAttrParams oldPrintAttr");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
PrintAttributesAdapter newPA;
if (!ParseWebPrintAttrParams(env, newPrintAttr, newPA)) {
WVLOG_E("failed to ParseWebPrintAttrParams newPrintAttr");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
WebPrintWriteResultCallback writeResultCallback = nullptr;
writeResultCallback = ParseWebPrintWriteResultCallback(env, object, callback);
if (!writeResultCallback) {
WVLOG_E("failed to ParseWebPrintWriteResultCallback");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
webPrintDocument->OnStartLayoutWrite(jobIDString, oldPA, newPA, fdUint, writeResultCallback);
return;
}
ani_status StsPrintDocumentAdapterInit(ani_env* env)
{
ani_class printDocumentAdapterCls = nullptr;
ani_status status = env->FindClass(ANI_PRINT_DOCUMENT_ADAPTER_INNER_CLASS_NAME, &printDocumentAdapterCls);
if (status != ANI_OK || !printDocumentAdapterCls) {
WVLOG_E(
"find %{public}s class failed, status: %{public}d", ANI_PRINT_DOCUMENT_ADAPTER_INNER_CLASS_NAME, status);
return ANI_ERROR;
}
std::array methodArray = {
ani_native_function { "onStartLayoutWrite", nullptr, reinterpret_cast<void*>(OnStartLayoutWrite) },
ani_native_function { "onJobStateChanged", nullptr, reinterpret_cast<void*>(OnJobStateChanged) },
};
status = env->Class_BindNativeMethods(printDocumentAdapterCls, methodArray.data(), methodArray.size());
if (status != ANI_OK) {
WVLOG_E("Class_BindNativeMethods failed status: %{public}d", status);
}
return ANI_OK;
}
static void SetSocketIdleTimeout(ani_env* env, ani_object object, ani_int timeout)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_E("SetSocketIdleTimeout unsupported engine version: M114");
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("SetSocketIdleTimeout start");
int32_t socketIdleTimeout =
std::clamp(static_cast<int32_t>(timeout), MIN_SOCKET_IDLE_TIMEOUT, MAX_SOCKET_IDLE_TIMEOUT);
NWebHelper::Instance().SetSocketIdleTimeout(socketIdleTimeout);
}
static void EnablePrivateNetworkAccess(ani_env* env, ani_object object, ani_boolean aniEnable)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_E("EnablePrivateNetworkAccess unsupported engine version: M114");
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("EnablePrivateNetworkAccess start");
bool enable = static_cast<bool>(aniEnable);
NWebHelper::Instance().EnablePrivateNetworkAccess(enable);
}
static ani_boolean IsPrivateNetworkAccessEnabled(ani_env* env, ani_object object)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_E("IsPrivateNetworkAccessEnabled unsupported engine version: M114");
return ANI_FALSE;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
WVLOG_D("IsPrivateNetworkAccessEnabled start");
return static_cast<ani_boolean>(NWebHelper::Instance().IsPrivateNetworkAccessEnabled());
}
static void SetErrorPageEnabled(ani_env* env, ani_object object, ani_boolean aniEnable)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("SetErrorPageEnabled unsupported engine version: M114");
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("SetErrorPageEnabled start");
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
bool enable = static_cast<bool>(aniEnable);
ErrCode ret = controller->SetErrorPageEnabled(enable);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
static void SetErrorPageEnabledWithSubframe(ani_env* env, ani_object object,
ani_boolean aniEnable, ani_boolean aniIncludeSubframe)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("SetErrorPageEnabledWithSubframe unsupported engine version: M114");
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
WVLOG_D("SetErrorPageEnabledWithSubframe in ani start");
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
bool enable = static_cast<bool>(aniEnable);
bool includeSubframe = static_cast<bool>(aniIncludeSubframe);
ErrCode ret = controller->SetErrorPageEnabled(enable, includeSubframe);
if (ret != NO_ERROR) {
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
static ani_boolean GetErrorPageEnabled(ani_env* env, ani_object object)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("GetErrorPageEnabled unsupported engine version: M114");
return ANI_FALSE;
}
WVLOG_D("GetErrorPageEnabled start");
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
return static_cast<ani_boolean>(controller->GetErrorPageEnabled());
}
static ani_boolean GetSubframeErrorPageEnabled(ani_env* env, ani_object object)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("GetSubframeErrorPageEnabled unsupported engine version: M114");
return ANI_FALSE;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
WVLOG_D("GetSubframeErrorPageEnabled in ani start");
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return ANI_FALSE;
}
return static_cast<ani_boolean>(controller->GetSubframeErrorPageEnabled());
}
bool ParseBlanklessString(ani_env* env, ani_ref ref, std::string& outValue)
{
ani_string str = static_cast<ani_string>(ref);
ani_size strSize;
auto status = env->String_GetUTF8Size(str, &strSize);
if (status != ANI_OK) {
WVLOG_E("blankless ParseBlanklessString String_GetUTF8Size failed, status: %{public}d", status);
return false;
}
if (strSize == 0 || strSize > MAX_KEY_LENGTH) {
WVLOG_E("blankless ParseBlanklessString string length is invalid");
return false;
}
std::vector<char> buffer(strSize + 1);
char* utfBuffer = buffer.data();
ani_size bytes_written = 0;
status = env->String_GetUTF8(str, utfBuffer, strSize + 1, &bytes_written);
if (status != ANI_OK) {
WVLOG_E("blankless ParseBlanklessString String_GetUTF8 failed, status: %{public}d", status);
return false;
}
utfBuffer[bytes_written] = '\0';
outValue = std::string(utfBuffer, strSize);
return true;
}
bool ParseBlanklessStringArray(ani_env* env, ani_object keysObj, std::vector<std::string>& outValue)
{
ani_array keysArray = static_cast<ani_array>(keysObj);
ani_size aniLength;
if (env->Array_GetLength(keysArray, &aniLength) != ANI_OK) {
WVLOG_E("blankless ParseBlanklessStringArray get array size failed");
return false;
}
uint32_t arrLen = static_cast<uint32_t>(aniLength);
if (arrLen > MAX_KEYS_COUNT) {
WVLOG_W("blankless ParseBlanklessStringArray array size should not exceed 100");
arrLen = MAX_KEYS_COUNT;
}
for (uint32_t i = 0; i < arrLen; i++) {
ani_ref keyItem = nullptr;
env->Array_Get(keysArray, i, &keyItem);
std::string key;
if (ParseBlanklessString(env, keyItem, key)) {
outValue.push_back(key);
}
}
return true;
}
ani_object CreateBlanklessInfo(ani_env* env, int32_t errCode, double similarity, int32_t loadingTime)
{
ani_object result = {};
if (!AniParseUtils::CreateObjectVoid(env, ANI_CLASS_BLANKLESS_INFO_INNER, result)) {
WVLOG_E("CreateBlanklessInfo FAILED");
return result;
}
ani_enum_item errCodeType;
if (AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, std::abs(errCode), errCodeType)) {
env->Object_SetPropertyByName_Ref(result, "errCode", errCodeType);
}
env->Object_SetPropertyByName_Double(result, "similarity", static_cast<ani_double>(similarity));
env->Object_SetPropertyByName_Int(result, "loadingTime", static_cast<ani_int>(loadingTime));
return result;
}
ani_object GetBlanklessInfoWithKey(ani_env* env, ani_object object, ani_object keyObj)
{
ProductDeviceType deviceType = SystemPropertiesAdapterImpl::GetInstance().GetProductDeviceType();
if (deviceType != ProductDeviceType::DEVICE_TYPE_MOBILE) {
WVLOG_E("GetBlanklessInfoWithKey capability not supported.");
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return nullptr;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webviewController is nullptr.");
return nullptr;
}
std::string key;
if (!ParseBlanklessString(env, static_cast<ani_ref>(keyObj), key)) {
WVLOG_E("GetBlanklessInfoWithKey ParseString failed");
return CreateBlanklessInfo(env, BLANKLESS_ERR_INVALID_ARGS, 0.0, 0);
}
if (!controller->IsInit()) {
WVLOG_E("GetBlanklessInfoWithKey controller is not inited");
return CreateBlanklessInfo(env, BLANKLESS_ERR_NOT_INITED, 0.0, 0);
}
double similarity = 0.0;
int32_t loadingTime = 0;
int32_t errCode = controller->GetBlanklessInfoWithKey(key, &similarity, &loadingTime);
return CreateBlanklessInfo(env, errCode, similarity, loadingTime);
}
ani_enum_item SetBlanklessLoadingWithKey(ani_env* env, ani_object object, ani_object keyObj, ani_boolean is_start)
{
ProductDeviceType deviceType = SystemPropertiesAdapterImpl::GetInstance().GetProductDeviceType();
if (deviceType != ProductDeviceType::DEVICE_TYPE_MOBILE) {
WVLOG_E("SetBlanklessLoadingWithKey capability not supported.");
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return nullptr;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webviewController is nullptr.");
return nullptr;
}
ani_enum_item result;
std::string key;
if (!ParseBlanklessString(env, static_cast<ani_ref>(keyObj), key)) {
WVLOG_E("SetBlanklessLoadingWithKey ParseString failed");
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, BLANKLESS_ERR_INVALID_ARGS, result);
return result;
}
if (!controller->IsInit()) {
WVLOG_E("SetBlanklessLoadingWithKey controller is not inited");
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, BLANKLESS_ERR_NOT_INITED, result);
return result;
}
auto errCode = controller->SetBlanklessLoadingWithKey(key, static_cast<bool>(is_start));
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, std::abs(errCode), result);
return result;
}
int32_t ParseBlanklessLoadingParam(ani_env* env, ani_object param, AniBlanklessLoadingParam& aniParam)
{
if (!env) {
WVLOG_E("env is nullptr");
return BLANKLESS_ERR_UNKNOWN;
}
ani_boolean enableObj;
if (env->Object_GetPropertyByName_Boolean(param, "enable", &enableObj) != ANI_OK) {
return BLANKLESS_ERR_INVALID_ARGS;
}
aniParam.enable = static_cast<bool>(enableObj);
ani_int durationObj;
if (env->Object_GetPropertyByName_Int(param, "duration", &durationObj) == ANI_OK) {
int32_t durationTemp = static_cast<int32_t>(durationObj);
if (durationTemp != 0 && (durationTemp < MIN_BLANKLESS_DURATION_TIME ||
durationTemp > MAX_BLANKLESS_DURATION_TIME)) {
return BLANKLESS_ERR_DURATION_OUT_OF_RANGE;
}
aniParam.duration = durationTemp;
}
ani_long expirationTimeObj;
if (env->Object_GetPropertyByName_Long(param, "expirationTime", &expirationTimeObj) == ANI_OK) {
int64_t expirationTimeTemp = static_cast<int64_t>(expirationTimeObj);
int64_t nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
if (expirationTimeTemp != 0 && (expirationTimeTemp < nowMs ||
expirationTimeTemp - nowMs > MAX_EXPIRATION_TIME)) {
return BLANKLESS_ERR_EXPIRATION_TIME_OUT_OF_RANGE;
}
aniParam.expirationTime = expirationTimeTemp;
}
ani_ref callbackRef = nullptr;
if (env->Object_GetPropertyByName_Ref(param, "callback", &callbackRef) == ANI_OK) {
aniParam.callbackRef = callbackRef;
}
return BLANKLESS_SUCCESS;
}
ani_enum_item SetBlanklessLoadingWithParams(ani_env* env, ani_object object, ani_object keyObj, ani_object param)
{
ProductDeviceType deviceType = SystemPropertiesAdapterImpl::GetInstance().GetProductDeviceType();
if (deviceType != ProductDeviceType::DEVICE_TYPE_MOBILE) {
WVLOG_E("SetBlanklessLoadingWithParams capability not supported.");
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return nullptr;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("webviewController is nullptr.");
return nullptr;
}
ani_enum_item result;
std::string key;
if (!ParseBlanklessString(env, static_cast<ani_ref>(keyObj), key)) {
WVLOG_E("SetBlanklessLoadingWithKey ParseString failed");
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, BLANKLESS_ERR_INVALID_ARGS, result);
return result;
}
AniBlanklessLoadingParam aniParam;
if (auto parseResult = ParseBlanklessLoadingParam(env, param, aniParam); parseResult != BLANKLESS_SUCCESS) {
WVLOG_E("SetBlanklessLoadingWithKey ParseParam failed");
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, parseResult, result);
return result;
}
if (!controller->IsInit()) {
WVLOG_E("SetBlanklessLoadingWithKey controller is not inited");
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, BLANKLESS_ERR_NOT_INITED, result);
return result;
}
auto errCode = controller->SetBlanklessLoadingParams(env, key, aniParam);
AniParseUtils::GetEnumItemByIndex(env, ANI_ENUM_WEB_BLANKLESS_ERROR_CODE, std::abs(errCode), result);
return result;
}
static ani_int SetBlanklessLoadingCacheCapacity(ani_env* env, ani_object object, ani_int capacityObj)
{
ProductDeviceType deviceType = SystemPropertiesAdapterImpl::GetInstance().GetProductDeviceType();
if (deviceType != ProductDeviceType::DEVICE_TYPE_MOBILE) {
WVLOG_E("SetBlanklessLoadingCacheCapacity capability not supported.");
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return static_cast<ani_int>(0);
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return static_cast<ani_int>(0);
}
int32_t capacity = static_cast<int32_t>(capacityObj);
if (capacity < 0) {
capacity = 0;
}
if (capacity > MAX_DATABASE_SIZE_IN_MB) {
capacity = MAX_DATABASE_SIZE_IN_MB;
}
NWebHelper::Instance().SetBlanklessLoadingCacheCapacity(capacity);
return static_cast<ani_int>(capacity);
}
static void ClearBlanklessLoadingCache(ani_env* env, ani_object object, ani_object keysObj)
{
ProductDeviceType deviceType = SystemPropertiesAdapterImpl::GetInstance().GetProductDeviceType();
if (deviceType != ProductDeviceType::DEVICE_TYPE_MOBILE) {
WVLOG_E("ClearBlanklessLoadingCache capability not supported.");
AniBusinessError::ThrowErrorByErrCode(env, CAPABILITY_NOT_SUPPORTED_ERROR);
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined;
if (env->Reference_IsUndefined(keysObj, &isUndefined) != ANI_OK) {
WVLOG_E("ClearBlanklessLoadingCache Reference_IsUndefined failed.");
return;
}
std::vector<std::string> keys;
if (isUndefined) {
NWebHelper::Instance().ClearBlanklessLoadingCache(keys);
return;
}
if (!ParseBlanklessStringArray(env, keysObj, keys)) {
WVLOG_E("ClearBlanklessLoadingCache parse string array failed");
return;
}
if (keys.size() == 0) {
WVLOG_W("ClearBlanklessLoadingCache valid keys are 0");
return;
}
NWebHelper::Instance().ClearBlanklessLoadingCache(keys);
}
WEBVIEW_ANI_STATIC void SetWebDestroyMode(ani_env *env, ani_object object, ani_enum_item mode)
{
WVLOG_D("[WebviewCotr] SetWebDestroyMode");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(mode, &isUndefined) != ANI_OK || isUndefined) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
ani_int iMode;
if (env->EnumItem_GetValue_Int(mode, &iMode) != ANI_OK) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "mode", "WebDestroyMode"));
return;
}
int32_t webDestroyMode = static_cast<int32_t>(iMode);
if (webDestroyMode < static_cast<int32_t>(WebDestroyMode::NORMAL_MODE) ||
webDestroyMode > static_cast<int32_t>(WebDestroyMode::FAST_MODE)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_TYPE_INVALID, "mode"));
return;
}
WVLOG_I("SetWebDestroyMode mode: %{public}d", webDestroyMode);
NWebHelper::Instance().SetWebDestroyMode(static_cast<WebDestroyMode>(webDestroyMode));
}
WEBVIEW_ANI_STATIC void SetScrollbarMode(ani_env *env, ani_object object, ani_enum_item mode)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(mode, &isUndefined) != ANI_OK || isUndefined) {
return;
}
ani_int modeInt;
if (env->EnumItem_GetValue_Int(mode, &modeInt) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (modeInt < static_cast<int>(ScrollbarMode::OVERLAY_LAYOUT_SCROLLBAR) ||
modeInt > static_cast<int>(ScrollbarMode::OVERLAY_VISUAL_SCROLLBAR)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
WVLOG_I("SetScrollbarMode mode: %{public}d", static_cast<OHOS::NWeb::ScrollbarMode>(modeInt));
NWebHelper::Instance().SetScrollbarMode(static_cast<OHOS::NWeb::ScrollbarMode>(modeInt));
}
static void SetUserAgentClientHintsEnabled(ani_env* env, ani_object object, ani_boolean aniEnable)
{
if (IS_CALLING_FROM_M114() || !env) {
WVLOG_E("SetUserAgentClientHintsEnabled unsupported engine version: M114 or env is nullptr");
return;
}
WVLOG_D("SetUserAgentClientHintsEnabled enable:%{public}d", aniEnable);
NWebHelper::Instance().SetUserAgentClientHintsEnabled(static_cast<bool>(aniEnable));
}
static ani_boolean GetUserAgentClientHintsEnabled(ani_env* env, ani_object object)
{
if (IS_CALLING_FROM_M114() || !env) {
WVLOG_E("GetUserAgentClientHintsEnabled unsupported engine version: M114 or env is nullptr");
return ANI_FALSE;
}
WVLOG_D("GetUserAgentClientHintsEnabled.");
return static_cast<ani_boolean>(NWebHelper::Instance().GetUserAgentClientHintsEnabled());
}
static void SetUserAgentMetadata(ani_env* env, ani_object object, ani_object aniUserAgent, ani_object aniMetadata)
{
if (IS_CALLING_FROM_M114() || !env) {
WVLOG_E("SetUserAgentMetadata unsupported engine version: M114 or env is nullptr");
return;
}
WVLOG_D("webviewController SetUserAgentMetadata.");
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string userAgent;
if (!AniParseUtils::ParseString(env, aniUserAgent, userAgent)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "userAgent", "string"));
return;
}
auto* metadata = reinterpret_cast<NWebUserAgentMetadataImpl*>(AniParseUtils::Unwrap(env, aniMetadata));
if (!metadata) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::vector<std::string> strBrand;
std::vector<std::string> strMajorVersion;
std::vector<std::string> strFullVersion;
metadata->GetBrandVersionList(strBrand, strMajorVersion, strFullVersion);
UserAgentMetadataInfo metadataInfo { .arch = metadata->GetArchitecture(),
.bitness = metadata->GetBitness(),
.formFactors = metadata->GetFormFactors(),
.fullVersion = metadata->GetFullVersion(),
.isMobile = metadata->GetMobile(),
.model = metadata->GetModel(),
.platform = metadata->GetPlatform(),
.platformVersion = metadata->GetPlatformVersion(),
.isWow64 = metadata->GetWow64() };
auto ptrMetadata = std::make_shared<OHOS::NWeb::NWebUserAgentMetadataImpl>(
strBrand, strMajorVersion, strFullVersion, metadataInfo);
controller->SetUserAgentMetadata(userAgent, ptrMetadata);
}
static ani_object GetUserAgentMetadata(ani_env* env, ani_object object, ani_object aniUserAgent)
{
if (IS_CALLING_FROM_M114() || !env) {
WVLOG_E("GetUserAgentMetadata unsupported engine version: M114 or env is nullptr");
return nullptr;
}
WVLOG_D("webviewController GetUserAgentMetadata ");
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return nullptr;
}
std::string userAgent;
if (!AniParseUtils::ParseString(env, aniUserAgent, userAgent)) {
AniBusinessError::ThrowError(env, NWebError::PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "userAgent", "string"));
return nullptr;
}
auto metadata = controller->GetUserAgentMetadata(userAgent);
if (!metadata) {
WVLOG_E("GetUserAgentMetadata is null");
return nullptr;
}
ani_object metadataObj = {};
metadataObj = CreateUserAgentMetadataObject(env, metadata);
return metadataObj;
}
void ParseBooleanProperty(ani_env *env, ani_object obj, const char* name, bool& value)
{
ani_ref propRef = nullptr;
if (AniParseUtils::GetRefProperty(env, obj, name, propRef)) {
if (!AniParseUtils::ParseBoolean(env, propRef, value)) {
WVLOG_W("ParseBooleanProperty: name=%{public}s, ParseBoolean failed, using default value", name);
}
}
}
std::shared_ptr<NWebSecurityOptions> ParseSecurityOptions(ani_env *env, ani_object optionsObj)
{
bool disableJIT = false;
ParseBooleanProperty(env, optionsObj, "disableJITCompilation", disableJIT);
bool disableWasm = false;
ParseBooleanProperty(env, optionsObj, "disableWebAssembly", disableWasm);
bool disableWebGL = false;
ParseBooleanProperty(env, optionsObj, "disableWebGL", disableWebGL);
bool disablePDF = false;
ParseBooleanProperty(env, optionsObj, "disablePDFViewer", disablePDF);
bool disableMathML = false;
ParseBooleanProperty(env, optionsObj, "disableMathML", disableMathML);
bool disableSW = false;
ParseBooleanProperty(env, optionsObj, "disableServiceWorker", disableSW);
bool disableUDP = false;
ParseBooleanProperty(env, optionsObj, "disableNonProxyUDP", disableUDP);
return std::make_shared<NWebSecurityOptionsImpl>(
disableJIT, disableWasm, disableWebGL, disablePDF, disableMathML, disableSW, disableUDP);
}
WEBVIEW_ANI_STATIC void EnableAdvancedSecurityMode(ani_env *env, ani_object object, ani_object optionsObj)
{
WVLOG_D("[WebviewCotr] EnableAdvancedSecurityMode");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
if (IS_CALLING_FROM_M114()) {
WVLOG_W("EnableAdvancedSecurityMode unsupported engine version: M114");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_boolean isUndefined = ANI_TRUE;
env->Reference_IsUndefined(optionsObj, &isUndefined);
if (isUndefined == ANI_TRUE) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::TYPE_ERROR, "options", "SecurityOptions"));
return;
}
auto options = ParseSecurityOptions(env, optionsObj);
NWebHelper::Instance().EnableAdvancedSecurityMode(options);
WVLOG_I("EnableAdvancedSecurityMode done");
}
WEBVIEW_ANI_STATIC void SetSiteIsolationMode(ani_env *env, ani_object object, ani_enum_item mode)
{
WVLOG_D("[WebviewCotr] SetSiteIsolationMode");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(mode, &isUndefined) != ANI_OK || isUndefined) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
ani_int iMode;
if (env->EnumItem_GetValue_Int(mode, &iMode) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
int32_t siteIsolationMode = static_cast<int32_t>(iMode);
if (siteIsolationMode < static_cast<int>(SiteIsolationMode::PARTIAL) ||
siteIsolationMode > static_cast<int>(SiteIsolationMode::STRICT)) {
AniBusinessError::ThrowError(env, PARAM_CHECK_ERROR,
NWebError::FormatString(ParamCheckErrorMsgTemplate::PARAM_TYPE_INVALID, "mode"));
return;
}
WVLOG_I("SetSiteIsolationMode mode: %{public}d", siteIsolationMode);
int32_t res = NWebHelper::Instance().SetSiteIsolationMode(static_cast<SiteIsolationMode>(siteIsolationMode));
if (res == static_cast<int32_t>(SetSiteIsolationModeErr::ALREADY_SET_ERR)) {
AniBusinessError::ThrowError(env, INIT_ERROR,
"InitError 17100001: Site Isolation mode is already set by the developer.");
}
if (res == static_cast<int32_t>(SetSiteIsolationModeErr::SINGLE_RENDER_SET_STRICT_ERR)) {
AniBusinessError::ThrowError(env, INIT_ERROR,
"InitError 17100001: Site Isolation mode cannot be strict in single-render-process mode.");
}
if (res == static_cast<int32_t>(SetSiteIsolationModeErr::ADVANCED_SECURITY_SET_ERR)) {
AniBusinessError::ThrowError(env, INIT_ERROR,
"InitError 17100001: Site Isolation mode cannot be changed while Secure Shield mode is active.");
}
WVLOG_I("SetSiteIsolationMode mode res %{public}d", res);
}
WEBVIEW_ANI_STATIC ani_enum_item GetSiteIsolationMode(ani_env *env, ani_object object)
{
WVLOG_D("[WebviewCotr] GetSiteIsolationMode");
ani_int siteIsolationMode = 0;
ani_enum enumType;
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
if (env->FindEnum("@ohos.web.webview.webview.SiteIsolationMode", &enumType) != ANI_OK) {
WVLOG_E("env find enum failed");
return nullptr;
}
siteIsolationMode = static_cast<ani_int>(NWebHelper::Instance().GetSiteIsolationMode());
WVLOG_D("getSiteIsolationMode mode = %{public}d", static_cast<int32_t>(siteIsolationMode));
ani_enum_item mode;
if (env->Enum_GetEnumItemByIndex(enumType, siteIsolationMode, &mode) != ANI_OK) {
WVLOG_E("env enum_GetEnumItemByIndex failed");
return nullptr;
}
return mode;
}
static void SetSoftKeyboardBehaviorMode(ani_env *env, ani_object object, ani_enum_item mode)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(mode, &isUndefined) != ANI_OK || isUndefined) {
return;
}
ani_int modeInt;
if (env->EnumItem_GetValue_Int(mode, &modeInt) != ANI_OK) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (modeInt < static_cast<int>(WebSoftKeyboardBehaviorMode::DEFAULT) ||
modeInt > static_cast<int>(WebSoftKeyboardBehaviorMode::DISABLE_AUTO_KEYBOARD_ON_ACTIVE)) {
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
controller->SetSoftKeyboardBehaviorMode(static_cast<int>(modeInt));
}
WEBVIEW_ANI_STATIC ani_enum_item GetAttachState(ani_env *env, ani_object object)
{
WVLOG_D("Entry GetAttachState");
ani_enum_item result = nullptr;
if (!env) {
WVLOG_E("env is nullptr");
return result;
}
auto *controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return result;
}
ani_enum enumType;
if (env->FindEnum("@ohos.web.webview.webview.ControllerAttachState", &enumType) != ANI_OK) {
WVLOG_E("Find enumType failed");
return result;
}
ani_int attachState = controller->GetAttachState();
if (env->Enum_GetEnumItemByIndex(enumType, attachState, &result) != ANI_OK) {
WVLOG_E("Convert attachState(%{public}d) failed", attachState);
}
WVLOG_I("Get attachState = %{public}d", attachState);
return result;
}
WEBVIEW_ANI_STATIC void OnControllerAttachStateChange(ani_env *env, ani_object object, ani_object callback)
{
WVLOG_D("Entry OnControllerAttachStateChange");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto *controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(callback, &isUndefined) != ANI_OK || isUndefined) {
WVLOG_E("Callback para error");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (!AniParseUtils::IsFunction(env, callback)) {
WVLOG_E("Callback type error");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
controller->RegisterStateChangeCallback(env, CONTROLLER_ATTACH_STATE_CHANGE, callback);
return;
}
WEBVIEW_ANI_STATIC void OffControllerAttachStateChange(ani_env *env, ani_object object, ani_object callback)
{
WVLOG_D("Entry OffControllerAttachStateChange");
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto *controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return;
}
ani_boolean isUndefined = ANI_FALSE;
if (env->Reference_IsUndefined(callback, &isUndefined) != ANI_OK) {
WVLOG_E("Callback para error");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
if (!isUndefined && !AniParseUtils::IsFunction(env, callback)) {
WVLOG_E("Callback type error");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
controller->UnregisterStateChangeCallback(env, CONTROLLER_ATTACH_STATE_CHANGE, isUndefined ? nullptr : callback);
return;
}
WEBVIEW_ANI_STATIC ani_object WaitForAttachedPromise(ani_env *env, ani_object object, ani_int timeout)
{
WVLOG_D("Entry WaitForAttachedPromise");
if (!env) {
WVLOG_E("env is nullptr");
return nullptr;
}
auto *controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return nullptr;
}
ani_object promise = nullptr;
ani_resolver resolver = nullptr;
ani_status status = ANI_ERROR;
if ((status = env->Promise_New(&resolver, &promise)) != ANI_OK) {
WVLOG_E("Promise_New failed, status: %{public}d", status);
return nullptr;
}
if (promise && resolver) {
controller->WaitForAttachedInternal(env, timeout, resolver);
}
return promise;
}
static ani_boolean IsAutoPreconnectEnabled(ani_env *env, ani_object object)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("IsAutoPreconnectEnabled unsupported engine version: M114");
return ANI_FALSE;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
WVLOG_D("IsAutoPreconnectEnabled start");
return static_cast<ani_boolean>(NWebHelper::Instance().IsAutoPreconnectEnabled());
}
static void SetAutoPreconnect(ani_env *env, ani_object object, ani_boolean aniEnable)
{
if (IS_CALLING_FROM_M114()) {
WVLOG_W("SetAutoPreconnect unsupported engine version: M114");
return;
}
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
bool autoPreconnectEnabled = static_cast<bool>(aniEnable);
WVLOG_D("SetAutoPreconnect start");
NWebHelper::Instance().SetAutoPreconnect(autoPreconnectEnabled);
}
void PrefetchPageWithHttpHeadersAndPrefetchOptions(ani_env* env, ani_object object, ani_object aniUrl,
ani_object aniAdditionalHeaders, ani_object aniPrefetchOptions)
{
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
WVLOG_E("PrefetchPage: Init webview controller error.");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string url;
if (!ParsePrepareUrl(env, aniUrl, url)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return;
}
std::map<std::string, std::string> additionalHttpHeaders;
ani_boolean isHeadersUndefined;
if (env->Reference_IsUndefined(aniAdditionalHeaders, &isHeadersUndefined) != ANI_OK) {
WVLOG_E("PrefetchPage Reference_IsUndefined failed.");
return;
}
if (!isHeadersUndefined) {
if (!GetWebHeaders(env, aniAdditionalHeaders, additionalHttpHeaders)) {
WVLOG_E("getWebHeaders error.");
return;
}
}
std::shared_ptr<NWebPrefetchOptions> prefetchOptions = GetPrefetchOptions(env, object, aniPrefetchOptions);
WVLOG_D("PrefetchPageWithHttpHeadersAndPrefetchOptions start");
ErrCode ret = controller->PrefetchPage(url, additionalHttpHeaders, prefetchOptions);
if (ret != NO_ERROR) {
WVLOG_E("PrefetchPageWithHttpHeadersAndPrefetchOptions failed, error code: %{public}d", ret);
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
void PrefetchPage(ani_env* env, ani_object object, ani_object aniUrl,
ani_object aniAdditionalHeaders, ani_object aniPrefetchOptions)
{
if (!env) {
WVLOG_E("env is nullptr");
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
auto* controller = reinterpret_cast<WebviewController*>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
WVLOG_E("PrefetchPage: Init webview controller error.");
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return;
}
std::string url;
if (!ParsePrepareUrl(env, aniUrl, url)) {
AniBusinessError::ThrowError(env, INVALID_URL,
NWebError::FormatString(ParamCheckErrorMsgTemplate::URL_INVALID_OR_TOO_LONG));
return;
}
ani_boolean isHeadersUndefined;
if (env->Reference_IsUndefined(aniAdditionalHeaders, &isHeadersUndefined) != ANI_OK) {
WVLOG_E("PrefetchPage Reference_IsUndefined failed.");
return;
}
ani_boolean isOptionsUndefined;
if (env->Reference_IsUndefined(aniPrefetchOptions, &isOptionsUndefined) != ANI_OK) {
WVLOG_E("PrefetchPage Reference_IsUndefined failed.");
return;
}
if (!isOptionsUndefined) {
PrefetchPageWithHttpHeadersAndPrefetchOptions(env, object, aniUrl, aniAdditionalHeaders, aniPrefetchOptions);
return;
}
std::map<std::string, std::string> additionalHttpHeaders;
if (!isHeadersUndefined) {
if (!GetWebHeaders(env, aniAdditionalHeaders, additionalHttpHeaders)) {
WVLOG_E("getWebHeaders error.");
return;
}
}
WVLOG_D("PrefetchPage start");
ErrCode ret = controller->PrefetchPage(url, additionalHttpHeaders);
if (ret != NO_ERROR) {
WVLOG_E("PrefetchPage failed, error code: %{public}d", ret);
AniBusinessError::ThrowErrorByErrCode(env, ret);
}
}
WEBVIEW_ANI_STATIC void SetWebDetach(ani_env *env, ani_object object, ani_int nwebId)
{
WVLOG_D("Entry SetWebDetach nwebId: %{public}d", nwebId);
if (!env) {
WVLOG_E("env is nullptr");
return;
}
auto *controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller) {
WVLOG_E("controller is nullptr");
return;
}
auto id = static_cast<int32_t>(nwebId);
controller->SetWebDetach(id);
return;
}
static ani_enum_item GetActiveWebEngineVersion(ani_env *env, ani_object object)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return nullptr;
}
ani_enum enumType;
ani_status status = ANI_ERROR;
if ((status = env->FindEnum(ANI_ENUM_ARK_WEB_ENGINE_VERSION, &enumType)) != ANI_OK) {
WVLOG_E("FindEnum failed, status: %{public}d", status);
return nullptr;
}
auto version = OHOS::ArkWeb::getActiveWebEngineVersion();
ani_enum_item aniEnumState;
if ((status = (env->Enum_GetEnumItemByIndex(enumType, static_cast<ani_int>(version),
&aniEnumState))) != ANI_OK) {
WVLOG_E("Enum_GetEnumItemByIndex failed, status: %{public}d", status);
return nullptr;
}
WVLOG_D("GetActiveWebEngineVersion start");
return aniEnumState;
}
static void SetActiveWebEngineVersion(ani_env *env, ani_object object, ani_enum_item aniEngineVersion)
{
if (env == nullptr) {
WVLOG_E("env is nullptr");
return;
}
ani_int aniVersion;
ani_status status = ANI_ERROR;
if ((status = env->EnumItem_GetValue_Int(aniEngineVersion, &aniVersion)) != ANI_OK) {
WVLOG_E("EnumItem_GetValue_Int failed, status: %{public}d", status);
AniBusinessError::ThrowErrorByErrCode(env, PARAM_CHECK_ERROR);
return;
}
WVLOG_D("SetActiveWebEngineVersion start");
auto version = static_cast<OHOS::ArkWeb::ArkWebEngineVersion>(aniVersion);
OHOS::ArkWeb::setActiveWebEngineVersion(version);
}
static ani_boolean IsActiveWebEngineEvergreen(ani_env *env, ani_object object)
{
if (!OHOS::ArkWeb::IsActiveWebEngineEvergreen()) {
return ANI_FALSE;
}
return ANI_TRUE;
}
static ani_string GetLastPostMessageURL(ani_env *env, ani_object object)
{
ani_string lastPostMessageUrl = nullptr;
if (env == nullptr) {
WVLOG_E("env is nullptr");
return lastPostMessageUrl;
}
auto* controller = reinterpret_cast<WebviewController *>(AniParseUtils::Unwrap(env, object));
if (!controller || !controller->IsInit()) {
AniBusinessError::ThrowErrorByErrCode(env, INIT_ERROR);
return lastPostMessageUrl;
}
std::string result = controller->GetLastPostMessageURL();
env->String_NewUTF8(result.c_str(), result.size(), &lastPostMessageUrl);
return lastPostMessageUrl;
}
static ani_boolean InnerGetWebDebuggingAccess(ani_env* env, ani_object object)
{
WVLOG_D("InnerGetWebDebuggingAccess start");
if (!env) {
WVLOG_E("env is nullptr");
return ANI_FALSE;
}
bool webDebuggingAccess = WebviewController::webDebuggingAccess_;
return static_cast<ani_boolean>(webDebuggingAccess);
}
static ani_int InnerGetWebDebuggingPort(ani_env* env, ani_object object)
{
WVLOG_D("InnerGetWebDebuggingPort start");
ani_int port = 0;
if (!env) {
WVLOG_E("env is nullptr");
return port;
}
int32_t webDebuggingPort = WebviewController::webDebuggingPort_;
return static_cast<ani_int>(webDebuggingPort);
}
ani_status StsWebviewControllerInit(ani_env *env)
{
WVLOG_D("[DOWNLOAD] StsWebviewControllerInit");
if (!env) {
WVLOG_E("env is nullptr");
return ANI_ERROR;
}
ani_class webviewControllerCls = nullptr;
ani_status status = env->FindClass(ANI_CLASS_WEBVIEW_CONTROLLER, &webviewControllerCls);
if (status != ANI_OK || !webviewControllerCls) {
WVLOG_E("find %{public}s class failed, status: %{public}d", ANI_CLASS_WEBVIEW_CONTROLLER, status);
return ANI_ERROR;
}
std::array instanceMethods = {
ani_native_function { "<ctor>", "C{std.core.String}:", reinterpret_cast<void *>(Constructor) },
ani_native_function { "_setNWebId", nullptr, reinterpret_cast<void *>(SetNWebId) },
ani_native_function { "_setHapPath", nullptr, reinterpret_cast<void *>(SetHapPath) },
ani_native_function { "loadUrl", nullptr, reinterpret_cast<void *>(LoadUrl) },
ani_native_function { "onActive", nullptr, reinterpret_cast<void *>(OnActive) },
ani_native_function { "onInactive", nullptr, reinterpret_cast<void *>(OnInactive) },
ani_native_function { "getWebId", nullptr, reinterpret_cast<void *>(GetWebId) },
ani_native_function { "innerGetWebId", nullptr, reinterpret_cast<void *>(InnerGetWebId) },
ani_native_function { "getScrollable", nullptr, reinterpret_cast<void *>(GetScrollable) },
ani_native_function { "requestFocus", nullptr, reinterpret_cast<void *>(RequestFocus) },
ani_native_function { "clearClientAuthenticationCache", nullptr,
reinterpret_cast<void *>(clearClientAuthenticationCache) },
ani_native_function { "createPdfNative", nullptr, reinterpret_cast<void *>(CreatePdfNative) },
ani_native_function { "scrollByWithResult", nullptr, reinterpret_cast<void *>(ScrollByWithResult) },
ani_native_function { "setScrollable", nullptr, reinterpret_cast<void *>(SetScrollable) },
ani_native_function { "scrollTo", nullptr, reinterpret_cast<void *>(ScrollTo) },
ani_native_function { "scrollBy", nullptr, reinterpret_cast<void *>(ScrollBy) },
ani_native_function { "getScrollOffset", nullptr, reinterpret_cast<void *>(GetScrollOffset) },
ani_native_function { "getPageOffset", nullptr, reinterpret_cast<void *>(GetPageOffset) },
ani_native_function { "slideScroll", nullptr, reinterpret_cast<void *>(SlideScroll) },
ani_native_function { "zoom", nullptr, reinterpret_cast<void *>(Zoom) },
ani_native_function { "pageDown", nullptr, reinterpret_cast<void *>(PageDown) },
ani_native_function { "pageUp", nullptr, reinterpret_cast<void *>(PageUp) },
ani_native_function { "isAdsBlockEnabledForCurPage", nullptr,
reinterpret_cast<void *>(IsAdsBlockEnabledForCurPage) },
ani_native_function { "isIntelligentTrackingPreventionEnabled", nullptr,
reinterpret_cast<void *>(IsIntelligentTrackingPreventionEnabled) },
ani_native_function { "isSafeBrowsingEnabled", nullptr, reinterpret_cast<void *>(IsSafeBrowsingEnabled) },
ani_native_function { "getFavicon", nullptr, reinterpret_cast<void *>(GetFavicon) },
ani_native_function { "setUrlTrustList", "C{std.core.String}:", reinterpret_cast<void *>(SetUrlTrustList) },
ani_native_function { "setUrlTrustList", "C{std.core.String}zz:",
reinterpret_cast<void *>(SetUrlTrustListWithWildcard) },
ani_native_function { "enableIntelligentTrackingPrevention", nullptr,
reinterpret_cast<void *>(EnableIntelligentTrackingPrevention) },
ani_native_function { "searchNext", nullptr, reinterpret_cast<void *>(SearchNext) },
ani_native_function { "zoomOut", nullptr, reinterpret_cast<void *>(ZoomOut) },
ani_native_function { "zoomIn", nullptr, reinterpret_cast<void *>(ZoomIn) },
ani_native_function { "getLastHitTest", nullptr, reinterpret_cast<void *>(GetLastHitTest) },
ani_native_function { "getPageHeight", nullptr, reinterpret_cast<void *>(GetPageHeight) },
ani_native_function { "reload", nullptr, reinterpret_cast<void *>(Refresh) },
ani_native_function { "reloadIgnoreCache", nullptr, reinterpret_cast<void *>(ReloadIgnoreCache) },
ani_native_function { "stop", nullptr, reinterpret_cast<void *>(Stop) },
ani_native_function { "clearSslCache", nullptr, reinterpret_cast<void *>(clearSslCache) },
ani_native_function { "clearMatches", nullptr, reinterpret_cast<void *>(clearMatches) },
ani_native_function { "startDownload", nullptr, reinterpret_cast<void *>(StartDownload) },
ani_native_function { "setDownloadDelegate", nullptr, reinterpret_cast<void *>(SetDownloadDelegate) },
ani_native_function { "getBackForwardEntries", nullptr, reinterpret_cast<void *>(GetBackForwardEntries) },
ani_native_function { "accessStep", nullptr, reinterpret_cast<void *>(AccessStep) },
ani_native_function { "isAdsBlockEnabled", nullptr, reinterpret_cast<void *>(IsAdsBlockEnabled) },
ani_native_function { "enableAdsBlock", nullptr, reinterpret_cast<void *>(EnableAdsBlock) },
ani_native_function { "postUrl", nullptr, reinterpret_cast<void *>(PostUrl) },
ani_native_function { "postMessage", nullptr, reinterpret_cast<void *>(PostMessage) },
ani_native_function { "getUrl", nullptr, reinterpret_cast<void *>(GetUrlAni) },
ani_native_function { "getTitle", nullptr, reinterpret_cast<void *>(GetTitle) },
ani_native_function { "getProgress", nullptr, reinterpret_cast<void *>(GetProgress) },
ani_native_function { "getOriginalUrl", nullptr, reinterpret_cast<void *>(GetOriginalUrl) },
ani_native_function { "getUserAgent", nullptr, reinterpret_cast<void *>(GetUserAgent) },
ani_native_function { "getCustomUserAgent", nullptr, reinterpret_cast<void *>(GetCustomUserAgent) },
ani_native_function { "getLastJavascriptProxyCallingFrameUrl", nullptr,
reinterpret_cast<void *>(GetLastJavascriptProxyCallingFrameUrl) },
ani_native_function { "getSecurityLevel", nullptr, reinterpret_cast<void *>(GetSecurityLevel) },
ani_native_function { "prefetchPageUrl", nullptr, reinterpret_cast<void *>(PrefetchPage) },
ani_native_function { "prefetchPageUrlHeaders", nullptr, reinterpret_cast<void *>(PrefetchPage) },
ani_native_function { "prefetchPageUrlHeadersOptions", nullptr, reinterpret_cast<void *>(PrefetchPage) },
ani_native_function { "searchAllAsync", nullptr, reinterpret_cast<void *>(SearchAllAsync) },
ani_native_function { "forward", nullptr, reinterpret_cast<void *>(Forward) },
ani_native_function { "createWebMessagePorts", nullptr, reinterpret_cast<void *>(CreateWebMessagePorts) },
ani_native_function { "backward", nullptr, reinterpret_cast<void *>(Backward) },
ani_native_function { "accessForward", nullptr, reinterpret_cast<void *>(AccessForward) },
ani_native_function { "accessBackward", nullptr, reinterpret_cast<void *>(AccessBackward) },
ani_native_function { "loadData", nullptr, reinterpret_cast<void *>(LoadData) },
ani_native_function { "clearHistory", nullptr, reinterpret_cast<void *>(ClearHistory) },
ani_native_function { "clearWebSchemeHandler", nullptr, reinterpret_cast<void *>(ClearWebSchemeHandler) },
ani_native_function { "terminateRenderProcess", nullptr, reinterpret_cast<void *>(TerminateRenderProcess) },
ani_native_function { "backOrForward", nullptr, reinterpret_cast<void *>(BackOrForward) },
ani_native_function { "enableSafeBrowsing", nullptr, reinterpret_cast<void *>(EnableSafeBrowsing) },
ani_native_function { "setCustomUserAgent", nullptr, reinterpret_cast<void *>(SetCustomUserAgent) },
ani_native_function { "removeCache", nullptr, reinterpret_cast<void *>(RemoveCache) },
ani_native_function { "setNetworkAvailable", nullptr, reinterpret_cast<void *>(SetNetworkAvailable) },
ani_native_function { "isIncognitoMode", nullptr, reinterpret_cast<void *>(IsIncognitoMode) },
ani_native_function { "serializeWebStateInternal", nullptr, reinterpret_cast<void *>(SerializeWebState) },
ani_native_function { "setPathAllowingUniversalAccess", nullptr,
reinterpret_cast<void *>(SetPathAllowingUniversalAccess) },
ani_native_function { "onCreateNativeMediaPlayer", "C{std.core.Function2}:",
reinterpret_cast<void *>(OnCreateNativeMediaPlayer) },
ani_native_function { "injectOfflineResourcesInternal", nullptr,
reinterpret_cast<void *>(InjectOfflineResources) },
ani_native_function { "precompileJavaScriptInternal", nullptr, reinterpret_cast<void *>(PrecompileJavaScript) },
ani_native_function { "getSurfaceId", nullptr, reinterpret_cast<void *>(GetSurfaceId) },
ani_native_function { "setPrintBackground", nullptr, reinterpret_cast<void*>(SetPrintBackground) },
ani_native_function {
"createWebPrintDocumentAdapter", nullptr, reinterpret_cast<void*>(CreateWebPrintDocumentAdapter) },
ani_native_function { "getPrintBackground", nullptr, reinterpret_cast<void*>(GetPrintBackground) },
ani_native_function { "startCamera", nullptr, reinterpret_cast<void *>(StartCamera) },
ani_native_function { "closeAllMediaPresentations", nullptr,
reinterpret_cast<void *>(CloseAllMediaPresentations) },
ani_native_function { "stopAllMedia", nullptr, reinterpret_cast<void *>(StopAllMedia) },
ani_native_function { "stopCamera", nullptr, reinterpret_cast<void *>(StopCamera) },
ani_native_function { "closeCamera", nullptr, reinterpret_cast<void *>(CloseCamera) },
ani_native_function { "resumeMicrophone", nullptr, reinterpret_cast<void *>(ResumeMicrophone) },
ani_native_function { "stopMicrophone", nullptr, reinterpret_cast<void *>(StopMicrophone) },
ani_native_function { "pauseMicrophone", nullptr, reinterpret_cast<void *>(PauseMicrophone) },
ani_native_function { "pauseAllMedia", nullptr, reinterpret_cast<void *>(PauseAllMedia) },
ani_native_function { "resumeAllMedia", nullptr, reinterpret_cast<void *>(ResumeAllMedia) },
ani_native_function { "setAudioMuted", nullptr, reinterpret_cast<void *>(SetAudioMuted) },
ani_native_function { "getMediaPlaybackState", nullptr, reinterpret_cast<void *>(GetMediaPlaybackState) },
ani_native_function { "avoidVisibleViewportBottom", nullptr,
reinterpret_cast<void *>(AvoidVisibleViewportBottom) },
ani_native_function { "webPageSnapshot", nullptr, reinterpret_cast<void *>(WebPageSnapshot) },
ani_native_function { "innerCompleteWindowNew", nullptr, reinterpret_cast<void *>(InnerCompleteWindowNew) },
ani_native_function { "setWebSchemeHandler", nullptr, reinterpret_cast<void *>(SetWebSchemeHandler) },
ani_native_function { "registerJavaScriptProxy", nullptr, reinterpret_cast<void *>(RegisterJavaScriptProxy) },
ani_native_function { "deleteJavaScriptRegister", nullptr, reinterpret_cast<void *>(DeleteJavaScriptRegister) },
ani_native_function { "runJavaScriptCallback", nullptr, reinterpret_cast<void *>(RunJavaScriptCallback) },
ani_native_function { "runJavaScriptPromise", nullptr, reinterpret_cast<void *>(RunJavaScriptPromise) },
ani_native_function { "executeAIPageCommand", nullptr, reinterpret_cast<void *>(ExecuteAIPageCommand) },
ani_native_function { "runJavaScriptCallbackExt", nullptr, reinterpret_cast<void *>(RunJavaScriptCallbackExt) },
ani_native_function { "runJavaScriptPromiseExt", nullptr, reinterpret_cast<void *>(RunJavaScriptPromiseExt) },
ani_native_function { "setBackForwardCacheOptions", nullptr,
reinterpret_cast<void *>(SetBackForwardCacheOptions) },
ani_native_function { "storeWebArchiveCallback", nullptr, reinterpret_cast<void *>(StoreWebArchiveCallback) },
ani_native_function { "storeWebArchivePromise", nullptr, reinterpret_cast<void *>(StoreWebArchivePromise) },
ani_native_function { "hasImageCallback", nullptr, reinterpret_cast<void *>(HasImageCallback) },
ani_native_function { "hasImagePromise", nullptr, reinterpret_cast<void *>(HasImagePromise) },
ani_native_function { "restoreWebState", nullptr, reinterpret_cast<void*>(RestoreWebState) },
ani_native_function { "getCertificateSync", nullptr, reinterpret_cast<void*>(GetCertificateSync) },
ani_native_function { "jsProxy", nullptr, reinterpret_cast<void *>(InnerJsProxy) },
ani_native_function { "setErrorPageEnabled", "z:", reinterpret_cast<void*>(SetErrorPageEnabled) },
ani_native_function { "setErrorPageEnabled", "zz:", reinterpret_cast<void*>(SetErrorPageEnabledWithSubframe) },
ani_native_function { "getErrorPageEnabled", nullptr, reinterpret_cast<void*>(GetErrorPageEnabled) },
ani_native_function { "getSubframeErrorPageEnabled", nullptr,
reinterpret_cast<void*>(GetSubframeErrorPageEnabled) },
ani_native_function { "getBlanklessInfoWithKey", nullptr, reinterpret_cast<void*>(GetBlanklessInfoWithKey) },
ani_native_function { "setBlanklessLoadingWithKey", nullptr,
reinterpret_cast<void*>(SetBlanklessLoadingWithKey) },
ani_native_function { "setBlanklessLoadingWithParams", nullptr,
reinterpret_cast<void*>(SetBlanklessLoadingWithParams) },
ani_native_function { "setSoftKeyboardBehaviorMode", nullptr,
reinterpret_cast<void *>(SetSoftKeyboardBehaviorMode) },
ani_native_function { "getAttachState", nullptr, reinterpret_cast<void *>(GetAttachState) },
ani_native_function { "onControllerAttachStateChange", nullptr,
reinterpret_cast<void *>(OnControllerAttachStateChange) },
ani_native_function { "offControllerAttachStateChange", nullptr,
reinterpret_cast<void *>(OffControllerAttachStateChange) },
ani_native_function { "waitForAttachedPromise", nullptr, reinterpret_cast<void *>(WaitForAttachedPromise) },
ani_native_function { "setWebDetach", nullptr, reinterpret_cast<void *>(SetWebDetach) },
ani_native_function { "setUserAgentMetadata", nullptr, reinterpret_cast<void*>(SetUserAgentMetadata) },
ani_native_function { "getUserAgentMetadata", nullptr, reinterpret_cast<void*>(GetUserAgentMetadata) },
ani_native_function { "getLastPostMessageURL", nullptr, reinterpret_cast<void *>(GetLastPostMessageURL) },
ani_native_function { "innerGetWebDebuggingAccess", nullptr,
reinterpret_cast<void *>(InnerGetWebDebuggingAccess) },
ani_native_function { "innerGetWebDebuggingPort", nullptr, reinterpret_cast<void *>(InnerGetWebDebuggingPort) },
};
status = env->Class_BindNativeMethods(webviewControllerCls, instanceMethods.data(), instanceMethods.size());
if (status != ANI_OK) {
WVLOG_E("StsWebviewControllerInit Class_BindNativeMethods failed status: %{public}d", status);
}
std::array controllerStaticMethods = {
ani_native_function { "initializeWebEngine", nullptr, reinterpret_cast<void *>(InitializeWebEngine) },
ani_native_function { "addIntelligentTrackingPreventionBypassingList", nullptr,
reinterpret_cast<void *>(AddIntelligentTrackingPreventionBypassingList) },
ani_native_function { "removeIntelligentTrackingPreventionBypassingList", nullptr,
reinterpret_cast<void *>(RemoveIntelligentTrackingPreventionBypassingList) },
ani_native_function { "clearIntelligentTrackingPreventionBypassingList", nullptr,
reinterpret_cast<void *>(ClearIntelligentTrackingPreventionBypassingList) },
ani_native_function { "setHostIP", nullptr, reinterpret_cast<void *>(SetHostIP) },
ani_native_function { "clearHostIP", nullptr, reinterpret_cast<void *>(ClearHostIP) },
ani_native_function { "warmupServiceWorker", nullptr, reinterpret_cast<void *>(WarmupServiceWorker) },
ani_native_function { "prepareForPageLoad", nullptr, reinterpret_cast<void *>(PrepareForPageLoad) },
ani_native_function { "getDefaultUserAgent", nullptr, reinterpret_cast<void *>(GetDefaultUserAgent) },
ani_native_function { "removeAllCache", nullptr, reinterpret_cast<void *>(RemoveAllCache) },
ani_native_function { "setServiceWorkerWebSchemeHandler", nullptr,
reinterpret_cast<void *>(SetServiceWorkerWebSchemeHandler) },
ani_native_function { "setRenderProcessMode", nullptr, reinterpret_cast<void *>(SetRenderProcessMode) },
ani_native_function { "getRenderProcessMode", nullptr, reinterpret_cast<void *>(GetRenderProcessMode) },
ani_native_function { "setConnectionTimeout", nullptr, reinterpret_cast<void *>(SetConnectionTimeout) },
ani_native_function { "pauseAllTimers", nullptr, reinterpret_cast<void *>(PauseAllTimers) },
ani_native_function { "resumeAllTimers", nullptr, reinterpret_cast<void *>(ResumeAllTimers) },
ani_native_function { "trimMemoryByPressureLevel", nullptr,
reinterpret_cast<void *>(TrimMemoryByPressureLevel) },
ani_native_function { "clearPrefetchedResource", nullptr, reinterpret_cast<void *>(ClearPrefetchedResource) },
ani_native_function { "prefetchResource", nullptr, reinterpret_cast<void *>(PrefetchResource) },
ani_native_function { "enableWholeWebPageDrawing", nullptr,
reinterpret_cast<void *>(EnableWholeWebPageDrawing) },
ani_native_function { "setHttpDns", nullptr, reinterpret_cast<void *>(SetHttpDns) },
ani_native_function { "clearServiceWorkerWebSchemeHandler", nullptr,
reinterpret_cast<void *>(ClearServiceWorkerWebSchemeHandler) },
ani_native_function { "customizeSchemes", "C{std.core.Array}:", reinterpret_cast<void *>(CustomizeSchemes) },
ani_native_function {
"customizeSchemes", "C{std.core.Array}z:", reinterpret_cast<void *>(CustomizeSchemesLazyInit) },
ani_native_function { "setServiceWorkerWebSchemeHandler", nullptr,
reinterpret_cast<void *>(SetServiceWorkerWebSchemeHandler) },
ani_native_function {
"SetWebDebuggingAccess", nullptr, reinterpret_cast<void*>(SetWebDebuggingAccess) },
ani_native_function {
"setWebDebuggingAccessAndPort", nullptr, reinterpret_cast<void*>(SetWebDebuggingAccessAndPort) },
ani_native_function { "enableBackForwardCache", nullptr, reinterpret_cast<void *>(EnableBackForwardCache) },
ani_native_function { "setAppCustomUserAgent", nullptr, reinterpret_cast<void *>(SetAppCustomUserAgent) },
ani_native_function { "setUserAgentForHosts", nullptr, reinterpret_cast<void *>(SetUserAgentForHosts) },
ani_native_function { "setSiteIsolationMode", nullptr, reinterpret_cast<void *>(SetSiteIsolationMode) },
ani_native_function { "getSiteIsolationMode", nullptr, reinterpret_cast<void *>(GetSiteIsolationMode) },
ani_native_function { "enableAdvancedSecurityMode", nullptr,
reinterpret_cast<void *>(EnableAdvancedSecurityMode) },
ani_native_function { "enablePrivateNetworkAccess", nullptr,
reinterpret_cast<void*>(EnablePrivateNetworkAccess) },
ani_native_function { "isPrivateNetworkAccessEnabled", nullptr,
reinterpret_cast<void*>(IsPrivateNetworkAccessEnabled) },
ani_native_function { "clearBlanklessLoadingCache", nullptr,
reinterpret_cast<void*>(ClearBlanklessLoadingCache) },
ani_native_function { "setBlanklessLoadingCacheCapacity", nullptr,
reinterpret_cast<void*>(SetBlanklessLoadingCacheCapacity) },
ani_native_function { "setWebDestroyMode", nullptr,
reinterpret_cast<void *>(SetWebDestroyMode) },
ani_native_function { "isAutoPreconnectEnabled", nullptr, reinterpret_cast<void*>(IsAutoPreconnectEnabled) },
ani_native_function { "setAutoPreconnect", nullptr, reinterpret_cast<void*>(SetAutoPreconnect) },
ani_native_function { "getActiveWebEngineVersion", nullptr,
reinterpret_cast<void*>(GetActiveWebEngineVersion) },
ani_native_function { "setActiveWebEngineVersion", nullptr,
reinterpret_cast<void*>(SetActiveWebEngineVersion) },
ani_native_function { "isActiveWebEngineEvergreen", nullptr,
reinterpret_cast<void*>(IsActiveWebEngineEvergreen) },
ani_native_function { "setScrollbarMode", nullptr,
reinterpret_cast<void *>(SetScrollbarMode) },
ani_native_function {
"setUserAgentClientHintsEnabled", nullptr, reinterpret_cast<void*>(SetUserAgentClientHintsEnabled) },
ani_native_function {
"getUserAgentClientHintsEnabled", nullptr, reinterpret_cast<void*>(GetUserAgentClientHintsEnabled) },
ani_native_function { "setSocketIdleTimeout", nullptr, reinterpret_cast<void *>(SetSocketIdleTimeout) },
};
status = env->Class_BindStaticNativeMethods(webviewControllerCls, controllerStaticMethods.data(),
controllerStaticMethods.size());
if (status != ANI_OK) {
WVLOG_E("StsWebviewControllerInit Class_BindStaticNativeMethods failed status: %{public}d", status);
}
return ANI_OK;
}
}
}