├── .gitignore ├── CoreSimulator ├── CoreSimulator.h ├── CoreSimulatorWrapper.h ├── CoreSimulatorWrapper.m └── Generate Headers.txt ├── LICENSE ├── README.md ├── TestTrustedCertificate ├── TestTrustedCertificate.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── TestTrustedCertificate.xcscheme └── TestTrustedCertificate │ ├── AppDelegate.swift │ ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard │ ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Info.plist │ ├── TestUrlSessionViewController.swift │ └── TestWebViewController.swift ├── iSimulatorExplorer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── iSimulatorExplorer.xccheckout └── xcshareddata │ └── xcschemes │ └── iSimulatorExplorer.xcscheme ├── iSimulatorExplorer.xcworkspace └── contents.xcworkspacedata ├── iSimulatorExplorer ├── AppDelegate.swift ├── Base.lproj │ └── MainMenu.xib ├── DCAppInfoTableCellView.swift ├── DCImportCertificateWindowController.swift ├── DCImportCertificateWindowController.xib ├── DCSimulator.swift ├── DCSimulatorAppViewController.swift ├── DCSimulatorAppViewController.xib ├── DCSimulatorExplorerController.swift ├── DCSimulatorInfoViewController.swift ├── DCSimulatorInfoViewController.xib ├── DCSimulatorManager.swift ├── DCSimulatorTrustStore.swift ├── DCSimulatorTrustStoreViewController.swift ├── DCSimulatorTrustStoreViewController.xib ├── DCXCodeSupport.swift ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── iSimulatorExplorer1.png │ │ ├── iSimulatorExplorer2-1.png │ │ ├── iSimulatorExplorer2.png │ │ ├── iSimulatorExplorer3-1.png │ │ ├── iSimulatorExplorer3.png │ │ ├── iSimulatorExplorer4.png │ │ ├── iSimulatorExplorer5.png │ │ ├── iSimulatorExplorer6-1.png │ │ ├── iSimulatorExplorer6.png │ │ └── iSimulatorExplorer7.png │ ├── Simulator.imageset │ │ ├── Contents.json │ │ ├── Simulator1.png │ │ ├── Simulator2.png │ │ └── Simulator3.png │ └── ViewDetail.imageset │ │ ├── Contents.json │ │ ├── view-32.png │ │ └── view-64.png ├── Info.plist └── iSimulatorExplorer-Bridging-Header.h ├── iSimulatorExplorerTests ├── Info.plist └── iSimulatorExplorerTests.swift └── img ├── screen1.jpg ├── screen2.jpg └── screen3.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # XCode # 2 | ######### 3 | 4 | xcuserdata 5 | *.xccheckout 6 | 7 | # Packages # 8 | ############ 9 | # it's better to unpack these files and commit the raw source 10 | # git has its own built in compression methods 11 | *.7z 12 | *.dmg 13 | *.gz 14 | *.iso 15 | *.jar 16 | *.rar 17 | *.tar 18 | *.zip 19 | 20 | # OS generated files # 21 | ###################### 22 | .DS_Store 23 | .DS_Store? 24 | ._* 25 | .Spotlight-V100 26 | .Trashes 27 | 28 | # Project specific 29 | ################## 30 | 31 | temp/ 32 | -------------------------------------------------------------------------------- /CoreSimulator/CoreSimulatorWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreSimulatorHelper.h 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 18/09/15. 6 | // Copyright © 2015 Daniel Cerutti. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CoreSimulator.h" 11 | 12 | @interface CoreSimulatorHelper : NSObject 13 | 14 | + (BOOL)loadAllPlatformsReturningError:(NSError **)error; 15 | 16 | @end 17 | 18 | //@class SimDevice; 19 | 20 | 21 | @interface SimServiceContextWrapper : NSObject 22 | 23 | + (SimServiceContext *)sharedServiceContextForDeveloperDir:(NSString *)developerDir simServiceContextClass:(Class)serviceClass error:(NSError **)error; 24 | 25 | 26 | @end 27 | 28 | 29 | @interface SimDeviceWrapper : NSObject 30 | 31 | + (instancetype)simDeviceWrapper:(id)simDevice; 32 | 33 | //@property(retain, nonatomic) NSDistantObject *simBridgeDistantObject; 34 | //@property(retain, nonatomic) NSMachPort *simBridgePort; 35 | //@property(retain, nonatomic) NSMachPort *hostSupportPort; 36 | //@property(retain) NSMachPort *deathTriggerPort; 37 | //@property(retain) NSObject *stateVariableQueue; 38 | //@property(retain) NSMutableDictionary *registeredServices; 39 | //@property(retain) NSObject *bootstrapQueue; 40 | //@property(retain) SimDeviceNotificationManager *notificationManager; 41 | //@property(copy) NSString *setPath; 42 | //@property(retain) SimServiceConnectionManager *connectionManager; 43 | //@property(readonly) SimDeviceSet *deviceSet; 44 | //@property(copy) NSUUID *UDID; 45 | //@property(retain) SimRuntime *runtime; 46 | //@property(retain) SimDeviceType *deviceType; 47 | // 48 | //- (BOOL)isAvailableWithError:(NSError **)error; 49 | @property(readonly) BOOL available; 50 | //- (BOOL)triggerCloudSyncWithError:(NSError **)error; 51 | //- (void)triggerCloudSyncWithCompletionHandler:(CDUnknownBlockType)arg1; 52 | //- (BOOL)postDarwinNotification:(id)arg1 error:(id *)arg2; 53 | // 54 | //- (pid_t)launchApplicationWithID:(NSString *)appId options:(NSDictionary *)options error:(NSError **)error; 55 | //- (void)launchApplicationAsyncWithID:(NSString *)appId options:(NSDictionary *)options completionHandler:(CDUnknownBlockType)arg3; 56 | - (NSDictionary *)installedAppsWithError:(NSError **)error; 57 | //- (BOOL)applicationIsInstalled:(NSString *)appId type:(id *)arg2 error:(NSError **)error; 58 | - (BOOL)uninstallApplication:(NSString *)appId withOptions:(id)arg2 error:(NSError **)error; 59 | - (BOOL)installApplication:(NSURL *)appUrl withOptions:(NSDictionary *)options error:(NSError **)error; 60 | // 61 | //- (BOOL)setKeyboardLanguage:(NSString *)lang error:(NSError **)error; 62 | //- (BOOL)addPhoto:(NSURL *)url error:(NSError **)error; 63 | //- (BOOL)openURL:(NSURL *)url error:(NSError **)error; 64 | // 65 | //- (void)simBridgeSync:(CDUnknownBlockType)arg1; 66 | //- (void)simBridgeAsync:(CDUnknownBlockType)arg1; 67 | //- (void)simBridgeCommon:(CDUnknownBlockType)arg1; 68 | //- (long long)compare:(id)arg1; 69 | //- (id)newDeviceNotification; 70 | //- (id)createXPCNotification:(const char *)arg1; 71 | //- (id)createXPCRequest:(const char *)arg1; 72 | //- (void)handleXPCRequestSpawn:(id)arg1 peer:(id)arg2; 73 | //- (void)handleXPCRequestGetenv:(id)arg1 peer:(id)arg2; 74 | //- (void)handleXPCRequestLookup:(id)arg1 peer:(id)arg2; 75 | //- (void)handleXPCRequestRegister:(id)arg1 peer:(id)arg2; 76 | //- (void)handleXPCRequestRestore:(id)arg1 peer:(id)arg2; 77 | //- (void)handleXPCRequestUpdateUIWindow:(id)arg1 peer:(id)arg2; 78 | //- (void)handleXPCRequestErase:(id)arg1 peer:(id)arg2; 79 | //- (void)handleXPCRequestUpgrade:(id)arg1 peer:(id)arg2; 80 | //- (void)handleXPCRequestShutdown:(id)arg1 peer:(id)arg2; 81 | //- (void)handleXPCRequestBoot:(id)arg1 peer:(id)arg2; 82 | //- (void)handleXPCRequestRename:(id)arg1 peer:(id)arg2; 83 | //- (void)handleXPCRequest:(id)arg1 peer:(id)arg2; 84 | //- (void)handleXPCNotificationDeviceUIWindowPropertiesChanged:(id)arg1; 85 | //- (void)handleXPCNotificationDeviceRenamed:(id)arg1; 86 | //- (void)handleXPCNotificationDeviceStateChanged:(id)arg1; 87 | //- (void)handleXPCNotification:(id)arg1; 88 | 89 | //@property(copy) NSDictionary *uiWindowProperties; 90 | //- (void)setName:(NSString *)name; 91 | @property(readonly, copy) NSString *name; 92 | //- (void)setState:(SimDeviceState)state; 93 | @property(readonly) SimDeviceState state; 94 | - (NSString*)stateString; 95 | 96 | //- (void)simulateMemoryWarning; 97 | //- (id)memoryWarningFilePath; 98 | //@property(readonly, copy) NSString *logPath; 99 | //- (NSString *)dataPath; 100 | //- (NSString *)devicePath; 101 | //- (NSDictionary *)environment; 102 | 103 | //- (int)_spawnFromSelfWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 104 | //- (int)_spawnFromLaunchdWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 105 | //- (int)spawnWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 106 | //- (void)spawnAsyncWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 completionHandler:(CDUnknownBlockType)arg4; 107 | //- (BOOL)registerPort:(unsigned int)arg1 service:(id)arg2 error:(id *)arg3; 108 | //- (unsigned int)lookup:(id)arg1 error:(id *)arg2; 109 | //- (unsigned int)_lookup:(id)arg1 error:(id *)arg2; 110 | 111 | //- (id)getenv:(id)arg1 error:(id *)arg2; 112 | 113 | //- (BOOL)restoreContentsAndSettingsFromDevice:(id)arg1 error:(id *)arg2; 114 | //- (void)restoreContentsAndSettingsAsyncFromDevice:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 115 | 116 | //- (BOOL)updateUIWindowProperties:(id)arg1 error:(id *)arg2; 117 | //- (void)updateAsyncUIWindowProperties:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 118 | //- (void)_sendUIWindowPropertiesToDevice; 119 | 120 | //- (BOOL)eraseContentsAndSettingsWithError:(id *)arg1; 121 | //- (void)eraseContentsAndSettingsAsyncWithCompletionHandler:(CDUnknownBlockType)arg1; 122 | 123 | //- (BOOL)upgradeToRuntime:(id)arg1 error:(id *)arg2; 124 | //- (void)upgradeAsyncToRuntime:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 125 | 126 | //- (BOOL)rename:(id)arg1 error:(id *)arg2; 127 | //- (void)renameAsync:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 128 | 129 | //- (BOOL)shutdownWithError:(NSError **)error; 130 | //- (BOOL)_shutdownWithError:(id *)arg1; 131 | - (void)shutdownAsyncWithCompletionHandler:(void (^)(NSError *error))completionBlock; 132 | 133 | //- (BOOL)bootWithOptions:(NSDictionary *)options error:(NSError **)error; 134 | - (void)bootAsyncWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionBlock; 135 | 136 | //- (void)launchdDeathHandlerWithDeathPort:(id)arg1; 137 | //- (BOOL)startLaunchdWithDeathPort:(id)arg1 deathHandler:(CDUnknownBlockType)arg2 error:(id *)arg3; 138 | //- (void)registerPortsWithLaunchd; 139 | //@property(readonly) NSArray *launchDaemonsPaths; 140 | //- (BOOL)removeLaunchdJobWithError:(id *)arg1; 141 | //- (BOOL)createLaunchdJobWithError:(id *)arg1 extraEnvironment:(id)arg2 disabledJobs:(id)arg3; 142 | //- (BOOL)clearTmpWithError:(id *)arg1; 143 | //- (BOOL)ensureLogPathsWithError:(id *)arg1; 144 | //- (BOOL)supportsFeature:(id)arg1; 145 | //@property(readonly, copy) NSString *launchdJobName; 146 | //- (void)saveToDisk; 147 | //- (id)saveStateDict; 148 | //- (void)validateAndFixState; 149 | //@property(readonly, copy) NSString *descriptiveName; 150 | //- (NSString *)description; 151 | 152 | //- (id)initDevice:(NSString *)name 153 | // UDID:(NSUUID *)udid 154 | // deviceType:(SimDeviceType *)deviceType 155 | // runtime:(SimRuntime *)runtime 156 | // state:(unsigned long long)state 157 | //connectionManager:(SimServiceConnectionManager *)connectionManager 158 | // setPath:(NSString *)path; 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /CoreSimulator/CoreSimulatorWrapper.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreSimulatorHelper.m 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 18/09/15. 6 | // Copyright © 2015 Daniel Cerutti. All rights reserved. 7 | // 8 | 9 | #import "CoreSimulatorWrapper.h" 10 | //#import "CoreSimulator.h" 11 | 12 | @implementation CoreSimulatorHelper 13 | 14 | + (BOOL)loadAllPlatformsReturningError:(NSError **)error; 15 | { 16 | NSString *nameOfClass = @"DVTPlatform"; 17 | Class DVTPlatformClass = NSClassFromString(nameOfClass); 18 | if (DVTPlatformClass == nil) 19 | { 20 | NSString* errorDescription = [NSString stringWithFormat:@"Failed to find class %@ at runtime.", nameOfClass]; 21 | *error = [NSError errorWithDomain:@"iSimulatorExplorer" code:1 userInfo:@{NSLocalizedDescriptionKey : errorDescription}]; 22 | return FALSE; 23 | } 24 | 25 | return [DVTPlatformClass loadAllPlatformsReturningError:error]; 26 | 27 | } 28 | 29 | @end 30 | 31 | 32 | @implementation SimServiceContextWrapper 33 | 34 | + (SimServiceContext *)sharedServiceContextForDeveloperDir:(NSString *)developerDir simServiceContextClass:(Class)serviceClass error:(NSError **)error; 35 | { 36 | return [serviceClass sharedServiceContextForDeveloperDir:developerDir error:error]; 37 | } 38 | 39 | @end 40 | 41 | @interface SimDeviceWrapper() 42 | 43 | @property (nonatomic) SimDevice* simDevice; 44 | 45 | @end 46 | 47 | 48 | 49 | @implementation SimDeviceWrapper 50 | 51 | + (instancetype)simDeviceWrapper:(SimDevice *)simDevice; 52 | { 53 | return [[SimDeviceWrapper alloc] initWithSimDevice:simDevice]; 54 | } 55 | 56 | -(instancetype)initWithSimDevice:(SimDevice *)simDevice; 57 | { 58 | self = [super init]; 59 | if (self != nil) 60 | { 61 | self.simDevice = simDevice; 62 | } 63 | return self; 64 | } 65 | 66 | 67 | //@property(retain, nonatomic) NSDistantObject *simBridgeDistantObject; 68 | //@property(retain, nonatomic) NSMachPort *simBridgePort; 69 | //@property(retain, nonatomic) NSMachPort *hostSupportPort; 70 | //@property(retain) NSMachPort *deathTriggerPort; 71 | //@property(retain) NSObject *stateVariableQueue; 72 | //@property(retain) NSMutableDictionary *registeredServices; 73 | //@property(retain) NSObject *bootstrapQueue; 74 | //@property(retain) SimDeviceNotificationManager *notificationManager; 75 | //@property(copy) NSString *setPath; 76 | //@property(retain) SimServiceConnectionManager *connectionManager; 77 | //@property(readonly) SimDeviceSet *deviceSet; 78 | //@property(copy) NSUUID *UDID; 79 | //@property(retain) SimRuntime *runtime; 80 | //@property(retain) SimDeviceType *deviceType; 81 | 82 | //- (BOOL)isAvailableWithError:(NSError **)error; 83 | 84 | -(BOOL)available; 85 | { 86 | return self.simDevice.available; 87 | } 88 | 89 | //- (BOOL)triggerCloudSyncWithError:(NSError **)error; 90 | //- (void)triggerCloudSyncWithCompletionHandler:(CDUnknownBlockType)arg1; 91 | //- (BOOL)postDarwinNotification:(id)arg1 error:(id *)arg2; 92 | // 93 | //- (pid_t)launchApplicationWithID:(NSString *)appId options:(NSDictionary *)options error:(NSError **)error; 94 | //- (void)launchApplicationAsyncWithID:(NSString *)appId options:(NSDictionary *)options completionHandler:(CDUnknownBlockType)arg3; 95 | - (NSDictionary *)installedAppsWithError:(NSError **)error; 96 | { 97 | return [self.simDevice installedAppsWithError:error]; 98 | } 99 | 100 | //- (BOOL)applicationIsInstalled:(NSString *)appId type:(id *)arg2 error:(NSError **)error; 101 | 102 | - (BOOL)uninstallApplication:(NSString *)appId withOptions:(id)arg2 error:(NSError **)error; 103 | { 104 | return [self.simDevice uninstallApplication:appId withOptions:arg2 error:error]; 105 | } 106 | 107 | - (BOOL)installApplication:(NSURL *)appUrl withOptions:(NSDictionary *)options error:(NSError **)error; 108 | { 109 | return [self.simDevice installApplication:appUrl withOptions:options error:error]; 110 | } 111 | 112 | // 113 | //- (BOOL)setKeyboardLanguage:(NSString *)lang error:(NSError **)error; 114 | //- (BOOL)addPhoto:(NSURL *)url error:(NSError **)error; 115 | //- (BOOL)openURL:(NSURL *)url error:(NSError **)error; 116 | // 117 | //- (void)simBridgeSync:(CDUnknownBlockType)arg1; 118 | //- (void)simBridgeAsync:(CDUnknownBlockType)arg1; 119 | //- (void)simBridgeCommon:(CDUnknownBlockType)arg1; 120 | //- (long long)compare:(id)arg1; 121 | //- (id)newDeviceNotification; 122 | //- (id)createXPCNotification:(const char *)arg1; 123 | //- (id)createXPCRequest:(const char *)arg1; 124 | //- (void)handleXPCRequestSpawn:(id)arg1 peer:(id)arg2; 125 | //- (void)handleXPCRequestGetenv:(id)arg1 peer:(id)arg2; 126 | //- (void)handleXPCRequestLookup:(id)arg1 peer:(id)arg2; 127 | //- (void)handleXPCRequestRegister:(id)arg1 peer:(id)arg2; 128 | //- (void)handleXPCRequestRestore:(id)arg1 peer:(id)arg2; 129 | //- (void)handleXPCRequestUpdateUIWindow:(id)arg1 peer:(id)arg2; 130 | //- (void)handleXPCRequestErase:(id)arg1 peer:(id)arg2; 131 | //- (void)handleXPCRequestUpgrade:(id)arg1 peer:(id)arg2; 132 | //- (void)handleXPCRequestShutdown:(id)arg1 peer:(id)arg2; 133 | //- (void)handleXPCRequestBoot:(id)arg1 peer:(id)arg2; 134 | //- (void)handleXPCRequestRename:(id)arg1 peer:(id)arg2; 135 | //- (void)handleXPCRequest:(id)arg1 peer:(id)arg2; 136 | //- (void)handleXPCNotificationDeviceUIWindowPropertiesChanged:(id)arg1; 137 | //- (void)handleXPCNotificationDeviceRenamed:(id)arg1; 138 | //- (void)handleXPCNotificationDeviceStateChanged:(id)arg1; 139 | //- (void)handleXPCNotification:(id)arg1; 140 | // 141 | //@property(copy) NSDictionary *uiWindowProperties; 142 | //- (void)setName:(NSString *)name; 143 | 144 | -(NSString *)name; 145 | { 146 | return self.simDevice.name; 147 | } 148 | 149 | //- (void)setState:(SimDeviceState)state; 150 | 151 | -(SimDeviceState)state; 152 | { 153 | return self.simDevice.state; 154 | } 155 | 156 | - (NSString*)stateString; 157 | { 158 | return self.simDevice.stateString; 159 | } 160 | 161 | //- (void)simulateMemoryWarning; 162 | //- (id)memoryWarningFilePath; 163 | //@property(readonly, copy) NSString *logPath; 164 | //- (NSString *)dataPath; 165 | //- (NSString *)devicePath; 166 | //- (NSDictionary *)environment; 167 | 168 | //- (int)_spawnFromSelfWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 169 | //- (int)_spawnFromLaunchdWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 170 | //- (int)spawnWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 error:(id *)arg4; 171 | //- (void)spawnAsyncWithPath:(id)arg1 options:(id)arg2 terminationHandler:(CDUnknownBlockType)arg3 completionHandler:(CDUnknownBlockType)arg4; 172 | //- (BOOL)registerPort:(unsigned int)arg1 service:(id)arg2 error:(id *)arg3; 173 | //- (unsigned int)lookup:(id)arg1 error:(id *)arg2; 174 | //- (unsigned int)_lookup:(id)arg1 error:(id *)arg2; 175 | 176 | //- (id)getenv:(id)arg1 error:(id *)arg2; 177 | 178 | //- (BOOL)restoreContentsAndSettingsFromDevice:(id)arg1 error:(id *)arg2; 179 | //- (void)restoreContentsAndSettingsAsyncFromDevice:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 180 | 181 | //- (BOOL)updateUIWindowProperties:(id)arg1 error:(id *)arg2; 182 | //- (void)updateAsyncUIWindowProperties:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 183 | //- (void)_sendUIWindowPropertiesToDevice; 184 | 185 | //- (BOOL)eraseContentsAndSettingsWithError:(id *)arg1; 186 | //- (void)eraseContentsAndSettingsAsyncWithCompletionHandler:(CDUnknownBlockType)arg1; 187 | 188 | //- (BOOL)upgradeToRuntime:(id)arg1 error:(id *)arg2; 189 | //- (void)upgradeAsyncToRuntime:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 190 | 191 | //- (BOOL)rename:(id)arg1 error:(id *)arg2; 192 | //- (void)renameAsync:(id)arg1 completionHandler:(CDUnknownBlockType)arg2; 193 | 194 | //- (BOOL)shutdownWithError:(NSError **)error; 195 | //- (BOOL)_shutdownWithError:(id *)arg1; 196 | - (void)shutdownAsyncWithCompletionHandler:(void (^)(NSError *error))completionBlock; 197 | { 198 | [self.simDevice shutdownAsyncWithCompletionHandler:completionBlock]; 199 | } 200 | 201 | //- (BOOL)bootWithOptions:(NSDictionary *)options error:(NSError **)error; 202 | - (void)bootAsyncWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionBlock; 203 | { 204 | [self.simDevice bootAsyncWithOptions:options completionHandler:completionBlock]; 205 | } 206 | 207 | //- (void)launchdDeathHandlerWithDeathPort:(id)arg1; 208 | //- (BOOL)startLaunchdWithDeathPort:(id)arg1 deathHandler:(CDUnknownBlockType)arg2 error:(id *)arg3; 209 | //- (void)registerPortsWithLaunchd; 210 | //@property(readonly) NSArray *launchDaemonsPaths; 211 | //- (BOOL)removeLaunchdJobWithError:(id *)arg1; 212 | //- (BOOL)createLaunchdJobWithError:(id *)arg1 extraEnvironment:(id)arg2 disabledJobs:(id)arg3; 213 | //- (BOOL)clearTmpWithError:(id *)arg1; 214 | //- (BOOL)ensureLogPathsWithError:(id *)arg1; 215 | //- (BOOL)supportsFeature:(id)arg1; 216 | //@property(readonly, copy) NSString *launchdJobName; 217 | //- (void)saveToDisk; 218 | //- (id)saveStateDict; 219 | //- (void)validateAndFixState; 220 | //@property(readonly, copy) NSString *descriptiveName; 221 | //- (NSString *)description; 222 | 223 | //- (id)initDevice:(NSString *)name 224 | // UDID:(NSUUID *)udid 225 | // deviceType:(SimDeviceType *)deviceType 226 | // runtime:(SimRuntime *)runtime 227 | // state:(unsigned long long)state 228 | //connectionManager:(SimServiceConnectionManager *)connectionManager 229 | // setPath:(NSString *)path; 230 | // 231 | 232 | 233 | @end 234 | -------------------------------------------------------------------------------- /CoreSimulator/Generate Headers.txt: -------------------------------------------------------------------------------- 1 | With XCode 6 2 | ============= 3 | 4 | class-dump -CSim /Applications/Xcode.app/Contents/Developer/Library/PrivateFrameworks/CoreSimulator.framework > CoreSimulator.h 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Daniel Cerutti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### What is iSimulatorExplorer? ### 2 | 3 | iSimulatorExplorer is a simple OS X application written in Swift to browse the available iOS Simulators on your system. It provides the following functions: 4 | 5 | * View informations and status on each available iOS simulator. 6 | 7 | * Launch the iOS simulator 8 | 9 | * Quickly open applications program and data folder in Finder. 10 | 11 | * Add/remove/import/export CA certificate on iOS Simulators. This make it easy to test applications connecting to development server with self-signed certificates or using a man-in-the-middle proxy like mitmproxy where you need to install the proxy CA in the simulator. 12 | 13 | * Install/Uninstall Apps in iOS simulator. 14 | 15 | ![iSimulatorExplorer screen](img/screen1.jpg) 16 | 17 | ![iSimulatorExplorer screen](img/screen2.jpg) 18 | 19 | ![iSimulatorExplorer screen](img/screen3.jpg) 20 | 21 | ### System requirements ### 22 | 23 | * OS X 10.10 or above 24 | * Xcode 8.0 or above 25 | 26 | ### Notes on CA certificates in iOS simulator ### 27 | 28 | * The trusted certificate management in iOS simulator is based on the [ADVTrustStore project](https://github.com/ADVTOOLS/ADVTrustStore) I have written 2 years ago. 29 | 30 | * To make it easy to test certificate imported with this tool, a sample iOS application is provided in this project: TestTrustedCertificate. It consist of a simple WebView to test a SSL connection to a server. 31 | 32 | ### Copyright and license ### 33 | 34 | Copyright (c) 2015-2016, Daniel Cerutti. Licensed under the MIT license. See LICENSE file in this project. 35 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 654510AE1BF5266500D494AE /* TestUrlSessionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654510AD1BF5266500D494AE /* TestUrlSessionViewController.swift */; }; 11 | 6590379019E9CA0400C4C366 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6590378F19E9CA0400C4C366 /* AppDelegate.swift */; }; 12 | 6590379219E9CA0400C4C366 /* TestWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6590379119E9CA0400C4C366 /* TestWebViewController.swift */; }; 13 | 6590379519E9CA0400C4C366 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6590379319E9CA0400C4C366 /* Main.storyboard */; }; 14 | 6590379719E9CA0400C4C366 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6590379619E9CA0400C4C366 /* Images.xcassets */; }; 15 | 6590379A19E9CA0400C4C366 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6590379819E9CA0400C4C366 /* LaunchScreen.xib */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 654510AD1BF5266500D494AE /* TestUrlSessionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUrlSessionViewController.swift; sourceTree = ""; }; 20 | 6590378A19E9CA0400C4C366 /* TestTrustedCertificate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestTrustedCertificate.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 6590378E19E9CA0400C4C366 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 6590378F19E9CA0400C4C366 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | 6590379119E9CA0400C4C366 /* TestWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestWebViewController.swift; sourceTree = ""; }; 24 | 6590379419E9CA0400C4C366 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 25 | 6590379619E9CA0400C4C366 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 26 | 6590379919E9CA0400C4C366 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 6590378719E9CA0400C4C366 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | 6590378119E9CA0400C4C366 = { 41 | isa = PBXGroup; 42 | children = ( 43 | 6590378C19E9CA0400C4C366 /* TestTrustedCertificate */, 44 | 6590378B19E9CA0400C4C366 /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 6590378B19E9CA0400C4C366 /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 6590378A19E9CA0400C4C366 /* TestTrustedCertificate.app */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 6590378C19E9CA0400C4C366 /* TestTrustedCertificate */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 6590378F19E9CA0400C4C366 /* AppDelegate.swift */, 60 | 6590379119E9CA0400C4C366 /* TestWebViewController.swift */, 61 | 6590379319E9CA0400C4C366 /* Main.storyboard */, 62 | 6590379619E9CA0400C4C366 /* Images.xcassets */, 63 | 6590379819E9CA0400C4C366 /* LaunchScreen.xib */, 64 | 6590378D19E9CA0400C4C366 /* Supporting Files */, 65 | 654510AD1BF5266500D494AE /* TestUrlSessionViewController.swift */, 66 | ); 67 | path = TestTrustedCertificate; 68 | sourceTree = ""; 69 | }; 70 | 6590378D19E9CA0400C4C366 /* Supporting Files */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 6590378E19E9CA0400C4C366 /* Info.plist */, 74 | ); 75 | name = "Supporting Files"; 76 | sourceTree = ""; 77 | }; 78 | /* End PBXGroup section */ 79 | 80 | /* Begin PBXNativeTarget section */ 81 | 6590378919E9CA0400C4C366 /* TestTrustedCertificate */ = { 82 | isa = PBXNativeTarget; 83 | buildConfigurationList = 659037A919E9CA0400C4C366 /* Build configuration list for PBXNativeTarget "TestTrustedCertificate" */; 84 | buildPhases = ( 85 | 6590378619E9CA0400C4C366 /* Sources */, 86 | 6590378719E9CA0400C4C366 /* Frameworks */, 87 | 6590378819E9CA0400C4C366 /* Resources */, 88 | ); 89 | buildRules = ( 90 | ); 91 | dependencies = ( 92 | ); 93 | name = TestTrustedCertificate; 94 | productName = TestTrustedCertificate; 95 | productReference = 6590378A19E9CA0400C4C366 /* TestTrustedCertificate.app */; 96 | productType = "com.apple.product-type.application"; 97 | }; 98 | /* End PBXNativeTarget section */ 99 | 100 | /* Begin PBXProject section */ 101 | 6590378219E9CA0400C4C366 /* Project object */ = { 102 | isa = PBXProject; 103 | attributes = { 104 | LastSwiftUpdateCheck = 0700; 105 | LastUpgradeCheck = 0800; 106 | ORGANIZATIONNAME = "Cerutti Software Design"; 107 | TargetAttributes = { 108 | 6590378919E9CA0400C4C366 = { 109 | CreatedOnToolsVersion = 6.1; 110 | LastSwiftMigration = 0800; 111 | }; 112 | }; 113 | }; 114 | buildConfigurationList = 6590378519E9CA0400C4C366 /* Build configuration list for PBXProject "TestTrustedCertificate" */; 115 | compatibilityVersion = "Xcode 3.2"; 116 | developmentRegion = English; 117 | hasScannedForEncodings = 0; 118 | knownRegions = ( 119 | en, 120 | Base, 121 | ); 122 | mainGroup = 6590378119E9CA0400C4C366; 123 | productRefGroup = 6590378B19E9CA0400C4C366 /* Products */; 124 | projectDirPath = ""; 125 | projectRoot = ""; 126 | targets = ( 127 | 6590378919E9CA0400C4C366 /* TestTrustedCertificate */, 128 | ); 129 | }; 130 | /* End PBXProject section */ 131 | 132 | /* Begin PBXResourcesBuildPhase section */ 133 | 6590378819E9CA0400C4C366 /* Resources */ = { 134 | isa = PBXResourcesBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | 6590379519E9CA0400C4C366 /* Main.storyboard in Resources */, 138 | 6590379A19E9CA0400C4C366 /* LaunchScreen.xib in Resources */, 139 | 6590379719E9CA0400C4C366 /* Images.xcassets in Resources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXResourcesBuildPhase section */ 144 | 145 | /* Begin PBXSourcesBuildPhase section */ 146 | 6590378619E9CA0400C4C366 /* Sources */ = { 147 | isa = PBXSourcesBuildPhase; 148 | buildActionMask = 2147483647; 149 | files = ( 150 | 6590379219E9CA0400C4C366 /* TestWebViewController.swift in Sources */, 151 | 6590379019E9CA0400C4C366 /* AppDelegate.swift in Sources */, 152 | 654510AE1BF5266500D494AE /* TestUrlSessionViewController.swift in Sources */, 153 | ); 154 | runOnlyForDeploymentPostprocessing = 0; 155 | }; 156 | /* End PBXSourcesBuildPhase section */ 157 | 158 | /* Begin PBXVariantGroup section */ 159 | 6590379319E9CA0400C4C366 /* Main.storyboard */ = { 160 | isa = PBXVariantGroup; 161 | children = ( 162 | 6590379419E9CA0400C4C366 /* Base */, 163 | ); 164 | name = Main.storyboard; 165 | sourceTree = ""; 166 | }; 167 | 6590379819E9CA0400C4C366 /* LaunchScreen.xib */ = { 168 | isa = PBXVariantGroup; 169 | children = ( 170 | 6590379919E9CA0400C4C366 /* Base */, 171 | ); 172 | name = LaunchScreen.xib; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXVariantGroup section */ 176 | 177 | /* Begin XCBuildConfiguration section */ 178 | 659037A719E9CA0400C4C366 /* Debug */ = { 179 | isa = XCBuildConfiguration; 180 | buildSettings = { 181 | ALWAYS_SEARCH_USER_PATHS = NO; 182 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 183 | CLANG_CXX_LIBRARY = "libc++"; 184 | CLANG_ENABLE_MODULES = YES; 185 | CLANG_ENABLE_OBJC_ARC = YES; 186 | CLANG_WARN_BOOL_CONVERSION = YES; 187 | CLANG_WARN_CONSTANT_CONVERSION = YES; 188 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 189 | CLANG_WARN_EMPTY_BODY = YES; 190 | CLANG_WARN_ENUM_CONVERSION = YES; 191 | CLANG_WARN_INFINITE_RECURSION = YES; 192 | CLANG_WARN_INT_CONVERSION = YES; 193 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 194 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 195 | CLANG_WARN_UNREACHABLE_CODE = YES; 196 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 197 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 198 | COPY_PHASE_STRIP = NO; 199 | ENABLE_STRICT_OBJC_MSGSEND = YES; 200 | ENABLE_TESTABILITY = YES; 201 | GCC_C_LANGUAGE_STANDARD = gnu99; 202 | GCC_DYNAMIC_NO_PIC = NO; 203 | GCC_NO_COMMON_BLOCKS = YES; 204 | GCC_OPTIMIZATION_LEVEL = 0; 205 | GCC_PREPROCESSOR_DEFINITIONS = ( 206 | "DEBUG=1", 207 | "$(inherited)", 208 | ); 209 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 212 | GCC_WARN_UNDECLARED_SELECTOR = YES; 213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 214 | GCC_WARN_UNUSED_FUNCTION = YES; 215 | GCC_WARN_UNUSED_VARIABLE = YES; 216 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 217 | MTL_ENABLE_DEBUG_INFO = YES; 218 | ONLY_ACTIVE_ARCH = YES; 219 | SDKROOT = iphoneos; 220 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 221 | TARGETED_DEVICE_FAMILY = "1,2"; 222 | }; 223 | name = Debug; 224 | }; 225 | 659037A819E9CA0400C4C366 /* Release */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_UNREACHABLE_CODE = YES; 243 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 244 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 245 | COPY_PHASE_STRIP = YES; 246 | ENABLE_NS_ASSERTIONS = NO; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | GCC_C_LANGUAGE_STANDARD = gnu99; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 251 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 252 | GCC_WARN_UNDECLARED_SELECTOR = YES; 253 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 254 | GCC_WARN_UNUSED_FUNCTION = YES; 255 | GCC_WARN_UNUSED_VARIABLE = YES; 256 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 257 | MTL_ENABLE_DEBUG_INFO = NO; 258 | SDKROOT = iphoneos; 259 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 260 | TARGETED_DEVICE_FAMILY = "1,2"; 261 | VALIDATE_PRODUCT = YES; 262 | }; 263 | name = Release; 264 | }; 265 | 659037AA19E9CA0400C4C366 /* Debug */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 269 | INFOPLIST_FILE = TestTrustedCertificate/Info.plist; 270 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 271 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ceruttisoftware.$(PRODUCT_NAME:rfc1034identifier)"; 272 | PRODUCT_NAME = "$(TARGET_NAME)"; 273 | SWIFT_VERSION = 3.0; 274 | }; 275 | name = Debug; 276 | }; 277 | 659037AB19E9CA0400C4C366 /* Release */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 281 | INFOPLIST_FILE = TestTrustedCertificate/Info.plist; 282 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 283 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ceruttisoftware.$(PRODUCT_NAME:rfc1034identifier)"; 284 | PRODUCT_NAME = "$(TARGET_NAME)"; 285 | SWIFT_VERSION = 3.0; 286 | }; 287 | name = Release; 288 | }; 289 | /* End XCBuildConfiguration section */ 290 | 291 | /* Begin XCConfigurationList section */ 292 | 6590378519E9CA0400C4C366 /* Build configuration list for PBXProject "TestTrustedCertificate" */ = { 293 | isa = XCConfigurationList; 294 | buildConfigurations = ( 295 | 659037A719E9CA0400C4C366 /* Debug */, 296 | 659037A819E9CA0400C4C366 /* Release */, 297 | ); 298 | defaultConfigurationIsVisible = 0; 299 | defaultConfigurationName = Release; 300 | }; 301 | 659037A919E9CA0400C4C366 /* Build configuration list for PBXNativeTarget "TestTrustedCertificate" */ = { 302 | isa = XCConfigurationList; 303 | buildConfigurations = ( 304 | 659037AA19E9CA0400C4C366 /* Debug */, 305 | 659037AB19E9CA0400C4C366 /* Release */, 306 | ); 307 | defaultConfigurationIsVisible = 0; 308 | defaultConfigurationName = Release; 309 | }; 310 | /* End XCConfigurationList section */ 311 | }; 312 | rootObject = 6590378219E9CA0400C4C366 /* Project object */; 313 | } 314 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate.xcodeproj/xcshareddata/xcschemes/TestTrustedCertificate.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TestTrustedCertificate 4 | // 5 | // Created by Daniel Cerutti on 11/10/14. 6 | // Copyright (c) 2014-2016 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import UIKit 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/TestUrlSessionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestUrlSessionViewController.swift 3 | // TestTrustedCertificate 4 | // 5 | // Created by Daniel Cerutti on 12/11/15. 6 | // Copyright © 2014-2016 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import UIKit 11 | 12 | class TestUrlSessionViewController: UIViewController, UIWebViewDelegate { 13 | 14 | @IBOutlet weak var urlTextField: UITextField! 15 | @IBOutlet weak var webView: UIWebView! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view, typically from a nib. 20 | webView.delegate = self 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | 27 | } 28 | 29 | @IBAction func openUrlButton(sender: AnyObject) { 30 | if let text = urlTextField.text { 31 | urlTextField.resignFirstResponder() 32 | if let url = URL(string: text){ 33 | 34 | let session = URLSession.init(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: OperationQueue.main) 35 | 36 | session.dataTask(with: url, completionHandler: { (data : Data?, response : URLResponse?, error : Error?) -> Void in 37 | if error != nil { 38 | let text = "

\(error!.localizedDescription)

\(error!)

" 39 | self.webView.loadHTMLString (text, baseURL:URL(string:"localhost")) 40 | } 41 | else 42 | { 43 | let mimeType = (response?.mimeType != nil) ? response!.mimeType! : "text/html" 44 | let encoding = (response?.textEncodingName != nil) ? response!.textEncodingName! : "utf-8" 45 | 46 | self.webView.load(data!, mimeType: mimeType, textEncodingName: encoding, baseURL: url) 47 | } 48 | }).resume() 49 | } 50 | } 51 | } 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /TestTrustedCertificate/TestTrustedCertificate/TestWebViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TestTrustedCertificate 4 | // 5 | // Created by Daniel Cerutti on 11/10/14. 6 | // Copyright (c) 2014-2016 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import UIKit 11 | 12 | class TestWebViewController: UIViewController, UIWebViewDelegate { 13 | 14 | @IBOutlet weak var urlTextField: UITextField! 15 | @IBOutlet weak var webView: UIWebView! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view, typically from a nib. 20 | webView.delegate = self 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | 27 | } 28 | 29 | @IBAction func openUrlButton(sender: AnyObject) { 30 | if let text = urlTextField.text { 31 | urlTextField.resignFirstResponder() 32 | if let url = URL(string: text){ 33 | let request = URLRequest(url: url) 34 | webView.loadRequest(request) 35 | } 36 | } 37 | } 38 | 39 | func webView(_ webView: UIWebView, didFailLoadWithError error: Error) { 40 | let text = "

\(error.localizedDescription)" 41 | webView.loadHTMLString (text, baseURL:URL(string:"localhost")) 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /iSimulatorExplorer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iSimulatorExplorer.xcodeproj/project.xcworkspace/xcshareddata/iSimulatorExplorer.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 08E698DC-A500-424F-883F-96E49A035022 9 | IDESourceControlProjectName 10 | iSimulatorExplorer 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C778EF317482FD0B7EE36DDCACE5E7B21310F22B 14 | bitbucket1:dcerutti/isimulatorexplorer.git 15 | 16 | IDESourceControlProjectPath 17 | iSimulatorExplorer.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C778EF317482FD0B7EE36DDCACE5E7B21310F22B 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | bitbucket1:dcerutti/isimulatorexplorer.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C778EF317482FD0B7EE36DDCACE5E7B21310F22B 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C778EF317482FD0B7EE36DDCACE5E7B21310F22B 36 | IDESourceControlWCCName 37 | iSimulatorExplorer 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /iSimulatorExplorer.xcodeproj/xcshareddata/xcschemes/iSimulatorExplorer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /iSimulatorExplorer.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /iSimulatorExplorer/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 30.07.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | @NSApplicationMain 13 | class AppDelegate: NSObject, NSApplicationDelegate { 14 | 15 | @IBOutlet weak var window: NSWindow! 16 | 17 | 18 | class func showModalAlert (_ messageText : String, informativeText : String) { 19 | let alert = NSAlert() 20 | alert.messageText = messageText 21 | alert.informativeText = informativeText 22 | alert.runModal() 23 | } 24 | 25 | func applicationDidFinishLaunching(_ aNotification: Notification) { 26 | // Insert code here to initialize your application 27 | 28 | let xcodeVersion = XCodeSupport.getDeveloperToolsVersion() 29 | if xcodeVersion == nil || xcodeVersion!.compare("6.0", options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending { 30 | 31 | AppDelegate.showModalAlert ( 32 | NSLocalizedString("Error", comment: ""), 33 | informativeText: NSLocalizedString("Xcode 6 or above must be installed for iSimulatorExplorer to run.", comment: "")) 34 | NSApplication.shared().terminate(nil) 35 | } 36 | } 37 | 38 | func applicationWillTerminate(_ aNotification: Notification) { 39 | // Insert code here to tear down your application 40 | } 41 | 42 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 43 | return true 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCAppInfoTableCellView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCAppInfoTableCellView.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 07.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | class DCAppInfoTableCellView: NSTableCellView { 13 | 14 | @IBOutlet weak var appNameTextField: NSTextField! 15 | @IBOutlet weak var appDetailTextField: NSTextField! 16 | 17 | var _appInfo : SimulatorApp! 18 | 19 | var appInfo : SimulatorApp! { 20 | get { 21 | return _appInfo 22 | } 23 | set(appInfo) { 24 | _appInfo = appInfo 25 | 26 | if appNameTextField == nil { 27 | appNameTextField = viewWithTag(1) as? NSTextField 28 | } 29 | if appDetailTextField == nil { 30 | appDetailTextField = viewWithTag(2) as? NSTextField 31 | } 32 | 33 | if appNameTextField != nil { 34 | if appInfo!.displayName != nil { 35 | appNameTextField!.stringValue = appInfo!.displayName! 36 | } 37 | else { 38 | appNameTextField!.stringValue = appInfo!.bundleName! 39 | } 40 | } 41 | //self.textField!.stringValue = appInfo!.displayName! 42 | if appDetailTextField != nil { 43 | appDetailTextField!.stringValue = appInfo!.identifier! 44 | } 45 | } 46 | } 47 | 48 | override func draw(_ dirtyRect: NSRect) { 49 | super.draw(dirtyRect) 50 | 51 | // Drawing code here. 52 | } 53 | 54 | @IBAction func openAppBundleInFinderButtonPressed(_ sender: NSButton) { 55 | if let path = appInfo?.path { 56 | NSWorkspace.shared().selectFile(path, inFileViewerRootedAtPath: path) 57 | } 58 | } 59 | 60 | @IBAction func openAppDataInFinderButtonPressed(_ sender: NSButton) { 61 | if let path = appInfo?.dataPath { 62 | NSWorkspace.shared().selectFile(path, inFileViewerRootedAtPath: path) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCImportCertificateWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCImportCertificateWindowController.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 11.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | class DCImportCertificateWindowController: NSWindowController, NSWindowDelegate, NSTableViewDelegate, NSTableViewDataSource, NSTextFieldDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate { 13 | 14 | @IBOutlet weak var urlTextField: NSTextField! 15 | @IBOutlet weak var infoTextField: NSTextField! 16 | @IBOutlet weak var tableView: NSTableView! 17 | @IBOutlet weak var importButton: NSButton! 18 | @IBOutlet weak var getServerDataButton: NSButton! 19 | 20 | private var certificates : [SecCertificate]? 21 | 22 | var certificate : SecCertificate? 23 | 24 | override func windowDidLoad() { 25 | super.windowDidLoad() 26 | 27 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 28 | 29 | self.window!.delegate = self 30 | enableButtons() 31 | enableGetServerDataButton() 32 | } 33 | 34 | func enableButtons() { 35 | importButton.isEnabled = (tableView.selectedRow >= 0) 36 | } 37 | 38 | func enableGetServerDataButton() { 39 | getServerDataButton.isEnabled = (urlTextField.stringValue != "") 40 | } 41 | 42 | 43 | @IBAction func cancelButtonPressed(_ sender: AnyObject) { 44 | NSApplication.shared().stopModal(withCode: 1) 45 | window!.close(); 46 | } 47 | 48 | func windowShouldClose(_ sender: Any) -> Bool { 49 | NSApplication.shared().stopModal(withCode: 2) 50 | return true 51 | } 52 | 53 | @IBAction func importButtonPressed(_ sender: AnyObject) { 54 | if tableView.selectedRow >= 0 { 55 | certificate = certificates?[tableView.selectedRow] 56 | } 57 | NSApplication.shared().stopModal(withCode: 0) 58 | window!.close(); 59 | } 60 | 61 | @IBAction func getServerDataButtonPressed(_ sender: AnyObject) { 62 | if let url = URL(string: "https://" + urlTextField.stringValue) { 63 | print("url scheme: \(url.scheme) absolute: \(url.absoluteString)", terminator: "\n") 64 | let request = URLRequest(url: url) 65 | if let connection = NSURLConnection(request: request, delegate: self, startImmediately: false) { 66 | connection.schedule(in: RunLoop.current, forMode: RunLoopMode.commonModes) 67 | connection.start() 68 | print("Connection started", terminator: "\n") 69 | infoTextField.stringValue = "Connecting..." 70 | } 71 | } 72 | } 73 | 74 | func connection(_ connection: NSURLConnection, didFailWithError error: Error) { 75 | infoTextField.textColor = NSColor.red 76 | infoTextField.stringValue = error.localizedDescription 77 | } 78 | 79 | func connectionDidFinishLoading(_ connection: NSURLConnection) { 80 | infoTextField.textColor = NSColor.textColor 81 | infoTextField.stringValue = "Successful" 82 | } 83 | 84 | func connection(_ connection: NSURLConnection, willSendRequestFor challenge: URLAuthenticationChallenge) { 85 | NSLog("willSendRequestForAuthenticationChallenge for \(challenge.protectionSpace.authenticationMethod)") 86 | 87 | if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { 88 | if let serverTrust = challenge.protectionSpace.serverTrust { 89 | 90 | var evaluateResult : SecTrustResultType = .invalid; 91 | let status = SecTrustEvaluate(serverTrust, &evaluateResult); 92 | 93 | if (status == errSecSuccess) && (evaluateResult == .proceed || evaluateResult == .unspecified ) { 94 | NSLog("Certificate is trusted") 95 | } 96 | else 97 | { 98 | NSLog("Certificate is not trusted") 99 | } 100 | certificates = [SecCertificate]() 101 | let certCount = SecTrustGetCertificateCount(serverTrust) 102 | NSLog("number certificate in serverTrust: \(certCount)"); 103 | 104 | for index in 0 ..< certCount { 105 | if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, index) { 106 | 107 | let summary = SecCertificateCopySubjectSummary(serverCertificate) 108 | NSLog(" server certificate: \(summary)") 109 | 110 | let cdata = SecCertificateCopyData(serverCertificate) 111 | if let cert = SecCertificateCreateWithData(nil, cdata) { 112 | 113 | certificates!.append(cert) 114 | } 115 | } 116 | } 117 | tableView.reloadData() 118 | enableButtons() 119 | } 120 | } 121 | 122 | challenge.sender?.performDefaultHandling!(for: challenge) 123 | } 124 | 125 | func numberOfRows(in tableView: NSTableView) -> Int { 126 | 127 | return certificates?.count ?? 0 128 | } 129 | 130 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 131 | if let result = tableView.make(withIdentifier: "DataCell", owner: self) as? NSTableCellView { 132 | if certificates != nil { 133 | let summary = SecCertificateCopySubjectSummary(certificates![row]) as String 134 | result.textField!.stringValue = summary 135 | } 136 | return result 137 | } 138 | return nil 139 | } 140 | 141 | func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { 142 | return nil; 143 | } 144 | 145 | func tableViewSelectionDidChange(_ notification: Notification) { 146 | enableButtons() 147 | } 148 | 149 | override func controlTextDidChange(_ obj: Notification) { 150 | enableGetServerDataButton() 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCImportCertificateWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 145 | 149 | 150 | 151 | 152 | 153 | 154 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulator.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 16/02/15. 6 | // Copyright (c) 2015 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | 13 | class SimulatorApp { 14 | var identifier : String? 15 | var bundleName : String? 16 | var displayName : String? 17 | var path : String? 18 | var dataPath : String? 19 | 20 | init(appInfo : [String : AnyObject]) { 21 | identifier = appInfo[kCFBundleIdentifierKey as String] as? String 22 | // appInfo[kCFBundleExecutableKey] as? String 23 | bundleName = appInfo[kCFBundleNameKey as String] as? String 24 | displayName = appInfo["CFBundleDisplayName"] as? String 25 | path = appInfo["Path"] as? String 26 | } 27 | 28 | } 29 | 30 | enum SimulatorOSType { 31 | case iOS 32 | case tvOS 33 | case watchOS 34 | } 35 | 36 | class Simulator { 37 | var _name : String? 38 | var deviceName : String? 39 | var version : String? 40 | var build : String? 41 | var UDID : UUID? 42 | var path : String? 43 | var trustStorePath : String? 44 | var isValid : Bool 45 | var simulatorOS : SimulatorOSType 46 | 47 | private var simDevice : SimDeviceWrapper? 48 | // private var appDataDirMap : [String : String]? 49 | 50 | init() { 51 | isValid = false 52 | simulatorOS = SimulatorOSType.iOS 53 | } 54 | 55 | var stateString : String? { 56 | return self.simDevice?.stateString() 57 | } 58 | 59 | var state : SimDeviceState? { 60 | return self.simDevice?.state 61 | } 62 | 63 | var name : String? { 64 | if simDevice != nil { 65 | return simDevice!.name 66 | } 67 | else { 68 | return _name 69 | } 70 | } 71 | 72 | private func initTrustStorePath() { 73 | trustStorePath = (path as NSString?)?.appendingPathComponent("data/Library/Keychains/TrustStore.sqlite3") 74 | } 75 | 76 | private func initDeviceType (_ runtimeIdentifier : String?) 77 | { 78 | if runtimeIdentifier != nil { 79 | if runtimeIdentifier!.hasPrefix("com.apple.CoreSimulator.SimRuntime.watchOS") { 80 | simulatorOS = SimulatorOSType.watchOS 81 | } 82 | else if runtimeIdentifier!.hasPrefix("com.apple.CoreSimulator.SimRuntime.tvOS") { 83 | simulatorOS = SimulatorOSType.tvOS 84 | } 85 | } 86 | } 87 | 88 | convenience init(path : String) { 89 | self.init() 90 | self.path = path 91 | let devicePlist = (path as NSString).appendingPathComponent("device.plist") 92 | let fm = FileManager.default 93 | if fm.fileExists(atPath: devicePlist) { 94 | let plistData = fm.contents(atPath: devicePlist)! 95 | if let plistobj : AnyObject? = try! PropertyListSerialization.propertyList(from: plistData, 96 | options: PropertyListSerialization.ReadOptions(rawValue: 0), 97 | format: nil) as AnyObject?? 98 | { 99 | if let plist = plistobj as? Dictionary { 100 | //let deviceType = plist["deviceType"] as? String 101 | let name1 = plist["name"] as? String 102 | if let runtime = plist["runtime"] as? String { 103 | version = runtime.components(separatedBy: ".").last 104 | _name = name1! + " v" + version! 105 | isValid = true 106 | initDeviceType(runtime) 107 | initTrustStorePath() 108 | } 109 | } 110 | } 111 | 112 | } 113 | } 114 | 115 | convenience init(device : AnyObject) { 116 | self.init() 117 | self.simDevice = SimDeviceWrapper(device) 118 | self.deviceName = device.deviceType?.name 119 | self.path = device.devicePath() as String? 120 | self.UDID = device.udid as UUID 121 | self.version = device.runtime?.versionString 122 | 123 | self.build = device.runtime?.buildVersionString 124 | initDeviceType(device.runtime?.identifier) 125 | initTrustStorePath() 126 | isValid = self.simDevice!.available; 127 | } 128 | 129 | func getAppDataDirMap() -> [String : String] { 130 | var map = [String : String]() 131 | let fm = FileManager.default 132 | let appDataContainerFolder = (self.path! as NSString).appendingPathComponent("data/Containers/Data/Application") 133 | if let dataFolders = try? fm.contentsOfDirectory(atPath: appDataContainerFolder) { 134 | for folderName in dataFolders { 135 | let folderPath = (appDataContainerFolder as NSString).appendingPathComponent(folderName) 136 | let metadataInfoFile = (folderPath as NSString).appendingPathComponent(".com.apple.mobile_container_manager.metadata.plist") 137 | if fm.fileExists(atPath: metadataInfoFile) { 138 | 139 | let plistData = fm.contents(atPath: metadataInfoFile)! 140 | if let plistobj : AnyObject? = try! PropertyListSerialization.propertyList(from: plistData, 141 | options: PropertyListSerialization.ReadOptions(rawValue: 0), 142 | format: nil) as AnyObject?? { 143 | if let identifier = (plistobj as? Dictionary)?["MCMMetadataIdentifier"] as? String { 144 | map[identifier] = folderPath 145 | } 146 | } 147 | } 148 | } 149 | } 150 | return map 151 | } 152 | 153 | func getAppInfoFromFolder(_ path : String) -> SimulatorApp? { 154 | let fm = FileManager.default 155 | if let bundleFolders = try? fm.contentsOfDirectory(atPath: path) { 156 | for filename in bundleFolders { 157 | let bundleFolder = (path as NSString).appendingPathComponent(filename) 158 | let appInfoFile = (bundleFolder as NSString).appendingPathComponent("info.plist") 159 | if fm.fileExists(atPath: appInfoFile) { 160 | 161 | let plistData = fm.contents(atPath: appInfoFile)! 162 | if let plistobj : AnyObject? = try! PropertyListSerialization.propertyList(from: plistData, 163 | options: PropertyListSerialization.ReadOptions(rawValue: 0), 164 | format: nil) as AnyObject?? { 165 | if let plist = plistobj as? Dictionary { 166 | let appInfo = SimulatorApp(appInfo: plist) 167 | appInfo.path = path 168 | return appInfo 169 | } 170 | } 171 | } 172 | } 173 | } 174 | return nil 175 | } 176 | 177 | private func includeAppFilter(_ appInfo : SimulatorApp) -> Bool { 178 | return appInfo.identifier == nil || !appInfo.identifier!.hasPrefix("com.apple.") 179 | } 180 | 181 | func getAppListFromContent() -> [SimulatorApp] { 182 | var appList = [SimulatorApp]() 183 | 184 | let fm = FileManager.default 185 | // For iOS < 8.0 186 | let appDataContainerFolder = (self.path! as NSString).appendingPathComponent("data/Applications") 187 | if let dataFolders = try? fm.contentsOfDirectory(atPath: appDataContainerFolder) { 188 | for folderName in dataFolders { 189 | let folderPath = (appDataContainerFolder as NSString).appendingPathComponent(folderName) 190 | if let appInfo = getAppInfoFromFolder(folderPath) { 191 | if includeAppFilter(appInfo) { 192 | appInfo.dataPath = appInfo.path 193 | appList.append(appInfo) 194 | } 195 | } 196 | } 197 | } 198 | else 199 | { 200 | let map = getAppDataDirMap() 201 | 202 | // For iOS >= 8.0 203 | let appDataContainerFolder = (self.path! as NSString).appendingPathComponent("data/Containers/Bundle/Application") 204 | if let dataFolders = try? fm.contentsOfDirectory(atPath: appDataContainerFolder) { 205 | for folderName in dataFolders { 206 | let folderPath = (appDataContainerFolder as NSString).appendingPathComponent(folderName) 207 | if let appInfo = getAppInfoFromFolder(folderPath) { 208 | if includeAppFilter(appInfo) { 209 | appInfo.dataPath = map[appInfo.identifier!] 210 | appList.append(appInfo) 211 | } 212 | } 213 | } 214 | } 215 | } 216 | return appList 217 | 218 | } 219 | 220 | 221 | func getAppList() -> [SimulatorApp]? 222 | { 223 | if self.simDevice?.state == SimDeviceState.booted { 224 | do { 225 | let appDict = try self.simDevice!.installedApps() as? [String : NSDictionary] 226 | //let appDict = app as? [String : NSDictionary] 227 | NSLog("apps: %@", appDict!) 228 | 229 | let map = getAppDataDirMap() 230 | 231 | var appList = [SimulatorApp]() 232 | for appItem in appDict! { 233 | let appItemInfo = appItem.1 as? [String : AnyObject] 234 | let appInfo = SimulatorApp(appInfo : appItemInfo!) 235 | if includeAppFilter(appInfo) { 236 | appInfo.dataPath = map[appInfo.identifier!] 237 | appList.append(appInfo) 238 | } 239 | } 240 | 241 | return appList 242 | } 243 | catch let error as NSError 244 | { 245 | NSLog("Cannot get app list from coresimulator: %@", error.localizedDescription) 246 | } 247 | catch 248 | { 249 | NSLog("Cannot get app list from coresimulator: Unknown error") 250 | } 251 | } 252 | return getAppListFromContent() 253 | } 254 | 255 | func launchSimulatorApp() -> Bool { 256 | var result = false 257 | let simulatorAppName : String 258 | if XCodeSupport.getDeveloperToolsVersion()?.compare("7.0", options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending { 259 | simulatorAppName = "iOS Simulator" 260 | } 261 | else 262 | { 263 | simulatorAppName = (simulatorOS == SimulatorOSType.watchOS) ? "Simulator (Watch)" : "Simulator" 264 | } 265 | let workspace = NSWorkspace.shared() 266 | var appPath : String? 267 | if let path = workspace.fullPath(forApplication: simulatorAppName) { 268 | appPath = path 269 | } 270 | else if let devPath = XCodeSupport.getDeveloperToolsPath() { 271 | NSLog("Try to find simulator app at \(devPath)") 272 | let possibleAppPath : [String] 273 | if simulatorOS == SimulatorOSType.watchOS { 274 | possibleAppPath = ["Applications/Simulator (Watch).app"] 275 | } 276 | else { 277 | possibleAppPath = ["Applications/iOS Simulator.app", "Applications/Simulator.app", "../Applications/iOS Simulator.app", "../Applications/iPhone Simulator.app"] 278 | } 279 | let fm = FileManager.default 280 | for testPath in possibleAppPath { 281 | let path = (devPath as NSString).appendingPathComponent(testPath) 282 | if fm.fileExists(atPath: path) { 283 | appPath = path 284 | break 285 | } 286 | } 287 | } 288 | if appPath != nil { 289 | NSLog("Found simulator app at \(appPath)") 290 | let appUrl = URL(fileURLWithPath: appPath!) 291 | let launchArg = (UDID != nil) ? 292 | [NSWorkspaceLaunchConfigurationArguments : ["-CurrentDeviceUDID", UDID!.uuidString]] : [String : Array]() 293 | 294 | NSLog("Launching iOS Simulator with \(launchArg)") 295 | 296 | do { 297 | let runningApp = try workspace.launchApplication(at: appUrl, options: NSWorkspaceLaunchOptions.default, configuration: launchArg) 298 | NSLog("Simulator started. PID=%u", runningApp.processIdentifier) 299 | result = true 300 | } 301 | catch let error as NSError { 302 | NSLog("Error launching simulator: %@", error) 303 | } 304 | catch{ 305 | NSLog("Error launching simulator: Unknown error") 306 | } 307 | 308 | } 309 | else { 310 | NSLog("Simulator App not found") 311 | } 312 | return result 313 | } 314 | 315 | func boot(_ completionHandler : ((_ error : Error?) -> Void)?) { 316 | 317 | if simDevice != nil { 318 | var env = [String : String]() // ProcessInfo.processInfo.environment; 319 | env["SIMULATOR_IS_HEADLESS"] = "1" 320 | let options : [String : AnyObject] = [ 321 | "env" : env as AnyObject, 322 | "persist" : true as AnyObject] 323 | // "disabled_jobs" : ["com.apple.backboardd" : true] as AnyObject] 324 | 325 | simDevice!.bootAsync(options: options, completionHandler: { (error : Error?) -> Void in 326 | if error != nil { 327 | NSLog("boot error:\(error!)") 328 | } 329 | else { 330 | NSLog("boot success") 331 | } 332 | DispatchQueue.main.async(execute: { () -> Void in 333 | completionHandler?(error) 334 | }) 335 | }) 336 | } 337 | else { 338 | completionHandler?(NSError(domain: "iSimulatorExplorer", code: 1, userInfo: [NSLocalizedDescriptionKey : "Cannot boot device when CoreSimulator is not available"])) 339 | } 340 | } 341 | 342 | func shutdown(_ completionHandler : ((_ error : Error?) -> Void)?) { 343 | 344 | if simDevice != nil { 345 | simDevice!.shutdownAsync { (error : Error?) -> Void in 346 | if error != nil { 347 | NSLog("shutdown error:\(error!)") 348 | } 349 | else { 350 | NSLog("shutdown success") 351 | } 352 | DispatchQueue.main.async(execute: { () -> Void in 353 | completionHandler?(error) 354 | }) 355 | } 356 | } 357 | else { 358 | completionHandler?(NSError(domain: "iSimulatorExplorer", code: 1, userInfo: [NSLocalizedDescriptionKey : "Cannot shutdown device when CoreSimulator is not available"])) 359 | } 360 | } 361 | 362 | enum SimulatorActionError : Error { 363 | case invalidBundleIdentifier 364 | } 365 | 366 | private func doActionWithBootAndShutdown ( 367 | _ arg1 : T, 368 | action: @escaping ((_ arg1 : T, _ completionHandler : ((_ error : Error?) -> Void)?) throws -> Void), 369 | completionHandler : ((_ error : Error?) -> Void)?) { 370 | 371 | if simDevice!.state != SimDeviceState.booted { 372 | boot({ (error) -> Void in 373 | if error != nil { 374 | completionHandler?(error) 375 | } 376 | try! action(arg1, { (error) -> Void in 377 | self.shutdown({ (shutdownError) -> Void in 378 | completionHandler?(error) 379 | }) 380 | }) 381 | }) 382 | } 383 | else { 384 | try! action(arg1, completionHandler) 385 | } 386 | } 387 | 388 | func installApp (_ appUrl : URL, completionHandler : ((_ error : Error?) -> Void)?) { 389 | 390 | let installAppAction = {(appUrl : URL, completionHandler : ((_ error : Error?) -> Void)?) -> Void in 391 | var bundleId = Bundle(url: appUrl)?.bundleIdentifier 392 | if bundleId == nil { 393 | let plistUrl = appUrl.appendingPathComponent("Info.plist") 394 | if let plist = NSDictionary(contentsOf: plistUrl) { 395 | bundleId = plist["CFBundleIdentifier"] as? String 396 | } 397 | } 398 | 399 | if bundleId != nil { 400 | let options : [String : AnyObject] = ["CFBundleIdentifier" : bundleId! as AnyObject] 401 | 402 | do { 403 | try self.simDevice!.installApplication(appUrl, withOptions: options) 404 | completionHandler?(nil) 405 | } 406 | catch let error { 407 | completionHandler?(error) 408 | } 409 | } 410 | else { 411 | completionHandler?(NSError( 412 | domain: "iSimulatorExplorer", 413 | code: 2, 414 | userInfo: [NSLocalizedDescriptionKey : "Cannot install app: bundle Identifier not found"])) 415 | } 416 | } 417 | 418 | if simDevice != nil { 419 | 420 | doActionWithBootAndShutdown(appUrl, action: installAppAction, completionHandler: completionHandler) 421 | } 422 | else { 423 | completionHandler?(NSError(domain: "iSimulatorExplorer", code: 1, userInfo: [NSLocalizedDescriptionKey : "Cannot install app when CoreSimulator is not available"])) 424 | } 425 | 426 | } 427 | 428 | func uninstallApp (_ appId : String, completionHandler : ((_ error : Error?) -> Void)?) { 429 | 430 | 431 | let uninstallAppAction = { (appId : String, completionHandler : ((_ error : Error?) -> Void)?) -> Void in 432 | do { 433 | try self.simDevice!.uninstallApplication(appId, withOptions: nil) 434 | completionHandler?(nil) 435 | } 436 | catch let error { 437 | completionHandler?(error) 438 | } 439 | } 440 | 441 | if simDevice != nil { 442 | doActionWithBootAndShutdown(appId, action: uninstallAppAction, completionHandler: completionHandler) 443 | } 444 | else { 445 | completionHandler?(NSError(domain: "iSimulatorExplorer", code: 1, userInfo: [NSLocalizedDescriptionKey : "Cannot uninstall app when CoreSimulator is not available"])) 446 | } 447 | 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorAppViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorAppViewController.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 10.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | class DCSimulatorAppViewController: DCSimulatorViewController, NSTableViewDataSource, NSTableViewDelegate { 13 | 14 | @IBOutlet weak var appTableView: NSTableView! 15 | @IBOutlet weak var installAppButton: NSButton! 16 | @IBOutlet weak var uninstallAppButton: NSButton! 17 | var isBusy : Bool = false 18 | 19 | var simulatorAppList : [SimulatorApp]? 20 | 21 | override var simulator : Simulator? { 22 | didSet { 23 | simulatorAppList = simulator!.getAppList() 24 | appTableView.reloadData() 25 | enableButtons() 26 | } 27 | } 28 | 29 | override func loadView() { 30 | super.loadView() 31 | enableButtons() 32 | } 33 | 34 | func enableButtons() { 35 | let enableActionOnSelected = (appTableView.selectedRow >= 0 && simulatorAppList != nil && simulatorAppList!.count > 0) 36 | uninstallAppButton.isEnabled = enableActionOnSelected && !isBusy 37 | installAppButton.isEnabled = !isBusy 38 | } 39 | 40 | func numberOfRows(in tableView: NSTableView) -> Int { 41 | 42 | if simulatorAppList != nil { 43 | return (simulatorAppList!.count > 0) ? simulatorAppList!.count : 1 44 | } 45 | return 0 46 | } 47 | 48 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 49 | if simulatorAppList != nil && simulatorAppList!.count == 0 { 50 | return tableView.make(withIdentifier: "NoAppCell", owner: self) as? NSTableCellView 51 | } 52 | if let result = tableView.make(withIdentifier: "DataCell", owner: self) as? DCAppInfoTableCellView { 53 | if let appInfo = simulatorAppList?[row] { 54 | //result.textField!.stringValue = appInfo.displayName! 55 | result.appInfo = appInfo 56 | } 57 | return result 58 | } 59 | return nil 60 | } 61 | 62 | func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { 63 | return nil 64 | } 65 | 66 | func tableViewSelectionDidChange(_ notification: Notification) { 67 | enableButtons() 68 | } 69 | 70 | 71 | @IBAction func openAppDataInFinderPressed(_ sender: NSButton) { 72 | if let appInfoCellView = sender.superview as? DCAppInfoTableCellView { 73 | if let path = appInfoCellView.appInfo?.dataPath { 74 | NSWorkspace.shared().selectFile(path, inFileViewerRootedAtPath: path) 75 | } 76 | } 77 | } 78 | 79 | @IBAction func openAppBundleInFinderPressed(_ sender: NSButton) { 80 | if let appInfoCellView = sender.superview as? DCAppInfoTableCellView { 81 | if let path = appInfoCellView.appInfo?.path { 82 | NSWorkspace.shared().selectFile(path, inFileViewerRootedAtPath: path) 83 | } 84 | } 85 | } 86 | 87 | @IBAction func installApp(_ sender: AnyObject) { 88 | let openPanel = NSOpenPanel() 89 | openPanel.canChooseFiles = true 90 | openPanel.canChooseDirectories = false 91 | openPanel.allowsMultipleSelection = false 92 | 93 | if openPanel.runModal() == NSFileHandlingPanelOKButton { 94 | for url in openPanel.urls { 95 | isBusy = true 96 | enableButtons() 97 | simulator!.installApp(url, completionHandler: { (error) -> Void in 98 | self.isBusy = false 99 | self.enableButtons() 100 | if error != nil { 101 | AppDelegate.showModalAlert( 102 | NSLocalizedString("Error installing app \(url)", comment: ""), 103 | informativeText: "Error details: \(error)") 104 | print("Install app \(url) error: \(error!)", terminator:"\n") 105 | } 106 | else { 107 | print("Install app \(url) successful", terminator:"\n") 108 | self.simulatorAppList = self.simulator!.getAppList() 109 | self.appTableView.reloadData() 110 | } 111 | }) 112 | } 113 | } 114 | } 115 | 116 | @IBAction func uninstallApp(_ sender: AnyObject) { 117 | if appTableView.selectedRow >= 0 { 118 | if let appId = simulatorAppList![appTableView.selectedRow].identifier { 119 | 120 | isBusy = true 121 | enableButtons() 122 | simulator!.uninstallApp(appId, completionHandler: { (error) -> Void in 123 | self.isBusy = false 124 | self.enableButtons() 125 | if error != nil { 126 | 127 | AppDelegate.showModalAlert( 128 | NSLocalizedString("Error uninstalling app \(appId)", comment: ""), 129 | informativeText: "Error details: \(error)") 130 | } 131 | else { 132 | print("Uninstall app \(appId) successful", terminator:"\n") 133 | self.simulatorAppList = self.simulator!.getAppList() 134 | self.appTableView.reloadData() 135 | } 136 | }) 137 | } 138 | 139 | } 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorAppViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 98 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 159 | 164 | 165 | 179 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorExplorerController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorExplorerController.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 15.08.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | class SimulatorVersion { 13 | var version : String 14 | var simulators : [Simulator] 15 | 16 | init(version : String, simulators : [Simulator]) { 17 | self.version = version 18 | self.simulators = simulators 19 | } 20 | 21 | } 22 | 23 | // Cannot use protocol because to support downcasting it must be marked as @objc which limits the types we can use. 24 | //protocol SimulatorController { 25 | // var simulator : Simulator? { get set } 26 | //} 27 | 28 | class DCSimulatorViewController: NSViewController { 29 | var simulator : Simulator? // { 30 | } 31 | 32 | class DCSimulatorExplorerController: NSObject, NSWindowDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSTabViewDelegate { 33 | 34 | @IBOutlet weak var outlineView: NSOutlineView! 35 | @IBOutlet weak var tabView: NSTabView! 36 | 37 | var simulatorManager : DCSimulatorManager? 38 | 39 | 40 | var _simulators : [SimulatorVersion]? 41 | var simulatorVersions : [SimulatorVersion] { 42 | get { 43 | if _simulators == nil { 44 | _simulators = [SimulatorVersion]() 45 | 46 | let firstInit = (simulatorManager == nil) 47 | if firstInit { 48 | simulatorManager = DCSimulatorManager() 49 | } 50 | 51 | DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.low).async(execute: { () -> Void in 52 | 53 | var simulatorsByVersion = [String : [Simulator]]() 54 | for sim in self.simulatorManager!.simulators { 55 | let typeAndVersion : String 56 | switch sim.simulatorOS { 57 | case SimulatorOSType.tvOS: 58 | typeAndVersion = "tvOS Simulator v\(sim.version!)" 59 | case SimulatorOSType.watchOS: 60 | typeAndVersion = "watchOS Simulator v\(sim.version!)" 61 | default: 62 | typeAndVersion = "Simulator v\(sim.version!)" 63 | 64 | } 65 | 66 | if simulatorsByVersion[typeAndVersion] == nil { 67 | let simulators = [Simulator]() 68 | simulatorsByVersion[typeAndVersion] = simulators 69 | } 70 | simulatorsByVersion[typeAndVersion]?.append(sim) 71 | 72 | } 73 | let sortedKeys = simulatorsByVersion.keys.sorted() 74 | //sortedKeys.sort({ (s1, s2) -> Bool in 75 | // return s2 > s1 76 | //}) 77 | var simulatorVersions = [SimulatorVersion]() 78 | for key in sortedKeys { 79 | let sims = simulatorsByVersion[key]! 80 | simulatorVersions.append(SimulatorVersion(version: key, simulators: sims)) 81 | 82 | } 83 | DispatchQueue.main.async(execute: { () -> Void in 84 | self._simulators = simulatorVersions 85 | self.outlineView.reloadData() 86 | self.initView(firstInit) 87 | }) 88 | }) 89 | 90 | } 91 | return _simulators! 92 | } 93 | } 94 | 95 | 96 | func initView(_ firstInit : Bool) { 97 | initTabViewItem(tabView.selectedTabViewItem) 98 | outlineView.expandItem(nil, expandChildren: true) 99 | if (_simulators != nil) { 100 | if let sim = simulatorVersions.first?.simulators.first { 101 | let row = outlineView.row(forItem: sim) 102 | if row >= 0 { 103 | outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) 104 | } 105 | } 106 | } 107 | if firstInit { 108 | simulatorManager!.startNotificationHandler(simDeviceChanged) 109 | } 110 | } 111 | 112 | func simDeviceChanged (_ notificationType : DCSimulatorManager.NotificationType, deviceUDID : UUID, newState : Int) -> Void { 113 | 114 | switch notificationType { 115 | case .deviceState: 116 | if let sim = outlineView.item(atRow: outlineView.selectedRow) as? Simulator { 117 | if sim.UDID == deviceUDID { 118 | for tabViewItem in tabView.tabViewItems { 119 | if let item = tabViewItem.identifier as? DCSimulatorViewController { 120 | item.simulator = sim 121 | } 122 | } 123 | } 124 | } 125 | 126 | case .deviceAdded, .deviceRemoved, .deviceRenamed: 127 | // Simplified handling of other cases: just reloading the complete list 128 | _simulators = nil 129 | self.outlineView.reloadData() 130 | 131 | } 132 | 133 | } 134 | 135 | func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { 136 | if (item == nil) { 137 | return simulatorVersions[index] 138 | } 139 | else if let simulatorsForVersion = item as? SimulatorVersion { 140 | return simulatorsForVersion.simulators[index]; 141 | } 142 | else { 143 | return ""; 144 | } 145 | } 146 | 147 | func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { 148 | if (item == nil) { 149 | return simulatorVersions.count 150 | } 151 | else if let simulatorsForVersion = item as? SimulatorVersion { 152 | return simulatorsForVersion.simulators.count 153 | } 154 | else { 155 | return 0; 156 | } 157 | } 158 | 159 | func outlineView(_ outlineView: NSOutlineView, isGroupItem item: Any) -> Bool { 160 | return item is SimulatorVersion 161 | } 162 | 163 | func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { 164 | return item is SimulatorVersion 165 | } 166 | 167 | func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { 168 | if let simulatorsForVersion = item as? SimulatorVersion { 169 | if let result = outlineView.make(withIdentifier: "HeaderCell", owner: self) as? NSTableCellView { 170 | result.textField!.stringValue = simulatorsForVersion.version 171 | return result 172 | } 173 | } 174 | else if let sim = item as? Simulator { 175 | if let result = outlineView.make(withIdentifier: "DataCell", owner: self) as? NSTableCellView { 176 | result.textField!.stringValue = sim.name! 177 | return result 178 | } 179 | } 180 | return nil 181 | } 182 | 183 | func outlineViewSelectionDidChange(_ notification: Notification) { 184 | if let sim = outlineView.item(atRow: outlineView.selectedRow) as? Simulator { 185 | NSLog("selected: %@", sim.name!) 186 | for tabViewItem in tabView.tabViewItems { 187 | if let item = tabViewItem.identifier as? DCSimulatorViewController { 188 | item.simulator = sim 189 | } 190 | } 191 | } 192 | } 193 | 194 | func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool { 195 | return item is Simulator 196 | } 197 | 198 | func initTabViewItem(_ tabViewItem: NSTabViewItem?) { 199 | if let identifier = tabViewItem?.identifier as? String { 200 | var viewController : NSViewController? 201 | switch identifier { 202 | case "Info": 203 | viewController = DCSimulatorInfoViewController(nibName: "DCSimulatorInfoViewController", bundle: nil) 204 | case "Apps": 205 | viewController = DCSimulatorAppViewController(nibName: "DCSimulatorAppViewController", bundle: nil) 206 | case "Truststore": 207 | viewController = DCSimulatorTrustStoreViewController(nibName: "DCSimulatorTrustStoreViewController", bundle: nil) 208 | default: 209 | viewController = nil 210 | } 211 | if viewController != nil { 212 | tabViewItem?.view = viewController!.view; 213 | tabViewItem?.identifier = viewController! 214 | if outlineView.selectedRow >= 0 { 215 | if let item = viewController as? DCSimulatorViewController { 216 | item.simulator = outlineView.item(atRow: outlineView.selectedRow) as? Simulator 217 | } 218 | } 219 | } 220 | } 221 | } 222 | 223 | func tabView(_ tabView: NSTabView, shouldSelect tabViewItem: NSTabViewItem?) -> Bool { 224 | initTabViewItem(tabViewItem) 225 | return true; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorInfoViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorInfoViewController.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 12.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | 12 | struct DCInfoViewItem { 13 | var name : String 14 | var value : String 15 | } 16 | 17 | class DCSimulatorInfoViewController: DCSimulatorViewController, NSTableViewDataSource, NSTableViewDelegate { 18 | 19 | @IBOutlet weak var infoTableView: NSTableView! 20 | @IBOutlet weak var startStopButton: NSButton! 21 | 22 | private var infoItems = [DCInfoViewItem]() 23 | override var simulator : Simulator? { 24 | didSet { 25 | infoItems = [DCInfoViewItem]() 26 | let empty = "" 27 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("Name:", comment: ""), value: simulator!.name ?? empty)) 28 | if simulator!.deviceName != nil { 29 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("Simulated Model:", comment: ""), value: simulator!.deviceName!)) 30 | } 31 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("Version:", comment: ""), value: "\(simulator!.version ?? empty) - \(simulator!.build ?? empty)")) 32 | if simulator!.UDID != nil { 33 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("UDID:", comment: ""), value: simulator!.UDID!.uuidString)) 34 | } 35 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("Path:", comment: ""), value: (simulator!.path as NSString?)?.abbreviatingWithTildeInPath ?? empty)) 36 | if simulator!.stateString != nil { 37 | infoItems.append(DCInfoViewItem(name: NSLocalizedString("State:", comment: ""), value: simulator!.stateString!)) 38 | } 39 | infoTableView.reloadData() 40 | updateStartStopButton() 41 | } 42 | } 43 | 44 | override func viewDidAppear() { 45 | // ViewController lifecycle methods are only available with OS X 10.10 and above 46 | } 47 | 48 | override func viewDidDisappear() { 49 | // ViewController lifecycle methods are only available with OS X 10.10 and above 50 | } 51 | 52 | 53 | func numberOfRows(in tableView: NSTableView) -> Int { 54 | 55 | if simulator != nil { 56 | return infoItems.count 57 | } 58 | return 0 59 | } 60 | 61 | func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { 62 | 63 | if tableColumn?.identifier == "NameColumn" { 64 | return infoItems[row].name 65 | } else if tableColumn?.identifier == "ValueColumn" { 66 | return infoItems[row].value 67 | } 68 | return nil 69 | } 70 | 71 | func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { 72 | return false 73 | } 74 | 75 | 76 | @IBAction func showInFinderPressed(_ sender: NSButton) { 77 | if simulator != nil { 78 | NSWorkspace.shared().selectFile(simulator!.path!, inFileViewerRootedAtPath: simulator!.path!) 79 | } 80 | } 81 | 82 | @IBAction func openSimulatorPressed(_ sender: NSButton) { 83 | if simulator != nil { 84 | let _ = simulator?.launchSimulatorApp() 85 | } 86 | } 87 | 88 | 89 | func updateStartStopButton() { 90 | if (simulator!.state == nil) { 91 | startStopButton.isHidden = true 92 | } 93 | else { 94 | startStopButton.isHidden = false 95 | switch simulator!.state! { 96 | case .booted: 97 | startStopButton.isEnabled = true 98 | startStopButton.title = "Shutdown" 99 | case .shutDown: 100 | startStopButton.isEnabled = true 101 | startStopButton.title = "Boot" 102 | default: 103 | startStopButton.isEnabled = false 104 | } 105 | } 106 | } 107 | 108 | 109 | @IBAction func startStopSimulatorPressed(_ sender: NSButton) { 110 | if (simulator!.state! == .shutDown) { 111 | simulator?.boot({ (error) in 112 | NSLog("boot complete. \(error)") 113 | }) 114 | } 115 | else { 116 | simulator?.shutdown({ (error) in 117 | NSLog("shudown complete. \(error)") 118 | }) 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorInfoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 35 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 104 | 108 | 109 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorManager.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 25.08.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | class DCSimulatorManager { 13 | private var simulatorFramework : Bundle? 14 | private let kDVTFoundationRelativePath = "../SharedFrameworks/DVTFoundation.framework" 15 | private let kDevToolsFoundationRelativePath = "../OtherFrameworks/DevToolsFoundation.framework" 16 | private var developerDir : String? 17 | private var simServiceContextClass : AnyClass? 18 | private var simDeviceSetClass : AnyClass? 19 | private var simDeviceSet : AnyObject? 20 | private var getSimulators : () -> [Simulator] 21 | 22 | // Helper to find a class by name and die if it isn't found. 23 | private func FindClassByName(_ nameOfClass : String) -> AnyClass! { 24 | if let theClass : AnyClass = NSClassFromString(nameOfClass) { 25 | return theClass 26 | } 27 | else 28 | { 29 | NSLog("Failed to find class %@ at runtime.", nameOfClass) 30 | return nil 31 | } 32 | } 33 | 34 | private func LoadSimulatorFramework() -> Bundle! { 35 | if let devDir = XCodeSupport.getDeveloperToolsPath() as NSString? { 36 | self.developerDir = devDir as String 37 | 38 | // The Simulator framework depends on some of the other Xcode private 39 | // frameworks; manually load them first so everything can be linked up. 40 | let dvtFoundationPath = devDir.appendingPathComponent(kDVTFoundationRelativePath) 41 | 42 | if let dvtFoundationBundle = Bundle(path: dvtFoundationPath) { 43 | if !(dvtFoundationBundle.load()) { 44 | return nil 45 | } 46 | } 47 | 48 | let devToolsFoundationPath = devDir.appendingPathComponent(kDevToolsFoundationRelativePath) 49 | if let devToolsFoundationBundle = Bundle(path: devToolsFoundationPath) { 50 | if !(devToolsFoundationBundle.load()) { 51 | return nil 52 | } 53 | } 54 | 55 | 56 | // Prime DVTPlatform. 57 | do { 58 | try CoreSimulatorHelper.loadAllPlatformsReturningError() 59 | } 60 | catch let error as NSError { 61 | NSLog("Unable to loadAllPlatformsReturningError. Error: %@", error.localizedDescription) 62 | return nil; 63 | } 64 | catch { 65 | NSLog("Unable to loadAllPlatformsReturningError. Unknown Error") 66 | return nil; 67 | } 68 | 69 | // The path within the developer dir of the private Simulator frameworks. 70 | let simulatorFrameworkRelativePath = "../SharedFrameworks/DVTiPhoneSimulatorRemoteClient.framework"; 71 | let kCoreSimulatorRelativePath = "Library/PrivateFrameworks/CoreSimulator.framework"; 72 | let coreSimulatorPath = devDir.appendingPathComponent(kCoreSimulatorRelativePath); 73 | if let coreSimulatorBundle = Bundle(path: coreSimulatorPath) { 74 | if !(coreSimulatorBundle.load()) { 75 | return nil 76 | } 77 | } 78 | let simBundlePath = devDir.appendingPathComponent(simulatorFrameworkRelativePath); 79 | if let simBundle = Bundle(path: simBundlePath) { 80 | if !(simBundle.load()) { 81 | return nil 82 | } 83 | return simBundle; 84 | } 85 | } 86 | return nil; 87 | } 88 | 89 | 90 | // Get XCode version 8 simulators using CoreSimulator framework 91 | fileprivate func getXcode8SimulatorsFromCoreSimulator() -> [Simulator] { 92 | 93 | var simulators = [Simulator]() 94 | 95 | //if let context = try? simServiceContextClass!.sharedServiceContext(forDeveloperDir: developerDir!) { 96 | if let context = try? SimServiceContextWrapper.sharedServiceContext(forDeveloperDir: developerDir!, simServiceContextClass:simServiceContextClass!) { 97 | 98 | simDeviceSet = try! context.defaultDeviceSet() 99 | 100 | if simDeviceSet != nil { 101 | if let deviceList = simDeviceSet!.availableDevices { 102 | for simDevice in deviceList { 103 | let sim = Simulator(device: simDevice as AnyObject) 104 | if sim.isValid { 105 | simulators.append(sim) 106 | } 107 | } 108 | } 109 | } 110 | 111 | } 112 | 113 | return simulators; 114 | } 115 | 116 | // Get XCode simulators by browsing the file system 117 | private func getXcode8SimulatorsFromFileSystem() -> [Simulator] { 118 | 119 | var simulators = [Simulator]() 120 | 121 | let simBasePath = ("~/Library/Developer/CoreSimulator/Devices" as NSString).expandingTildeInPath 122 | if let fileList = try? FileManager.default.contentsOfDirectory(atPath: simBasePath) { 123 | for item in fileList 124 | { 125 | print("item is \(item)", terminator:"\n") 126 | 127 | let path = (simBasePath as NSString).appendingPathComponent(item) 128 | 129 | let sim = Simulator(path: path) 130 | if sim.isValid { 131 | simulators.append(sim); 132 | } 133 | } 134 | } 135 | return simulators; 136 | } 137 | 138 | 139 | var simulators : [Simulator] { 140 | get { 141 | return getSimulators() 142 | } 143 | } 144 | 145 | 146 | init() { 147 | 148 | getSimulators = { () -> [Simulator] in 149 | return [Simulator]() 150 | } 151 | 152 | if let dtVersion = XCodeSupport.getDeveloperToolsVersion() { 153 | 154 | NSLog("XCode version \(dtVersion)") 155 | if dtVersion.compare("8.0", options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending { 156 | 157 | NSLog("XCode version < 8.0. Not Supported") 158 | 159 | } 160 | else { 161 | NSLog("XCode version >= 8.0") 162 | 163 | // XCode version 8.0 simulators 164 | simulatorFramework = LoadSimulatorFramework() 165 | simDeviceSetClass = FindClassByName("SimDeviceSet") 166 | simServiceContextClass = FindClassByName("SimServiceContext") 167 | if simServiceContextClass != nil { 168 | getSimulators = getXcode8SimulatorsFromCoreSimulator 169 | } 170 | else 171 | { 172 | getSimulators = getXcode8SimulatorsFromFileSystem 173 | } 174 | } 175 | } 176 | } 177 | 178 | enum NotificationType { 179 | case deviceState 180 | case deviceAdded 181 | case deviceRemoved 182 | case deviceRenamed 183 | } 184 | 185 | func startNotificationHandler(_ handler : @escaping (NotificationType, UUID, Int) -> Void ) { 186 | if simDeviceSet != nil { 187 | 188 | let _ = simDeviceSet!.registerNotificationHandler({ (data : [AnyHashable: Any]?) -> Void in 189 | 190 | if let notificationData = data as? [String : AnyObject] { 191 | if let notificationTypeString = notificationData["notification"] as? String { 192 | 193 | //var state : Int = 0 194 | var notificationType : NotificationType? 195 | //var udid : NSUUID? 196 | //TODO : review if SimDevice cast work 197 | let simDevice : AnyObject? = notificationData["device"] // as? SimDevice 198 | 199 | switch notificationTypeString { 200 | case "device_state": 201 | notificationType = .deviceState 202 | if let state = notificationData["new_state"] as? Int { 203 | NSLog("SimDevice \(simDevice?.udid) new state: \(state)") 204 | } 205 | 206 | case "device_added": 207 | notificationType = .deviceAdded 208 | NSLog("SimDevice \(simDevice?.udid) added: \(simDevice?.stateString())") 209 | 210 | case "device_removed": 211 | notificationType = .deviceRemoved 212 | NSLog("SimDevice \(simDevice?.udid) removed") 213 | 214 | case "device_renamed": 215 | notificationType = .deviceRenamed 216 | //NSLog("SimDevice \(simDevice?.udid) renamed to: \(simDevice?.name)") 217 | 218 | default: 219 | NSLog("Notification: \(data)") 220 | } 221 | if notificationType != nil && simDevice != nil { 222 | 223 | DispatchQueue.main.async(execute: { () -> Void in 224 | handler(notificationType!, simDevice!.udid, 0) 225 | }) 226 | 227 | } 228 | } 229 | } 230 | }) 231 | NSLog("SimDeviceSet notification started") 232 | } 233 | } 234 | 235 | } 236 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorTrustStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorTrustStore.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 11.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Foundation 11 | 12 | class DCSimulatorTruststoreItem { 13 | 14 | var sha1: Data?, subject : Data?, data : Data? 15 | 16 | var tset : Data? 17 | 18 | init() { 19 | 20 | tset = ("\n" + 21 | "\n" + 22 | "\n" + 23 | "\n" + 24 | "\n").data(using: String.Encoding.utf8, allowLossyConversion: false) 25 | 26 | } 27 | 28 | convenience init (sha1: Data?, subject : Data?, tset : Data?, data : Data?) 29 | { 30 | self.init() 31 | self.sha1 = sha1 32 | self.subject = subject 33 | self.tset = tset 34 | self.data = data 35 | } 36 | 37 | convenience init (certificate : SecCertificate) { 38 | self.init() 39 | let cdata = SecCertificateCopyData(certificate) 40 | data = cdata as Data 41 | sha1 = getThumbprint() 42 | subject = getNormalizedSubject() 43 | } 44 | 45 | private var _certificate : SecCertificate? 46 | var certificate : SecCertificate? { 47 | get { 48 | if _certificate == nil && data != nil { 49 | _certificate = SecCertificateCreateWithData(nil, data! as CFData) 50 | } 51 | return _certificate; 52 | } 53 | } 54 | 55 | var subjectSummary : String? { 56 | get { 57 | if certificate != nil { 58 | return SecCertificateCopySubjectSummary(certificate!) as String? 59 | } 60 | return nil 61 | } 62 | } 63 | 64 | 65 | func getNormalizedSubject() -> Data? { 66 | //BUG Something to causes an exception in the swift compiler! 67 | //if let data = SecCertificateCopyNormalizedSubjectContent(certificate, nil)?.takeRetainedValue() as? NSData { 68 | 69 | if certificate != nil { 70 | if let cdata = SecCertificateCopyNormalizedSubjectContent(certificate!, nil) { 71 | let data = cdata as Data 72 | return data 73 | } 74 | } 75 | return nil 76 | } 77 | 78 | func calcSHA1(_ data : Data) -> Data { 79 | 80 | let digest = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) 81 | CC_SHA1((data as NSData).bytes, CC_LONG(data.count), digest!.mutableBytes.assumingMemoryBound(to: UInt8.self)) 82 | return digest! as Data 83 | } 84 | 85 | func getThumbprint() -> Data { 86 | 87 | return calcSHA1(data!) 88 | } 89 | 90 | func hexstringFromData(_ data : Data) -> String { 91 | 92 | return data.withUnsafeBytes { (bytes : UnsafePointer) -> String in 93 | var str : String = "" 94 | var dataBytes = bytes 95 | for _ in 0 ..< data.count { 96 | str += NSString(format: "%02x", dataBytes.pointee) as String 97 | dataBytes = dataBytes.successor() 98 | } 99 | return str 100 | } 101 | } 102 | 103 | func getThumbprintAsHexString() -> String { 104 | return hexstringFromData(getThumbprint()) 105 | } 106 | 107 | func export(_ url : URL) -> Bool { 108 | var result = false 109 | if let cert = certificate { 110 | var outData : CFData? 111 | let status = SecItemExport(cert, SecExternalFormat.formatUnknown, SecItemImportExportFlags.pemArmour, nil, &outData) 112 | if status == errSecSuccess { 113 | if let cdata = outData { 114 | let data = cdata as Data 115 | result = (try? data.write(to: url, options: [])) != nil 116 | } 117 | } 118 | } 119 | return result 120 | } 121 | } 122 | 123 | class DCSimulatorTruststore { 124 | 125 | init (path : String) { 126 | self.path = path 127 | items = [DCSimulatorTruststoreItem]() 128 | } 129 | 130 | private var path : String 131 | 132 | private(set) var items : [DCSimulatorTruststoreItem] 133 | 134 | func openTrustStore() { 135 | 136 | var database : OpaquePointer? = nil 137 | var result = sqlite3_open(path.cString(using: String.Encoding.utf8)!, &database) 138 | if result == SQLITE_OK { 139 | var sqlStatements : OpaquePointer? = nil 140 | result = sqlite3_prepare(database, "SELECT sha1, subj, tset, data FROM tsettings", -1, &sqlStatements, nil) 141 | if result == SQLITE_OK { 142 | while (sqlite3_step(sqlStatements) == SQLITE_ROW) 143 | { 144 | var dataLength = sqlite3_column_bytes(sqlStatements, 0); 145 | if (dataLength > 0) 146 | { 147 | let blobData = sqlite3_column_blob(sqlStatements, 0) 148 | let sha1 = Data(bytes: blobData!, count: Int(dataLength)) 149 | 150 | var subj : Data?; 151 | var tset : Data?; 152 | var data : Data?; 153 | 154 | dataLength = sqlite3_column_bytes(sqlStatements, 1); 155 | if dataLength > 0 { 156 | if let blobData = sqlite3_column_blob(sqlStatements, 1) { 157 | subj = Data(bytes: blobData, count: Int(dataLength)) 158 | } 159 | } 160 | dataLength = sqlite3_column_bytes(sqlStatements, 2); 161 | if dataLength > 0 { 162 | if let blobData = sqlite3_column_blob(sqlStatements, 2) { 163 | tset = Data(bytes: blobData, count: Int(dataLength)) 164 | } 165 | } 166 | dataLength = sqlite3_column_bytes(sqlStatements, 3); 167 | if dataLength > 0 { 168 | if let blobData = sqlite3_column_blob(sqlStatements, 3) { 169 | data = Data(bytes: blobData, count: Int(dataLength)) 170 | } 171 | 172 | let item = DCSimulatorTruststoreItem(sha1: sha1, subject: subj, tset: tset, data: data) 173 | items.append(item) 174 | } 175 | } 176 | } 177 | } 178 | if sqlStatements != nil { 179 | sqlite3_finalize(sqlStatements); 180 | } 181 | } 182 | if database != nil { 183 | sqlite3_close(database) 184 | } 185 | } 186 | 187 | func removeItem(_ index : Int) -> Bool { 188 | var success = false 189 | if index >= 0 && index < items.count { 190 | let item = items[index] 191 | 192 | let certificateSha1 = item.getThumbprintAsHexString().uppercased().cString(using: String.Encoding.utf8)! 193 | 194 | var database : OpaquePointer? = nil 195 | var result = sqlite3_open(path.cString(using: String.Encoding.utf8)!, &database) 196 | if result == SQLITE_OK { 197 | var sqlStatements : OpaquePointer? = nil 198 | result = sqlite3_prepare_v2(database, "DELETE FROM tsettings WHERE hex(sha1)=?", -1, &sqlStatements, nil) 199 | if result == SQLITE_OK { 200 | 201 | result = sqlite3_bind_text(sqlStatements, 1, certificateSha1, -1, nil) // SQLITE_TRANSIENT); 202 | if result == SQLITE_OK { 203 | result = sqlite3_step(sqlStatements); 204 | if result == SQLITE_DONE { 205 | if (sqlite3_changes(database) > 0) { 206 | items.remove(at: index) 207 | success = true 208 | } 209 | else { 210 | NSLog("Could not remove the certificate \(item.subjectSummary) from TrustStore.sqlite3") 211 | } 212 | } 213 | else { 214 | NSLog("Error (sqlite3 code:\(result)) removing the certificate \(item.subjectSummary) from TrustStore.sqlite3") 215 | } 216 | } 217 | } 218 | if sqlStatements != nil { 219 | sqlite3_finalize(sqlStatements); 220 | } 221 | } 222 | if database != nil { 223 | sqlite3_close(database); 224 | } 225 | } 226 | return success 227 | } 228 | 229 | func addItem(_ item : DCSimulatorTruststoreItem) -> Bool { 230 | 231 | var success = false 232 | var database : OpaquePointer? = nil 233 | var result = sqlite3_open(path.cString(using: String.Encoding.utf8)!, &database) 234 | if result == SQLITE_OK { 235 | var sqlStatements : OpaquePointer? = nil 236 | result = sqlite3_prepare_v2(database, "INSERT INTO tsettings (sha1, subj, tset, data) VALUES (?, ?, ?, ?)", -1, &sqlStatements, nil) 237 | 238 | if result == SQLITE_OK { 239 | result = sqlite3_bind_blob(sqlStatements, 1, (item.sha1! as NSData).bytes, Int32(item.sha1!.count), nil) //SQLITE_TRANSIENT); 240 | result = sqlite3_bind_blob(sqlStatements, 2, (item.subject! as NSData).bytes, Int32(item.subject!.count), nil) // SQLITE_STATIC); 241 | result = sqlite3_bind_blob(sqlStatements, 3, (item.tset! as NSData).bytes, Int32(item.tset!.count), nil) // SQLITE_STATIC); 242 | result = sqlite3_bind_blob(sqlStatements, 4, (item.data! as NSData).bytes, Int32(item.data!.count), nil) //SQLITE_STATIC); 243 | if result == SQLITE_OK { 244 | result = sqlite3_step(sqlStatements); 245 | if result == SQLITE_DONE { 246 | if sqlite3_changes(database) > 0 { 247 | items.append(item); 248 | success = true 249 | } 250 | else { 251 | NSLog("Could not add the certificate \(item.subjectSummary) to TrustStore.sqlite3") 252 | } 253 | } 254 | else 255 | { 256 | //TODO: result == SQLITE_CONSTRAINT (19) -> due to already existing item: show a message box for this 257 | NSLog("Error (sqlite3 code:\(result)) adding the certificate \(item.subjectSummary) to TrustStore.sqlite3") 258 | } 259 | } 260 | } 261 | if sqlStatements != nil { 262 | sqlite3_finalize(sqlStatements); 263 | } 264 | } 265 | if database != nil { 266 | sqlite3_close(database); 267 | } 268 | return success 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCSimulatorTrustStoreViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCSimulatorTrustStoreViewController.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 10.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | // 9 | 10 | import Cocoa 11 | import SecurityInterface 12 | 13 | class DCSimulatorTrustStoreViewController: DCSimulatorViewController, NSTableViewDataSource, NSTableViewDelegate { 14 | 15 | @IBOutlet weak var notavailableInfoTextField: NSTextField! 16 | @IBOutlet weak var tableScrollView: NSScrollView! 17 | @IBOutlet weak var tableView: NSTableView! 18 | @IBOutlet weak var importServerButton: NSButton! 19 | @IBOutlet weak var importFileButton: NSButton! 20 | @IBOutlet weak var removeButton: NSButton! 21 | @IBOutlet weak var exportButton: NSButton! 22 | 23 | var truststore : DCSimulatorTruststore? 24 | 25 | override var simulator : Simulator? { 26 | didSet { 27 | truststore = nil 28 | if let truststorePath = simulator?.trustStorePath { 29 | if FileManager.default.fileExists(atPath: truststorePath) { 30 | truststore = DCSimulatorTruststore(path : truststorePath) 31 | truststore!.openTrustStore() 32 | NSLog("Trustore has \(truststore!.items.count) items") 33 | } 34 | } 35 | tableView.reloadData() 36 | enableButtons() 37 | if simulator != nil && truststore == nil { 38 | // If we do not find the truststore.sqlite3 file it is usually because the simulator has not yet been run 39 | // indicate it with an appropriate message and hide the tableview 40 | notavailableInfoTextField.isHidden = false 41 | tableScrollView!.isHidden = true 42 | } 43 | else { 44 | notavailableInfoTextField.isHidden = true 45 | tableScrollView!.isHidden = false 46 | } 47 | } 48 | } 49 | 50 | 51 | override func loadView() { 52 | super.loadView() 53 | enableButtons() 54 | } 55 | 56 | func enableButtons() { 57 | let enableActionOnSelected = (tableView.selectedRow >= 0) 58 | let enableActionOnTrustStore = (truststore != nil) 59 | removeButton.isEnabled = enableActionOnSelected 60 | exportButton.isEnabled = enableActionOnSelected 61 | importServerButton.isEnabled = enableActionOnTrustStore 62 | importFileButton.isEnabled = enableActionOnTrustStore 63 | } 64 | 65 | 66 | func numberOfRows(in tableView: NSTableView) -> Int { 67 | 68 | return truststore?.items.count ?? 0 69 | } 70 | 71 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 72 | if let result = tableView.make(withIdentifier: "DataCell", owner: self) as? NSTableCellView { 73 | if truststore != nil { 74 | if let text = truststore?.items[row].subjectSummary { 75 | result.textField!.stringValue = text 76 | } 77 | } 78 | return result 79 | } 80 | return nil 81 | } 82 | 83 | func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { 84 | return nil; 85 | } 86 | 87 | @IBAction func viewCertificateButtonPressed(_ sender: NSButton) { 88 | if let cellView = sender.superview as? NSTableCellView { 89 | let row = tableView.row(for: cellView) 90 | if row >= 0 { 91 | tableView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) 92 | if let cert = truststore?.items[row].certificate { 93 | showCertificate(cert) 94 | } 95 | } 96 | } 97 | return; 98 | } 99 | 100 | func showCertificate(_ cert : SecCertificate) { 101 | SFCertificatePanel.shared().runModal(forCertificates: [cert], showGroup: false) 102 | } 103 | 104 | @IBAction func importCertificateFromServerButtonPressed(_ sender: AnyObject) { 105 | 106 | let importPanel = DCImportCertificateWindowController(windowNibName: "DCImportCertificateWindowController") 107 | let result = NSApplication.shared().runModal(for: importPanel.window!) 108 | if result == 0 { 109 | if importPanel.certificate != nil { 110 | let item = DCSimulatorTruststoreItem(certificate: importPanel.certificate!) 111 | if truststore!.addItem(item) { 112 | tableView.reloadData() 113 | enableButtons() 114 | } 115 | } 116 | } 117 | NSLog("Modal close: \(result)") 118 | return; 119 | 120 | } 121 | 122 | @IBAction func importCertificateFromFile(_ sender: AnyObject) { 123 | let openPanel = NSOpenPanel() 124 | openPanel.canChooseFiles = true 125 | openPanel.canChooseDirectories = false 126 | openPanel.allowsMultipleSelection = false 127 | 128 | if openPanel.runModal() == NSFileHandlingPanelOKButton { 129 | for url in openPanel.urls { 130 | if let data = try? Data(contentsOf: url) { 131 | 132 | var format : SecExternalFormat = SecExternalFormat.formatUnknown 133 | var itemType : SecExternalItemType = SecExternalItemType.itemTypeCertificate 134 | //var outItems : Unmanaged? 135 | var outItems : CFArray? 136 | //var outItems : UnsafeMutablePointer 137 | 138 | SecItemImport(data as CFData, nil, &format, &itemType, SecItemImportExportFlags(rawValue: 0), nil, nil, &outItems) 139 | //if let itemCFArray = outItems?.takeRetainedValue() { 140 | if let itemCFArray = outItems { 141 | let itemArray = itemCFArray as NSArray 142 | if itemArray.count > 0 && itemType == SecExternalItemType.itemTypeCertificate { 143 | 144 | // Here we must use an unconditional downcast (conditional downcast does not work here). 145 | let item = DCSimulatorTruststoreItem(certificate: itemArray[0] as! SecCertificate) 146 | 147 | if truststore!.addItem(item) { 148 | tableView.reloadData() 149 | } 150 | } 151 | } 152 | } 153 | } 154 | } 155 | } 156 | 157 | @IBAction func removeCertificateButtonPressed(_ sender: AnyObject) { 158 | if tableView.selectedRow >= 0 { 159 | if truststore != nil { 160 | if truststore!.removeItem(tableView.selectedRow) { 161 | tableView.reloadData() 162 | enableButtons() 163 | } 164 | } 165 | } 166 | } 167 | 168 | @IBAction func exportButtonPressed(_ sender: AnyObject) { 169 | if tableView.selectedRow >= 0 { 170 | if truststore != nil { 171 | let item = truststore!.items[tableView.selectedRow] 172 | let savePanel = NSSavePanel() 173 | if let text = item.subjectSummary { 174 | savePanel.nameFieldStringValue = text 175 | } 176 | if savePanel.runModal() == NSFileHandlingPanelOKButton { 177 | if let url = savePanel.url { 178 | item.export(url) 179 | } 180 | } 181 | } 182 | } 183 | } 184 | 185 | func tableViewSelectionDidChange(_ notification: Notification) { 186 | enableButtons() 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /iSimulatorExplorer/DCXCodeSupport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DCXCodeSupport.swift 3 | // iSimulatorExplorer 4 | // 5 | // Created by Daniel Cerutti on 06.10.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 8 | 9 | import Foundation 10 | 11 | class XCodeSupport { 12 | class func getDeveloperToolsPath() -> String? { 13 | if let developerDir = ProcessInfo.processInfo.environment["DEVELOPER_DIR"] { 14 | return developerDir 15 | } 16 | if let symDir = try? FileManager.default.destinationOfSymbolicLink(atPath: "/var/db/xcode_select_link") { 17 | return symDir 18 | } 19 | let defaultDir = "/Applications/Xcode.app/Contents/Developer" 20 | if FileManager.default.fileExists(atPath: defaultDir) { 21 | return defaultDir 22 | } 23 | return nil 24 | } 25 | 26 | class func getDeveloperToolsVersion() -> String? { 27 | if let developerDir = getDeveloperToolsPath() { 28 | let fm = FileManager.default 29 | let versionPlist = (developerDir as NSString).appendingPathComponent("../version.plist") 30 | if fm.fileExists(atPath: versionPlist) { 31 | let versionPlistData = FileManager.default.contents(atPath: versionPlist)! 32 | do { 33 | let plistobj: AnyObject? = try PropertyListSerialization.propertyList(from: versionPlistData, 34 | options: PropertyListSerialization.ReadOptions(rawValue: 0), 35 | format: nil) as AnyObject? 36 | if let plist = plistobj as? Dictionary { 37 | return plist["CFBundleShortVersionString"] as? String 38 | } 39 | } 40 | catch let error as NSError { 41 | NSLog("Error reading developer tools version: %@", error) 42 | } 43 | } 44 | } 45 | return nil; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "iSimulatorExplorer7.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "iSimulatorExplorer6-1.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "iSimulatorExplorer6.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "iSimulatorExplorer5.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "iSimulatorExplorer4.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "iSimulatorExplorer3-1.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "iSimulatorExplorer3.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "iSimulatorExplorer2-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "iSimulatorExplorer2.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "iSimulatorExplorer1.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer1.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer2-1.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer2.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer3-1.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer3.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer4.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer5.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer6-1.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer6.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/AppIcon.appiconset/iSimulatorExplorer7.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/Simulator.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Simulator1.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "Simulator2.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "Simulator3.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator1.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator2.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/Simulator.imageset/Simulator3.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/ViewDetail.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "view-32.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "view-64.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/ViewDetail.imageset/view-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/ViewDetail.imageset/view-32.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Images.xcassets/ViewDetail.imageset/view-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/iSimulatorExplorer/Images.xcassets/ViewDetail.imageset/view-64.png -------------------------------------------------------------------------------- /iSimulatorExplorer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | ${MACOSX_DEPLOYMENT_TARGET} 25 | NSHumanReadableCopyright 26 | Copyright © 2014 Daniel Cerutti. All rights reserved. 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /iSimulatorExplorer/iSimulatorExplorer-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | #import "CoreSimulator.h" 7 | #import "sqlite3.h" 8 | #import "CommonCrypto/CommonDigest.h" 9 | #import 10 | #import "CoreSimulatorWrapper.h" 11 | -------------------------------------------------------------------------------- /iSimulatorExplorerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /iSimulatorExplorerTests/iSimulatorExplorerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // iSimulatorExplorerTests.swift 3 | // iSimulatorExplorerTests 4 | // 5 | // Created by Daniel Cerutti on 30.07.14. 6 | // Copyright (c) 2014 Daniel Cerutti. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import XCTest 11 | 12 | class iSimulatorExplorerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /img/screen1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/img/screen1.jpg -------------------------------------------------------------------------------- /img/screen2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/img/screen2.jpg -------------------------------------------------------------------------------- /img/screen3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-c/iSimulatorExplorer/a6c589b989ebb85fd8b71f7196da79a24caddf78/img/screen3.jpg --------------------------------------------------------------------------------