/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
* 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.
*/
#import <WebKit/WebKit.h>
#import "AceWebInfoManager.h"
#include "base/log/log.h"
#define ARKUI_X_USER_AGENT @"ArkUIXDefaultUserAgent"
#define ARKUI_X_USER_AGENT_LAST_SYSTEM_VERSION @"ArkUIXUserAgentLastSystemVersion"
@interface AceWebInfoManager ()
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, copy) NSString *userAgent;
@property (nonatomic, copy) NSString *lastUpdateSystemVersion;
@end
@implementation AceWebInfoManager
+ (instancetype)sharedManager {
static AceWebInfoManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[AceWebInfoManager alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_userAgent = [[NSUserDefaults standardUserDefaults] stringForKey:ARKUI_X_USER_AGENT];
_lastUpdateSystemVersion = [[NSUserDefaults standardUserDefaults]
stringForKey:ARKUI_X_USER_AGENT_LAST_SYSTEM_VERSION];
[self.webView loadHTMLString:@"" baseURL:nil];
}
return self;
}
- (void)updateUserAgentIfNeeded {
NSString *currentSystemVersion = [self systemVersion];
if (!_lastUpdateSystemVersion || ![currentSystemVersion isEqualToString:_lastUpdateSystemVersion]) {
[self getUserAgent];
}
}
- (NSString *)systemVersion {
return [[UIDevice currentDevice] systemVersion];
}
- (NSString *)getUserAgent {
if (!_userAgent) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self refreshUserAgentWithCompletion:^{
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC));
}
return _userAgent ? _userAgent : [self fallbackUserAgent];
}
- (void)setUserAgent:(NSString *)userAgent {
if (!userAgent || userAgent.length == 0) {
return;
}
_userAgent = userAgent;
_lastUpdateSystemVersion = [self systemVersion];
[[NSUserDefaults standardUserDefaults] setObject:_userAgent forKey:ARKUI_X_USER_AGENT];
[[NSUserDefaults standardUserDefaults]
setObject:_lastUpdateSystemVersion forKey:ARKUI_X_USER_AGENT_LAST_SYSTEM_VERSION];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)refreshUserAgentWithCompletion:(void (^)(void))completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.webView evaluateJavaScript:@"window.location.href='about:blank';" completionHandler:nil];
[self.webView evaluateJavaScript:@"navigator.userAgent"
completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSString* desc = error.localizedDescription ?: @"";
LOGE("Error fetching UserAgent: %{public}s", desc.UTF8String);
} else {
if ([result isKindOfClass:[NSString class]]) {
[self setUserAgent:[NSString stringWithFormat:@"%@", result]];
}
}
if (completion) {
completion();
}
}];
});
}
- (WKWebView *)webView {
if (!_webView) {
_webView = [[WKWebView alloc] initWithFrame:CGRectZero];
}
return _webView;
}
- (NSString *)fallbackUserAgent {
NSString *deviceModel = [[UIDevice currentDevice] model];
NSString *osVersion = [self systemVersion];
return [NSString stringWithFormat:
@"Mozilla/5.0 (%@; CPU %@ OS %@ like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
deviceModel, deviceModel, [osVersion stringByReplacingOccurrencesOfString:@"." withString:@"_"]];
}
- (NSMutableSet<NSString *> *)authChallengeUseCredentials {
if (!_authChallengeUseCredentials) {
_authChallengeUseCredentials = [NSMutableSet set];
}
return _authChallengeUseCredentials;
}
@end