Skip to content

Commit

Permalink
Add support for providing simulator by name.
Browse files Browse the repository at this point in the history
Closes #4
CC #3
  • Loading branch information
LeoNatan committed Apr 18, 2017
1 parent 849dcd3 commit 8ebe7d6
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ brew install --HEAD applesimutils
## Usage

```shell
Usage: applesimutils --simulator <simulator identifier> --bundle <bundle identifier> --setPermissions "<permission1>, <permission1>, ..."
applesimutils --simulator <simulator identifier> --restartSB
Usage: applesimutils --simulator <simulator name/identifier> --bundle <bundle identifier> --setPermissions "<permission1>, <permission1>, ..."
applesimutils --simulator <simulator name/identifier> --restartSB

Options:
--simulator The simulator identifier
--simulator The simulator identifier or simulator name
--bundle The app bundle identifier
--setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect
--restartSB Restarts SpringBoard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--simulator 9446E8CE-9559-4D13-AB75-E7EED7EDA36A"
argument = "--simulator &quot;iPhone 6s Plus&quot;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
Expand All @@ -80,7 +80,7 @@
</CommandLineArgument>
<CommandLineArgument
argument = "--help"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
Expand Down
1 change: 1 addition & 0 deletions applesimutils/applesimutils/SetServicePermission.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

@interface SetServicePermission : NSObject

+ (BOOL)isSimulatorReadyForPersmissions:(NSString*)simulatorId;
+ (void)setPermisionEnabled:(BOOL)enabled forService:(NSString*)service bundleIdentifier:(NSString*)bundleIdentifier simulatorIdentifier:(NSString*)simulatorId;

@end
12 changes: 10 additions & 2 deletions applesimutils/applesimutils/SetServicePermission.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ + (NSURL *)_libraryURLForSimulatorId:(NSString*)simulatorId

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
userLibraryURL = [NSURL URLWithString:NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject];
userLibraryURL = [NSURL fileURLWithPath:NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject];
userLibraryURL = [[[userLibraryURL URLByAppendingPathComponent:@"/Developer/CoreSimulator/Devices/"] URLByAppendingPathComponent:simulatorId] URLByAppendingPathComponent:@"data/Library/"];
});

Expand All @@ -47,7 +47,8 @@ + (BOOL)_changeAccessToService:(NSString*)service

NSURL* tccURL = [self _tccPathForSimulatorId:simulatorId];

if ([tccURL checkResourceIsReachableAndReturnError:NULL])
NSError* err;
if ([tccURL checkResourceIsReachableAndReturnError:&err] == NO)
{
continue;
}
Expand Down Expand Up @@ -77,4 +78,11 @@ + (void)setPermisionEnabled:(BOOL)enabled forService:(NSString*)service bundleId
[self _changeAccessToService:service simulatorId:simulatorId bundleIdentifier:bundleIdentifier allowed:enabled];
}

+ (BOOL)isSimulatorReadyForPersmissions:(NSString *)simulatorId
{
NSURL* tccURL = [self _tccPathForSimulatorId:simulatorId];

return [tccURL checkResourceIsReachableAndReturnError:NULL];
}

@end
132 changes: 128 additions & 4 deletions applesimutils/applesimutils/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ static void printUsage(NSString* prependMessage)
LNLog(@"%@\n", prependMessage);
}

LNLog(@"Usage: %@ --simulator <simulator identifier> --bundle <bundle identifier> --setPermissions \"<permission1>, <permission1>, ...\"", utilName);
LNLog(@" %@ --simulator <simulator identifier> --restartSB", utilName);
LNLog(@"Usage: %@ --simulator <simulator name/identifier> --bundle <bundle identifier> --setPermissions \"<permission1>, <permission1>, ...\"", utilName);
LNLog(@" %@ --simulator <simulator name/identifier> --restartSB", utilName);
LNLog(@"");
LNLog(@"Options:");
LNLog(@" --simulator The simulator identifier");
LNLog(@" --simulator The simulator identifier or simulator name");
LNLog(@" --bundle The app bundle identifier");
LNLog(@" --setPermissions Sets the specified permissions and restarts SpringBoard for the changes to take effect");
LNLog(@" --restartSB Restarts SpringBoard");
Expand All @@ -61,6 +61,26 @@ static void printUsage(NSString* prependMessage)
LNLog(@"Pull-requests are always welcome!");
}



static void bootSimulator(NSString* simulatorId)
{
NSTask* rebootTask = [NSTask new];
rebootTask.launchPath = @"/usr/bin/xcrun";
rebootTask.arguments = @[@"simctl", @"boot", simulatorId];
[rebootTask launch];
[rebootTask waitUntilExit];
}

static void shutdownSimulator(NSString* simulatorId)
{
NSTask* rebootTask = [NSTask new];
rebootTask.launchPath = @"/usr/bin/xcrun";
rebootTask.arguments = @[@"simctl", @"shutdown", simulatorId];
[rebootTask launch];
[rebootTask waitUntilExit];
}

static void restartSpringBoard(NSString* simulatorId)
{
NSTask* rebootTask = [NSTask new];
Expand All @@ -70,6 +90,50 @@ static void restartSpringBoard(NSString* simulatorId)
[rebootTask waitUntilExit];
}

static NSArray* simulatorDevicesList()
{
NSTask* rebootTask = [NSTask new];
rebootTask.launchPath = @"/usr/bin/xcrun";
rebootTask.arguments = @[@"simctl", @"list", @"--json"];

NSPipe * out = [NSPipe pipe];
[rebootTask setStandardOutput:out];

[rebootTask launch];
[rebootTask waitUntilExit];

NSFileHandle* readFileHandle = [out fileHandleForReading];
NSData* jsonData = [readFileHandle readDataToEndOfFile];

NSError* error;
NSDictionary* list = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];

if(list == nil)
{
printUsage(error.localizedDescription);

return nil;
}

NSArray* runtimes = [list[@"runtimes"] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"availability == \"(available)\""]];
// NSArray* deviceTypes = list[@"devicetypes"];
NSDictionary* devices = list[@"devices"];

NSMutableArray* allDevices = [NSMutableArray new];

[runtimes enumerateObjectsUsingBlock:^(NSDictionary<NSString*, id>* _Nonnull runtime, NSUInteger idx, BOOL * _Nonnull stop) {
NSString* runtimeName = runtime[@"name"];
NSArray* runtimeDevices = [devices[runtimeName] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"availability == \"(available)\""]];
[runtimeDevices setValue:runtime forKey:@"os"];
[allDevices addObjectsFromArray:runtimeDevices];
}];

return [allDevices sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"os.name" ascending:YES comparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}]]];
}


/*
As of iOS 10.3:
Expand Down Expand Up @@ -174,10 +238,65 @@ int main(int argc, char** argv) {
NSString* simulatorId = [settings objectForKey:@"simulator"];
if(simulatorId.length == 0)
{
printUsage(@"Error: No simulator identifier provided");
printUsage(@"Error: No simulator provided");

return -1;
}

NSArray* simulatorDevices = simulatorDevicesList();

if([[NSUUID alloc] initWithUUIDString:simulatorId] == nil)
{
NSString* simulatorFilterRequest = simulatorId;

if(simulatorDevices == nil)
{
return -1;
}

NSRange range = [simulatorFilterRequest rangeOfString:@",OS=" options:NSBackwardsSearch];
NSPredicate* filterPredicate;

if(range.location != NSNotFound)
{
NSString* simName = [simulatorFilterRequest substringToIndex:range.location];
//Add 4 for the length of ",OS="
NSString* osVer = [simulatorFilterRequest substringFromIndex:range.location + 4];

filterPredicate = [NSPredicate predicateWithFormat:@"name ==[cd] %@ && os.version ==[cd] %@", simName, osVer];
}
else
{
NSString* simName = simulatorId;

filterPredicate = [NSPredicate predicateWithFormat:@"name ==[cd] %@", simName];
}

simulatorId = [[simulatorDevices filteredArrayUsingPredicate:filterPredicate] lastObject][@"udid"];

if(simulatorId.length == 0)
{
printUsage([NSString stringWithFormat:@"Error: No simulator found matching \"%@\"", simulatorFilterRequest]);

return -1;
}
}

NSDictionary* simulator = [[simulatorDevices filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"udid == %@", simulatorId]] firstObject];
if(simulator == nil)
{
printUsage([NSString stringWithFormat:@"Error: Simulator with identifier \"%@\" not found", simulatorId]);

return -1;
}

BOOL needsSimShutdown = NO;
if([simulator[@"state"] isEqualToString:@"Shutdown"] && [SetServicePermission isSimulatorReadyForPersmissions:simulatorId] == NO)
{
needsSimShutdown = YES;

bootSimulator(simulatorId);
}

BOOL needsSpringBoardRestart = NO;

Expand Down Expand Up @@ -206,6 +325,11 @@ int main(int argc, char** argv) {
{
restartSpringBoard(simulatorId);
}

if(needsSimShutdown)
{
shutdownSimulator(simulatorId);
}
}
return 0;
}

0 comments on commit 8ebe7d6

Please sign in to comment.