diff --git a/lib/CIOSUtils.h b/lib/CIOSUtils.h index 682429747..d3beaa0ce 100644 --- a/lib/CIOSUtils.h +++ b/lib/CIOSUtils.h @@ -7,10 +7,25 @@ * Full text of license available in license.txt file, in main folder * */ +#include + +#ifdef __OBJC__ +@class NSURL; +#endif extern const char *ios_documentsPath(); extern const char *ios_cachesPath(); +#ifdef __OBJC__ +NSURL *sharedContainerURL(); +NSURL *sharedGameDataURL(); +#endif +extern const char *ios_sharedDataPath(); + +#if TARGET_OS_SIMULATOR +extern const char *ios_hostApplicationSupportPath(); +#endif + extern const char *ios_bundlePath(); extern const char *ios_frameworksPath(); diff --git a/lib/CIOSUtils.m b/lib/CIOSUtils.m index 0621f1230..ee1db12c0 100644 --- a/lib/CIOSUtils.m +++ b/lib/CIOSUtils.m @@ -12,15 +12,46 @@ @import Foundation; -static const char *standardPath(NSSearchPathDirectory directory) +static NSString *standardPathNative(NSSearchPathDirectory directory) { - return [NSFileManager.defaultManager URLForDirectory:directory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL].path.UTF8String; + return [NSFileManager.defaultManager URLForDirectory:directory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL].path; } +static const char *standardPath(NSSearchPathDirectory directory) { return standardPathNative(directory).fileSystemRepresentation; } const char *ios_documentsPath() { return standardPath(NSDocumentDirectory); } const char *ios_cachesPath() { return standardPath(NSCachesDirectory); } -const char *ios_bundlePath() { return NSBundle.mainBundle.bundlePath.UTF8String; } -const char *ios_frameworksPath() { return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Frameworks"].UTF8String; } // TODO: sharedFrameworksPath? +NSURL *sharedContainerURL() +{ + static NSURL *sharedPathURL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __auto_type bundleID = NSBundle.mainBundle.bundleIdentifier; + __auto_type lastDotPos = [bundleID rangeOfString:@"." options:NSBackwardsSearch].location; + __auto_type groupID = [NSString stringWithFormat:@"group.%@.vcmi", [bundleID substringToIndex:lastDotPos]]; + sharedPathURL = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:groupID]; + }); + return sharedPathURL; +} +NSURL *sharedGameDataURL() { return [sharedContainerURL() URLByAppendingPathComponent:@"GameData"]; } +const char *ios_sharedDataPath() { return sharedGameDataURL().fileSystemRepresentation; } + +#if TARGET_OS_SIMULATOR +const char *ios_hostApplicationSupportPath() +{ + static NSString *applicationSupportPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __auto_type cachesPath = standardPathNative(NSCachesDirectory); + __auto_type afterMacOsHomeDirPos = [cachesPath rangeOfString:@"Library/Developer"].location; + NSCAssert(afterMacOsHomeDirPos != NSNotFound, @"simulator directory location is not under user's home directory: %@", cachesPath); + applicationSupportPath = [[cachesPath substringToIndex:afterMacOsHomeDirPos] stringByAppendingPathComponent:@"Library/Application Support/vcmi"].stringByResolvingSymlinksInPath; + }); + return applicationSupportPath.fileSystemRepresentation; +} +#endif + +const char *ios_bundlePath() { return NSBundle.mainBundle.bundlePath.fileSystemRepresentation; } +const char *ios_frameworksPath() { return NSBundle.mainBundle.privateFrameworksPath.fileSystemRepresentation; } const char *ios_bundleIdentifier() { return NSBundle.mainBundle.bundleIdentifier.UTF8String; } diff --git a/lib/VCMIDirs.cpp b/lib/VCMIDirs.cpp index adb33a468..45cac44d4 100644 --- a/lib/VCMIDirs.cpp +++ b/lib/VCMIDirs.cpp @@ -402,9 +402,9 @@ std::vector VCMIDirsIOS::dataPaths() const { return { #ifdef VCMI_IOS_SIM - // fixme ios - {"/Users/kambala/Library/Application Support/vcmi"}, + {ios_hostApplicationSupportPath()}, #endif + {ios_sharedDataPath()}, binaryPath(), userDataPath(), }; diff --git a/server/ios/main.mm b/server/ios/main.mm index fe0e3c8a1..c8fa6537c 100644 --- a/server/ios/main.mm +++ b/server/ios/main.mm @@ -11,11 +11,11 @@ #include "../Global.h" #include "CVCMIServer.h" - -#define SHARED_DATA_DIR @"GameData" +extern "C" { +#import "../lib/CIOSUtils.h" +} @interface ViewController : UIViewController -@property (nonatomic, copy) NSURL *sharedPathURL; @property (nonatomic, copy) NSArray *dataDirsInDocuments; @end @@ -35,29 +35,13 @@ [startServerButton.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor], ]]; - auto bundleID = NSBundle.mainBundle.bundleIdentifier; - auto lastDotPos = [bundleID rangeOfString:@"." options:NSBackwardsSearch].location; - auto groupID = [NSString stringWithFormat:@"group.%@.vcmi", [bundleID substringToIndex:lastDotPos]]; auto fm = NSFileManager.defaultManager; - self.sharedPathURL = [fm containerURLForSecurityApplicationGroupIdentifier:groupID]; - if (!self.sharedPathURL) - { - NSLog(@"shared path for group '%@' not available", groupID); + auto sharedGameDataUrl = sharedGameDataURL(); + if (!sharedGameDataUrl || [fm fileExistsAtPath:sharedGameDataUrl.path]) return; - } - - auto dirEnumerator = [fm enumeratorAtURL:self.sharedPathURL includingPropertiesForKeys:@[NSURLNameKey] options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil]; - for (NSURL *fileURL in dirEnumerator) - { - NSString *filename; - if ([fileURL getResourceValue:&filename forKey:NSURLNameKey error:nullptr] && [filename caseInsensitiveCompare:SHARED_DATA_DIR] == NSOrderedSame) { - NSLog(SHARED_DATA_DIR @" dir already exists in the shared path"); - return; - } - } auto documentsURL = [fm URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nullptr]; - dirEnumerator = [fm enumeratorAtURL:documentsURL includingPropertiesForKeys:@[NSURLNameKey] options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil]; + auto dirEnumerator = [fm enumeratorAtURL:documentsURL includingPropertiesForKeys:@[NSURLNameKey] options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil]; auto dataDirs = [NSMutableArray arrayWithCapacity:3]; for (NSURL *fileURL in dirEnumerator) { @@ -68,10 +52,7 @@ [dataDirs addObject:fileURL]; } if (dataDirs.count < 3) - { - NSLog(@"not all required dirs are present, found only: %@", dataDirs); return; - } self.dataDirsInDocuments = dataDirs; auto moveDataButton = [UIButton buttonWithType:UIButtonTypeSystem]; @@ -100,17 +81,13 @@ - (void)moveDataToSharedDir:(UIButton *)button { - button.enabled = NO; + [button removeFromSuperview]; dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ auto fm = NSFileManager.defaultManager; - auto destinationURL = [self.sharedPathURL URLByAppendingPathComponent:SHARED_DATA_DIR]; + auto destinationURL = sharedGameDataURL(); [fm createDirectoryAtURL:destinationURL withIntermediateDirectories:YES attributes:nil error:nullptr]; for (NSURL *dirURL in self.dataDirsInDocuments) [fm moveItemAtURL:dirURL toURL:[destinationURL URLByAppendingPathComponent:dirURL.lastPathComponent] error:nullptr]; - - dispatch_sync(dispatch_get_main_queue(), ^{ - [button removeFromSuperview]; - }); }); }