// // XenonSDK-Load.m // XenonSDK // // Created by SAGESSE on 2019/3/11. // Copyright © 2019 SAGESSE. All rights reserved. // #import #import /// Load the file from the Forwarder. id sdk_load_mapper = nil; id sdk_load_root = nil; //unsigned char* sdk_load_data(const char* name, const char* mode, size_t* osize) { // // printf("loader: %s - %s\n", name, mode); // // FILE* fp = fopen(name, mode); // // if (fp == nil) { // *osize = 0; // return nil; // } // // fseek(fp,0,SEEK_END); // ssize_t size = ftell(fp); // fseek(fp,0,SEEK_SET); // // unsigned char* buffer = malloc(size + 1); // size_t readed = fread(buffer, 1, size, fp); // // if (readed >= 0) { // buffer[readed] = '\0'; // } // // *osize = readed; // fclose(fp); // return buffer; //} //// Register methods with NSFileManager. //@implementation NSFileManager (XenonSDK) // //- (BOOL)sdk_fileExistsAtPath:(NSString*)path { // //printf("chcker: %s\n", path.UTF8String);; // // // Find the path after removing the bundle. // if (sdk_load_root != nil ) { // NSString* root = NSBundle.mainBundle.bundlePath; // if ([path hasPrefix:root]) { // NSString* relative = [path stringByReplacingOccurrencesOfString:root withString:@""]; // NSDictionary* descriptor = [sdk_load_mapper objectForKeyedSubscript:relative]; // if (descriptor != nil) { // relative = [descriptor objectForKeyedSubscript:@"path"]; // path = [sdk_load_root stringByAppendingPathComponent: relative]; // } // } // } // // return [self sdk_fileExistsAtPath:path]; //} // //@end // Register methods with NSBundle. @implementation NSBundle (XenonSDK) + (void)load { // Load mapper. NSURL* url = [NSBundle.mainBundle.executableURL URLByAppendingPathExtension:@"plist"]; NSDictionary* mapper = [NSDictionary dictionaryWithContentsOfURL:url]; // If the mapper file fails to load, ignore it. if (mapper == nil) { return; } // Save the map table. sdk_load_mapper = mapper; // Check if the app is unity project. if ([mapper[@"*"] isEqual:@"u"] || [mapper[@"*"] isEqual:@"k"]) { NSString* realBundlePath = NSBundle.mainBundle.bundlePath; NSString* linkBundlePath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) firstObject] stringByAppendingPathComponent:realBundlePath.lastPathComponent]; NSError* error = nil; NSFileManager* fileManager = [NSFileManager defaultManager]; // The relink each time to prevent changes. [fileManager removeItemAtPath:linkBundlePath error:&error]; [fileManager createDirectoryAtPath:linkBundlePath withIntermediateDirectories:YES attributes:nil error:&error]; // Create the connection file the first time you install it. [mapper enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, NSDictionary* obj, BOOL * _Nonnull stop) { if ([key isEqual:@"*"]) { return; } NSString* src = [realBundlePath stringByAppendingPathComponent:obj[@"path"]]; NSString* dest = [linkBundlePath stringByAppendingPathComponent:key]; BOOL isDirectory = NO; NSError* suberror = nil; // If the file does not exist, ignore it. if (![fileManager fileExistsAtPath:src isDirectory:&isDirectory]) { return ; } // If this is a directory file, create it directly. if (isDirectory) { [fileManager createDirectoryAtPath:dest withIntermediateDirectories:YES attributes:nil error:&suberror]; return; } // Check that the root directory exists, and if it does not, create it. if (![fileManager fileExistsAtPath:dest.stringByDeletingLastPathComponent]) { [fileManager createDirectoryAtPath:dest.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:nil error:&suberror]; } // Create file a soft link. [fileManager createSymbolicLinkAtPath:dest withDestinationPath:src error:&suberror]; }]; if ([mapper[@"*"] isEqual:@"k"]) { sdk_load_root = linkBundlePath; Method m1 = class_getInstanceMethod(self, @selector(URLForResource:withExtension:subdirectory:)); Method m2 = class_getInstanceMethod(self, @selector(sdk_URLForResource:withExtension:subdirectory:)); method_exchangeImplementations(m1, m2); // Method m3 = class_getInstanceMethod(NSFileManager.class, @selector(fileExistsAtPath:)); // Method m4 = class_getInstanceMethod(NSFileManager.class, @selector(sdk_fileExistsAtPath:)); // method_exchangeImplementations(m3, m4); return; } // Register with the project class. Class tmp = objc_allocateClassPair(NSObject.class, "XCBundle", 0); objc_registerClassPair(tmp); class_addMethod(objc_getMetaClass("XCBundle"), @selector(bundlePath), imp_implementationWithBlock((id)^{ return linkBundlePath; }), "@:"); return; } // Check if the app is cocos project. if ([mapper[@"*"] isEqual:@"c"]) { Method m1 = class_getInstanceMethod(self, @selector(URLForResource:withExtension:subdirectory:)); Method m2 = class_getInstanceMethod(self, @selector(sdk_URLForResource:withExtension:subdirectory:)); method_exchangeImplementations(m1, m2); } } - (NSURL*)sdk_URLForResource:(NSString*)resource withExtension:(NSString*)extension subdirectory:(NSString*)subdirectory { NSString* path = resource; if (subdirectory != nil) { path = [subdirectory stringByAppendingPathComponent:path]; } if (extension != nil) { path = [path stringByAppendingPathExtension:extension]; } if (path.length != 0 && [path hasPrefix:@"/"]) { path = [path substringFromIndex:1]; } NSDictionary* descriptor = [sdk_load_mapper objectForKeyedSubscript:path]; if (descriptor != nil) { if (sdk_load_root != nil) { return [NSURL URLWithString:[sdk_load_root stringByAppendingPathComponent:path]]; } path = [descriptor objectForKeyedSubscript:@"path"]; if (path != nil) { return [self sdk_URLForResource:path withExtension:nil subdirectory:nil]; } } return [self sdk_URLForResource:resource withExtension:extension subdirectory:subdirectory]; } @end //// Register methods with NSObject. //@implementation NSObject (XenonSDK) // //+ (void*)XCForwarderInit { // printf("loader: init\n"); // //// Method m1 = class_getInstanceMethod(NSBundle.class, @selector(pathForResource:ofType:inDirectory:)); //// Method m2 = class_getInstanceMethod(NSBundle.class, @selector(sdk_pathForResource:ofType:inDirectory:)); //// method_exchangeImplementations(m1, m2); // //// Method m3 = class_getInstanceMethod(NSBundle.class, @selector(fileExistsAtPath:)); //// Method m4 = class_getInstanceMethod(NSBundle.class, @selector(sdk_fileExistsAtPath:)); //// method_exchangeImplementations(m3, m4); // //// return &sdk_load_data; // return nil; //} // //@end