/*
* Copyright (c) 2023 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 <map>
#include <string>
#include <vector>
#include <mutex>
#import <Foundation/Foundation.h>
#include "scheme_handler/scheme_handler.h"
#include "base/log/log.h"
#import "AceWebResourcePlugin.h"
#import "AceWebControllerBridge.h"
#import "AceWebInfoManager.h"
#define MAX_DEPTH 10
void DealArrayType(NSArray* arrayArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument, int currentDepth);
void DealDictionaryType(NSDictionary* dicArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument, int currentDepth);
NSMutableDictionary* ConvertDictionaryToNSDictionary(const std::shared_ptr<OHOS::Ace::WebJSValue>& listValue);
NSMutableArray* ConvertListToNSArray(const std::shared_ptr<OHOS::Ace::WebJSValue>& listValue);
std::map<std::string, std::shared_ptr<AceWebDownloadImpl>> webDownloadImplMap;
std::map<std::string, std::chrono::steady_clock::time_point> lastReceivedTime;
std::map<std::string, int64_t> lastReceivedBytes;
std::mutex webDownloadImplMapMutex;
std::shared_ptr<AceWebDownloadImpl> getWebDownloadImpl(const std::string& guid)
{
auto it = webDownloadImplMap.find(guid);
if (it != webDownloadImplMap.end()) {
return it->second;
}
return nullptr;
}
double calculateDownloadSpeed(const std::string& guid, int64_t receivedBytes)
{
double speed = 0.0;
auto webDownloadImpl = webDownloadImplMap[guid];
auto currentTime = std::chrono::steady_clock::now();
auto lastTime = lastReceivedTime[guid];
auto lastBytes = lastReceivedBytes[guid];
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime).count();
if (duration > 0) {
speed = (receivedBytes - lastBytes) / duration;
}
lastReceivedTime[guid] = currentTime;
lastReceivedBytes[guid] = receivedBytes;
return speed;
}
void loadUrlOC(int id, const std::string& url, std::map<std::string, std::string> httpHeaders) {
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web == nil){
return;
}
NSString *ocUrl = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
for (auto it = httpHeaders.begin(); it != httpHeaders.end(); it++) {
NSString * key = (0 == it->first.length())?(@""):(@(it->first.c_str()));
NSString * value = (0 == it->second.length())?(@""):(@(it->second.c_str()));
[dict setObject:value forKey:key];
}
NSDictionary * nd = [NSDictionary dictionaryWithDictionary:dict];
[web loadUrl:ocUrl header:nd];
}
bool accessStepOC(int id, int32_t step){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
return [web accessStep:step];
}
return false;
}
void scrollToOC(int id, float x, float y){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
[web scrollTo:x y:y];
}
}
void scrollByOC(int id, float deltaX, float deltaY){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
[web scrollBy:deltaX deltaY:deltaY];
}
}
void zoomOC(int id, float factor){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
[web zoom:factor];
}
}
void zoomInOC(int id) {
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return;
}
[web zoomIn];
}
void zoomOutOC(int id) {
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return;
}
[web zoomOut];
}
bool isZoomAccessOC(int id) {
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return false;
}
return [web isZoomAccess];
}
void stopOC(int id){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
[web stop];
}
}
std::string getOriginalUrlOC(int id) {
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return "";
}
return [[web getOriginalUrl] UTF8String];
}
void pageUpOC(int id, bool value)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return;
}
[web pageUp:value];
}
void setCustomUserAgentOC(int id, const std::string& userAgent){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web != nil){
NSString *ocUserAgent = [NSString stringWithCString:userAgent.c_str() encoding:NSUTF8StringEncoding];
[web setCustomUserAgent:ocUserAgent];
}
}
std::string getCustomUserAgentOC(int id){
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if(web == nil){
return "";
}
return [[web getCustomUserAgent] UTF8String];
}
void loadDataOC(int id, const std::string& data, const std::string& mimeType, const std::string& encoding,
const std::string& baseUrl, const std::string& historyUrl)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
NSString* ocData = [NSString stringWithCString:data.c_str() encoding:NSUTF8StringEncoding];
NSString* ocMimeType = [NSString stringWithCString:mimeType.c_str() encoding:NSUTF8StringEncoding];
NSString* ocEncoding = [NSString stringWithCString:encoding.c_str() encoding:NSUTF8StringEncoding];
NSString* ocBaseUrl = [NSString stringWithCString:baseUrl.c_str() encoding:NSUTF8StringEncoding];
NSString* ocHistoryUrl = [NSString stringWithCString:historyUrl.c_str() encoding:NSUTF8StringEncoding];
[web loadData:ocData mimeType:ocMimeType encoding:ocEncoding baseUrl:ocBaseUrl historyUrl:ocHistoryUrl];
}
void evaluateJavaScriptOC(int webId, const std::string& script, int32_t asyncCallbackInfoId, void (*callbackOC)(const std::string& result, int32_t asyncCallbackInfoId))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocScript = [NSString stringWithCString:script.c_str() encoding:NSUTF8StringEncoding];
[web evaluateJavaScript:ocScript
callback:^(id _Nullable obj, NSError* _Nullable error) {
NSString* ocResult = [NSString stringWithFormat:@"%@", obj];
callbackOC([ocResult UTF8String], asyncCallbackInfoId);
}];
}
void evaluateJavaScriptExtOC(int webId, const std::string& script, int32_t asyncCallbackInfoId,
void (*callbackOC)(const std::string& type, const std::string& result, int32_t asyncCallbackInfoId))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocScript = [NSString stringWithCString:script.c_str() encoding:NSUTF8StringEncoding];
[web evaluateJavaScript:ocScript
callback:^(id _Nullable obj, NSError* _Nullable error) {
NSString* ocType = @"";
std::string ocResult = "";
if (error == nil) {
if ([obj isKindOfClass:[NSString class]]) {
ocType = @"STRING";
ocResult = [[NSString stringWithFormat:@"%@", obj] UTF8String];
} else if ([obj isKindOfClass:[NSNumber class]]) {
NSNumber* number = (NSNumber*)obj;
if (strcmp([obj objCType], @encode(char)) == 0){
ocType = @"BOOL";
bool boolValue = [number boolValue];
ocResult = boolValue ? "true" : "false";
} else if (strcmp([obj objCType], @encode(int)) == 0){
ocType = @"INT";
ocResult = [number stringValue].UTF8String;
} else {
ocType = @"DOUBLE";
ocResult = [number stringValue].UTF8String;
}
} else if ([obj isKindOfClass:[NSArray class]]) {
ocType = @"STRINGARRAY";
NSArray* array = (NSArray*)obj;
if (array.count > 0) {
id firstItem = array[0];
if ([firstItem isKindOfClass:[NSString class]]) {
ocType = @"STRINGARRAY";
} else if ([firstItem isKindOfClass:[NSNumber class]]) {
NSNumber* number = (NSNumber*)firstItem;
if (strcmp([number objCType], @encode(char)) == 0) {
ocType = @"BOOLEANARRAY";
} else if (strcmp([number objCType], @encode(int)) == 0) {
ocType = @"INTARRAY";
} else {
ocType = @"DOUBLEARRAY";
}
}
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:nil];
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
ocResult = [jsonString UTF8String];
}
} else {
ocType = @"STRING";
ocResult = "This type not support, only string/number/boolean/array is supported";
}
} else {
ocType = @"STRING";
NSString* errorDescription = [error localizedDescription];
ocResult = [errorDescription UTF8String];
}
callbackOC([ocType UTF8String], ocResult, asyncCallbackInfoId);
}];
}
std::string getUrlOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return "";
}
return [[web getUrl] UTF8String];
}
bool accessBackwardOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return false;
}
return [web accessBackward];
}
bool accessForwardOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return false;
}
return [web accessForward];
}
void backwardOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web backward];
}
void forwardOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web forward];
}
void refreshOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web refresh];
}
void removeCacheOC(int id, bool value)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web removeCache:value];
}
void backOrForwardOC(int id, int32_t step)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web backOrForward:step];
}
std::string getTitleOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return "";
}
return [[web getTitle] UTF8String];
}
int32_t getPageHeightOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return 0;
}
return (int)[web getPageHeight];
}
BackForwardResult getBackForwardEntriesOC(int id)
{
BackForwardResult backForwardResult;
BackForwardItem backForwardItem;
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web != nil) {
NSArray* backList = web.getWeb.backForwardList.backList;
NSArray* forwardList = web.getWeb.backForwardList.forwardList;
backForwardResult.currentIndex = (int)backList.count;
for (WKBackForwardListItem* backItem in backList) {
backForwardItem.URL = [[backItem.URL absoluteString] UTF8String];
backForwardItem.title = [backItem.title UTF8String];
backForwardItem.initialURL = [[backItem.initialURL absoluteString] UTF8String];
backForwardResult.backForwardItemList.push_back(backForwardItem);
}
backForwardItem.URL = [[web.getWeb.backForwardList.currentItem.URL absoluteString] UTF8String];
backForwardItem.title = [web.getWeb.backForwardList.currentItem.title UTF8String];
backForwardItem.initialURL = [[web.getWeb.backForwardList.currentItem.initialURL absoluteString] UTF8String];
backForwardResult.backForwardItemList.push_back(backForwardItem);
for (WKBackForwardListItem* forwardItem in forwardList) {
backForwardItem.URL = [[forwardItem.URL absoluteString] UTF8String];
backForwardItem.title = [forwardItem.title UTF8String];
backForwardItem.initialURL = [[forwardItem.initialURL absoluteString] UTF8String];
backForwardResult.backForwardItemList.push_back(backForwardItem);
}
}
return backForwardResult;
}
void createWebMessagePortsOC(int id, std::vector<std::string>& ports)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
NSArray* portsName = @[ @"port1", @"port2" ];
[web createWebMessagePorts:portsName];
ports.push_back([portsName[0] UTF8String]);
ports.push_back([portsName[1] UTF8String]);
}
void postWebMessageOC(int id, std::string& message, std::vector<std::string>& ports, std::string& targetUrl)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
NSString* ocMessage = [NSString stringWithCString:message.c_str() encoding:NSUTF8StringEncoding];
NSString* ocTargetUrl = [NSString stringWithCString:targetUrl.c_str() encoding:NSUTF8StringEncoding];
for (const auto& port : ports) {
NSString* ocPort = [NSString stringWithCString:port.c_str() encoding:NSUTF8StringEncoding];
[web postWebMessage:ocMessage port:ocPort targetUrl:ocTargetUrl];
}
}
bool postMessageEventOC(int id, const std::string& message)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return false;
}
NSString* ocMessage = [NSString stringWithCString:message.c_str() encoding:NSUTF8StringEncoding];
[web postMessageEvent:ocMessage];
return true;
}
bool postMessageEventExtOC(int id, const std::shared_ptr<AceWebMessageExtImpl> webMessageExtImpl){
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return false;
}
AceWebMessageType msgType = webMessageExtImpl->GetType();
switch (msgType) {
case AceWebMessageType::BOOLEAN:
[web postMessageEventExt:@(webMessageExtImpl->GetBoolean())];
break;
case AceWebMessageType::INTEGER:
[web postMessageEventExt:@(webMessageExtImpl->GetInt())];
break;
case AceWebMessageType::DOUBLE:
[web postMessageEventExt:@(webMessageExtImpl->GetDouble())];
break;
case AceWebMessageType::STRING: {
std::string value = webMessageExtImpl->GetString();
NSString* ocValue = [NSString stringWithCString:value.c_str() encoding:NSUTF8StringEncoding];
[web postMessageEventExt:ocValue];
break;
}
case AceWebMessageType::STRINGARRAY: {
NSMutableArray* ocArray = [NSMutableArray array];
std::vector<std::string> value = webMessageExtImpl->GetStringArray();
for (const auto& item : value) {
NSString* ocItem = [NSString stringWithCString:item.c_str() encoding:NSUTF8StringEncoding];
[ocArray addObject:ocItem];
}
[web postMessageEventExt:ocArray];
break;
}
case AceWebMessageType::BOOLEANARRAY: {
NSMutableArray* ocArray = [NSMutableArray array];
std::vector<bool> value = webMessageExtImpl->GetBooleanArray();
for (const auto& item : value) {
bool boolValue = item;
[ocArray addObject:@(boolValue)];
}
[web postMessageEventExt:ocArray];
break;
}
case AceWebMessageType::DOUBLEARRAY: {
NSMutableArray* ocArray = [NSMutableArray array];
std::vector<double> value = webMessageExtImpl->GetDoubleArray();
for (const auto& item : value) {
NSNumber* number = [NSNumber numberWithDouble:item];
[ocArray addObject:number];
}
[web postMessageEventExt:ocArray];
break;
}
case AceWebMessageType::INT64ARRAY: {
NSMutableArray* ocArray = [NSMutableArray array];
std::vector<int64_t> value = webMessageExtImpl->GetInt64Array();
for (const auto& item : value) {
NSNumber* number = [NSNumber numberWithLongLong:item];
[ocArray addObject:number];
}
[web postMessageEventExt:ocArray];
break;
}
case AceWebMessageType::BINARY: {
std::vector<uint8_t> value = webMessageExtImpl->GetArrayBuffer();
NSData* ocData = [NSData dataWithBytes:value.data() length:value.size()];
[web postMessageEventExt:ocData];
break;
}
case AceWebMessageType::ERROR: {
std::pair<std::string, std::string> errorInfo = webMessageExtImpl->GetError();
NSString* errorName = [NSString stringWithCString:errorInfo.first.c_str() encoding:NSUTF8StringEncoding];
NSString* errorMessage = [NSString stringWithCString:errorInfo.second.c_str() encoding:NSUTF8StringEncoding];
NSError* error = [NSError errorWithDomain:errorName code:0 userInfo:@{NSLocalizedDescriptionKey: errorMessage}];
[web postMessageEventExt:error];
break;
}
default:
break;
}
return true;
}
void onMessageEventOC(int id, const std::string& portHandle,
void (*callbackOC)(int32_t webId, const std::string& portHandle, const std::string& result))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web onMessageEvent:^(NSString* ocResult) {
callbackOC(id, portHandle, [ocResult UTF8String]);
}];
}
void onMessageEventExtOC(int webId, const std::string& portHandle,
void (*callbackOC)(int32_t webId, const std::string& portHandle,
const std::shared_ptr<AceWebMessageExtImpl> webMessageExtImpl))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
[web onMessageEventExt:^(id _Nullable ocResult) {
auto webMessageExtImpl = std::make_shared<AceWebMessageExtImpl>();
if (webMessageExtImpl == nullptr) {
LOGE("new WebMessageExt failed.");
return;
}
if ([ocResult isKindOfClass:[NSString class]]) {
webMessageExtImpl->SetString([ocResult UTF8String]);
} else if ([ocResult isKindOfClass:[NSNumber class]]) {
NSNumber* number = (NSNumber*)ocResult;
if (strcmp([ocResult objCType], @encode(char)) == 0) {
webMessageExtImpl->SetBoolean([number boolValue] ? true : false);
} else if (strcmp([ocResult objCType], @encode(int)) == 0) {
webMessageExtImpl->SetInt([number intValue]);
} else {
webMessageExtImpl->SetDouble([number doubleValue]);
}
} else if ([ocResult isKindOfClass:[NSArray class]]) {
NSArray* array = (NSArray*)ocResult;
if (array.count > 0) {
id firstItem = array[0];
if ([firstItem isKindOfClass:[NSString class]]) {
std::vector<std::string> stringArray;
for (NSString* item in array) {
stringArray.push_back([item UTF8String]);
}
webMessageExtImpl->SetStringArray(stringArray);
} else if ([firstItem isKindOfClass:[NSNumber class]]) {
if (strcmp([firstItem objCType], @encode(char)) == 0) {
std::vector<bool> boolArray;
for (NSNumber* item in array) {
boolArray.push_back([item boolValue] ? true : false);
}
webMessageExtImpl->SetBooleanArray(boolArray);
} else if (strcmp([firstItem objCType], @encode(int)) == 0) {
std::vector<int64_t> intArray;
for (NSNumber* item in array) {
intArray.push_back([item intValue]);
}
webMessageExtImpl->SetInt64Array(intArray);
} else {
std::vector<double> doubleArray;
for (NSNumber* item in array) {
doubleArray.push_back([item doubleValue]);
}
webMessageExtImpl->SetDoubleArray(doubleArray);
}
}
}
}
callbackOC(webId, portHandle, webMessageExtImpl);
}];
}
void closePortOC(int id)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (web == nil) {
return;
}
[web closePort];
}
bool saveHttpAuthCredentialsOC(
const std::string& host, const std::string& realm, const std::string& username, const char* password)
{
NSString* ocHost = [NSString stringWithCString:host.c_str() encoding:NSUTF8StringEncoding];
NSString* ocRealm = [NSString stringWithCString:realm.c_str() encoding:NSUTF8StringEncoding];
NSString* ocUsername = [NSString stringWithCString:username.c_str() encoding:NSUTF8StringEncoding];
NSString* ocPassword = [NSString stringWithUTF8String:password];
return [AceWeb saveHttpAuthCredentials:ocHost realm:ocRealm username:ocUsername password:ocPassword];
}
bool getHttpAuthCredentialsOC(const std::string& host, const std::string& realm, std::string& username, char* password, uint32_t passwordSize)
{
NSString* ocHost = [NSString stringWithCString:host.c_str() encoding:NSUTF8StringEncoding];
NSString* ocRealm = [NSString stringWithCString:realm.c_str() encoding:NSUTF8StringEncoding];
NSURLCredential* value = [AceWeb getHttpAuthCredentials:ocHost realm:ocRealm];
if (value == nil) {
return false;
}
username = [value.user UTF8String];
strlcpy(password, (char*)[value.password UTF8String], passwordSize);
return true;
}
bool existHttpAuthCredentialsOC()
{
return [AceWeb existHttpAuthCredentials];
}
bool deleteHttpAuthCredentialsOC()
{
return [AceWeb deleteHttpAuthCredentials];
}
void setWebDebuggingAccessOC(bool webDebuggingAccess){
[AceWeb setWebDebuggingAccess:webDebuggingAccess];
}
void pageDownOC(int id, bool value)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return;
}
[web pageDown:value];
}
void postUrlOC(int id, const std::string& url, const std::vector<uint8_t>& postData)
{
AceWeb *web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", id]];
if (!web) {
LOGE("Error:AceWebControllerBridge web is NULL");
return;
}
NSData *data = [NSData dataWithBytes:postData.data() length:postData.size()];
NSString *nsUrl = [NSString stringWithCString:url.c_str()];
[web postUrl:nsUrl postData:data];
}
void startDownloadOC(int webId, const std::string& url)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocUrl = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
[web startDownload:ocUrl];
}
void onDownloadBeforeStartOC(int32_t webId,
void (*callbackOC)(int32_t webId, const std::shared_ptr<AceWebDownloadImpl> webDownloadImpl))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
[web onDownloadBeforeStart:^(NSString* guid, NSString* method, NSString* mimeType, NSString* url) {
auto webDownloadImpl = std::make_shared<AceWebDownloadImpl>();
webDownloadImplMap[[guid UTF8String]] = webDownloadImpl;
webDownloadImpl->SetGuid([guid UTF8String]);
webDownloadImpl->SetMethod([method UTF8String]);
webDownloadImpl->SetMimeType([mimeType UTF8String]);
webDownloadImpl->SetUrl([url UTF8String]);
webDownloadImpl->SetState(WebDownloadState::PENDING);
callbackOC(webId, webDownloadImpl);
}];
}
void onDownloadUpdatedOC(int32_t webId,
void (*callbackOC)(int32_t webId, const std::shared_ptr<AceWebDownloadImpl> webDownloadImpl))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
[web onDownloadUpdated:^(NSString* guid, NSString* state, int64_t totalBytes, int64_t receivedBytes, NSString* suggestedFileName) {
auto webDownloadImpl = getWebDownloadImpl([guid UTF8String]);
if (webDownloadImpl != nullptr) {
if ([state isEqualToString:@"IN_PROGRESS"]) {
double progress = (double)receivedBytes / (double)totalBytes;
webDownloadImpl->SetGuid([guid UTF8String]);
webDownloadImpl->SetTotalBytes(totalBytes);
webDownloadImpl->SetReceivedBytes(receivedBytes);
webDownloadImpl->SetLastErrorCode(0);
webDownloadImpl->SetPercentComplete(progress*100);
webDownloadImpl->SetCurrentSpeed(calculateDownloadSpeed([guid UTF8String], receivedBytes));
webDownloadImpl->SetState(WebDownloadState::IN_PROGRESS);
webDownloadImpl->SetSuggestedFileName([suggestedFileName UTF8String]);
} else if ([state isEqualToString:@"PAUSED"]) {
webDownloadImpl->SetState(WebDownloadState::PAUSED);
} else if ([state isEqualToString:@"PENDING"]) {
webDownloadImpl->SetState(WebDownloadState::PENDING);
}
callbackOC(webId, webDownloadImpl);
}
}];
}
void onDownloadFailedOC(int32_t webId,
void (*callbackOC)(int32_t webId, const std::shared_ptr<AceWebDownloadImpl> webDownloadImpl))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
[web onDownloadFailed:^(NSString* guid, NSString* state, int64_t code) {
auto webDownloadImpl = getWebDownloadImpl([guid UTF8String]);
if (webDownloadImpl != nullptr) {
webDownloadImpl->SetGuid([guid UTF8String]);
if ([state isEqualToString:@"CANCELED"]) {
webDownloadImpl->SetLastErrorCode(40);
webDownloadImpl->SetState(WebDownloadState::CANCELED);
} else {
webDownloadImpl->SetState(WebDownloadState::INTERRUPTED);
}
webDownloadImplMap.erase([guid UTF8String]);
callbackOC(webId, webDownloadImpl);
}
}];
}
void onDownloadFinishOC(int32_t webId,
void (*callbackOC)(int32_t webId, const std::shared_ptr<AceWebDownloadImpl> webDownloadImpl))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
[web onDownloadFinish:^(NSString* guid, NSString* path) {
auto webDownloadImpl = getWebDownloadImpl([guid UTF8String]);
if (webDownloadImpl != nullptr) {
webDownloadImpl->SetGuid([guid UTF8String]);
webDownloadImpl->SetFullPath([path UTF8String]);
webDownloadImpl->SetPercentComplete(100);
webDownloadImpl->SetReceivedBytes(webDownloadImpl->GetTotalBytes());
webDownloadImpl->SetState(WebDownloadState::COMPLETE);
webDownloadImplMap.erase([guid UTF8String]);
callbackOC(webId, webDownloadImpl);
}
}];
}
void webDownloadItemStartOC(int webId, const std::string& guid, const std::string& path)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocPath = [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding];
NSString* ocGuid = [NSString stringWithCString:guid.c_str() encoding:NSUTF8StringEncoding];
[web webDownloadItemStart:ocGuid ocPath:ocPath];
}
void webDownloadItemCancelOC(int webId, const std::string& guid)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocGuid = [NSString stringWithCString:guid.c_str() encoding:NSUTF8StringEncoding];
[web webDownloadItemCancel:ocGuid];
webDownloadImplMap.erase(guid);
}
void webDownloadItemPauseOC(int webId, const std::string& guid)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocGuid = [NSString stringWithCString:guid.c_str() encoding:NSUTF8StringEncoding];
[web webDownloadItemPause:ocGuid];
}
void webDownloadItemResumeOC(int webId, const std::string& guid)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocGuid = [NSString stringWithCString:guid.c_str() encoding:NSUTF8StringEncoding];
[web webDownloadItemResume:ocGuid];
}
void DealNumberType(NSNumber* numArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument)
{
if (numArg == nil) {
LOGE("DealNumberType param is nil");
return;
}
if (argument == nullptr) {
LOGE("DealNumberType argument is nil");
return;
}
if (strcmp([numArg objCType], @encode(char)) == 0) {
argument->SetType(OHOS::Ace::WebJSValue::Type::BOOLEAN);
argument->SetBoolean([numArg boolValue]);
} else if (strcmp([numArg objCType], @encode(double)) == 0) {
argument->SetType(OHOS::Ace::WebJSValue::Type::DOUBLE);
argument->SetDouble([numArg doubleValue]);
} else if (strcmp([numArg objCType], @encode(int)) == 0) {
argument->SetType(OHOS::Ace::WebJSValue::Type::INTEGER);
argument->SetInt([numArg intValue]);
} else {
LOGE("DealNumberType undefined type");
}
}
void DealStringType(NSString* stringArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument)
{
if (stringArg == nil) {
LOGE("DealStringType paramStrting nil");
return;
}
if (argument == nullptr) {
LOGE("DealStringType argument is nil");
return;
}
argument->SetType(OHOS::Ace::WebJSValue::Type::STRING);
argument->SetString([stringArg UTF8String]);
}
void DealArrayType(NSArray* arrayArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument, int currentDepth = 0)
{
if (currentDepth >= MAX_DEPTH) {
LOGE("Exceeded maximum depth for array, setting value to null");
argument->SetType(OHOS::Ace::WebJSValue::Type::NONE);
return;
}
for (id subArg in arrayArg) {
std::shared_ptr<OHOS::Ace::WebJSValue> subargument =
std::make_shared<OHOS::Ace::WebJSValue>(OHOS::Ace::WebJSValue::Type::NONE);
if (subargument == nullptr) {
LOGE("subargument is nullptr");
return;
}
if (subArg == nil) {
LOGE("subarray arg is nil");
return;
}
if ([subArg isKindOfClass:[NSArray class]]) {
NSArray* subArray = (NSArray*)subArg;
subargument->SetType(OHOS::Ace::WebJSValue::Type::LIST);
DealArrayType(subArray, subargument, currentDepth + 1);
argument->AddListValue(*subargument);
} else if ([subArg isKindOfClass:[NSDictionary class]]) {
NSDictionary* dictionaryArg = (NSDictionary*)subArg;
subargument->SetType(OHOS::Ace::WebJSValue::Type::DICTIONARY);
DealDictionaryType(dictionaryArg, subargument, currentDepth + 1);
argument->AddListValue(*subargument);
} else if ([subArg isKindOfClass:[NSNumber class]]) {
NSNumber* numArg = (NSNumber*)subArg;
DealNumberType(numArg, subargument);
argument->AddListValue(*subargument);
} else if ([subArg isKindOfClass:[NSString class]]) {
NSString* stringArg = (NSString*)subArg;
DealStringType(stringArg, subargument);
argument->AddListValue(*subargument);
} else {
LOGE("subarray arg is of unknown type");
subargument->SetType(OHOS::Ace::WebJSValue::Type::NONE);
argument->AddListValue(*subargument);
}
}
}
void DealDictionaryType(NSDictionary* dicArg, std::shared_ptr<OHOS::Ace::WebJSValue>& argument, int currentDepth = 0)
{
if (currentDepth >= MAX_DEPTH) {
LOGE("Exceeded maximum depth for dictionary, setting value to null");
argument->SetType(OHOS::Ace::WebJSValue::Type::NONE);
return;
}
for (id key in dicArg) {
std::shared_ptr<OHOS::Ace::WebJSValue> subArgument =
std::make_shared<OHOS::Ace::WebJSValue>(OHOS::Ace::WebJSValue::Type::NONE);
if (subArgument == nullptr) {
LOGE("subArgument is nullptr");
return;
}
if (key == nil) {
LOGE("subdictionary arg key is nil");
return;
}
id value = dicArg[key];
if ([value isKindOfClass:[NSDictionary class]]) {
subArgument->SetType(OHOS::Ace::WebJSValue::Type::DICTIONARY);
DealDictionaryType((NSDictionary*)value, subArgument, currentDepth + 1);
argument->AddDictionaryValue([key UTF8String], *subArgument);
} else if ([value isKindOfClass:[NSArray class]]) {
subArgument->SetType(OHOS::Ace::WebJSValue::Type::LIST);
DealArrayType((NSArray*)value, subArgument, currentDepth + 1);
argument->AddDictionaryValue([key UTF8String], *subArgument);
} else if ([value isKindOfClass:[NSNumber class]]) {
DealNumberType((NSNumber*)value, subArgument);
argument->AddDictionaryValue([key UTF8String], *subArgument);
} else if ([value isKindOfClass:[NSString class]]) {
DealStringType((NSString*)value, subArgument);
argument->AddDictionaryValue([key UTF8String], *subArgument);
} else {
LOGE("subdictionary arg is of unknown type");
subArgument->SetType(OHOS::Ace::WebJSValue::Type::NONE);
argument->AddDictionaryValue([key UTF8String], *subArgument);
}
}
}
id ConvertWebJSValueToNSObject(OHOS::Ace::WebJSValue& item)
{
switch (item.GetType()) {
case OHOS::Ace::WebJSValue::Type::INTEGER:
return @(item.GetInt());
case OHOS::Ace::WebJSValue::Type::DOUBLE:
return @(item.GetDouble());
case OHOS::Ace::WebJSValue::Type::BOOLEAN:
return @(item.GetBoolean());
case OHOS::Ace::WebJSValue::Type::STRING:
return [NSString stringWithUTF8String:item.GetString().c_str()];
case OHOS::Ace::WebJSValue::Type::LIST: {
auto sharedItem = std::make_shared<OHOS::Ace::WebJSValue>(item);
if (sharedItem == nullptr) {
LOGE("ConvertWebJSValueToNSObject List sharedItem is nullptr");
return nil;
}
return ConvertListToNSArray(sharedItem);
}
case OHOS::Ace::WebJSValue::Type::DICTIONARY: {
auto sharedItem = std::make_shared<OHOS::Ace::WebJSValue>(item);
if (sharedItem == nullptr) {
LOGE("ConvertWebJSValueToNSObject DICTIONARY sharedItem is nullptr");
return nil;
}
return ConvertDictionaryToNSDictionary(sharedItem);
}
default:
LOGE("ConvertWebJSValueToNSObject Unsupported type in WebJSValue");
return nil;
}
}
NSMutableArray* ConvertListToNSArray(const std::shared_ptr<OHOS::Ace::WebJSValue>& listValue)
{
if (listValue == nullptr) {
LOGE("listValue is nullptr");
return nil;
}
NSMutableArray* array = [NSMutableArray array];
auto list = listValue->GetListValue();
for (auto& item: list) {
id convertedItem = ConvertWebJSValueToNSObject(item);
if (convertedItem != nil) {
[array addObject:convertedItem];
} else {
LOGE("Unsupported type in nested list, adding NSNull");
[array addObject:[NSNull null]];
}
}
return array;
}
NSMutableDictionary* ConvertDictionaryToNSDictionary(const std::shared_ptr<OHOS::Ace::WebJSValue>& listValue)
{
if (listValue == nullptr) {
return nil;
}
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
auto dict = listValue->GetDictionaryValue();
for (auto& item: dict) {
if (item.first.empty()) {
LOGE("Key is empty, skipping");
continue;
}
NSString* key = [NSString stringWithUTF8String:item.first.c_str()];
id convertedValue = ConvertWebJSValueToNSObject(item.second);
if (convertedValue != nil) {
[dictionary setObject:convertedValue forKey:key];
} else {
LOGE("Unsupported type for key: %{public}s, adding NSNull", key.UTF8String);
[dictionary setObject:[NSNull null] forKey:key];
}
}
return dictionary;
}
id ConvertResultToObjectiveC(const std::shared_ptr<OHOS::Ace::WebJSValue>& result)
{
if (result == nullptr) {
LOGE("ConvertResultToObjectiveC result is nullptr");
return nil;
}
switch (result->GetType()) {
case OHOS::Ace::WebJSValue::Type::INTEGER:
return [NSNumber numberWithInt:result->GetInt()];
case OHOS::Ace::WebJSValue::Type::DOUBLE:
return [NSNumber numberWithDouble:result->GetDouble()];
case OHOS::Ace::WebJSValue::Type::BOOLEAN:
return [NSNumber numberWithBool:result->GetBoolean()];
case OHOS::Ace::WebJSValue::Type::STRING:
return [NSString stringWithUTF8String:result->GetString().c_str()];
case OHOS::Ace::WebJSValue::Type::LIST:
return ConvertListToNSArray(result);
case OHOS::Ace::WebJSValue::Type::DICTIONARY:
return ConvertDictionaryToNSDictionary(result);
default:
break;
}
return nil;
}
NSMutableArray* GetMethodList(const std::vector<std::string>& methodList)
{
NSMutableArray* ocMethodList = [NSMutableArray array];
for (const auto& method : methodList) {
NSString* methodName = [NSString stringWithCString:method.c_str() encoding:NSUTF8StringEncoding];
[ocMethodList addObject:methodName];
}
return ocMethodList;
}
void registerJavaScriptProxyOC(int webId, const std::string& objName,
const std::vector<std::string>& syncMethodList, const std::vector<std::string>& asyncMethodList,
std::shared_ptr<OHOS::Ace::WebJSValue> (*callbackOC)(const std::string& objName,
const std::string& methodName, const std::vector<std::shared_ptr<OHOS::Ace::WebJSValue>>& args))
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocObjName = [NSString stringWithCString:objName.c_str() encoding:NSUTF8StringEncoding];
NSMutableArray* ocSyncMethodList = GetMethodList(syncMethodList);
NSMutableArray* ocAsyncMethodList = GetMethodList(asyncMethodList);
[web registerJavaScriptProxy:ocObjName syncMethodList:ocSyncMethodList asyncMethodList:ocAsyncMethodList
callback:^id(NSString* objName, NSString* methodName, NSArray* args) {
std::vector<std::shared_ptr<OHOS::Ace::WebJSValue>> argsList;
for (id arg in args) {
std::shared_ptr<OHOS::Ace::WebJSValue> argument =
std::make_shared<OHOS::Ace::WebJSValue>(OHOS::Ace::WebJSValue::Type::NONE);
if (argument == nullptr) {
LOGE("argument is nullptr");
break;
}
if ([arg isKindOfClass:[NSNumber class]]) {
NSNumber* numberArg = (NSNumber *)arg;
DealNumberType((NSNumber*)arg, argument);
}
if ([arg isKindOfClass:[NSString class]]) {
DealStringType((NSString*)arg, argument);
} else if ([arg isKindOfClass:[NSArray class]]){
argument->SetType(OHOS::Ace::WebJSValue::Type::LIST);
DealArrayType((NSArray*)arg, argument);
} else if ([arg isKindOfClass:[NSDictionary class]]){
argument->SetType(OHOS::Ace::WebJSValue::Type::DICTIONARY);
DealDictionaryType((NSDictionary*)arg, argument);
}
argsList.push_back(argument);
}
auto result = callbackOC([objName UTF8String], [methodName UTF8String], argsList);
return ConvertResultToObjectiveC(result);
}];
}
void deleteJavaScriptRegisterOC(int webId, const std::string& objName)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return;
}
NSString* ocObjName = [NSString stringWithCString:objName.c_str() encoding:NSUTF8StringEncoding];
[web deleteJavaScriptRegister:ocObjName];
}
bool setWebSchemeHandlerOC(int webId, const char* scheme, const ArkWeb_SchemeHandler* handler)
{
if (scheme == nullptr || handler == nullptr) {
return false;
}
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return false;
}
NSString* ocScheme = [NSString stringWithCString:scheme encoding:NSUTF8StringEncoding];
return [web setWebSchemeHandler:ocScheme handler:handler];
}
bool clearWebSchemeHandlerOC(int webId)
{
AceWeb* web = [AceWebResourcePlugin.getObjectMap objectForKey:[NSString stringWithFormat:@"%d", webId]];
if (web == nil) {
return false;
}
return [web clearWebSchemeHandler];
}
std::string getUserAgentOC()
{
return [[[AceWebInfoManager sharedManager] getUserAgent] UTF8String];
}