Permalink
Browse files

1.5

- First version published on Mac App Store.
- Include version number in generated files.
- Remembers the Web server publishing location for IPA files.
- Support for HTML template files - just replace the index_template.html file in the Application Support directory with your own.
- Several bugfixes and small improvements.

Thanks to chrisy, stoulouse, and rbochet for your submissions and code.
  • Loading branch information...
1 parent 1406b70 commit c36b24589a0d020051667d2f0ef3e69248462111 @HunterHillegas committed Jan 18, 2011
View
@@ -39,6 +39,8 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>2</string>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
View
@@ -8,7 +8,7 @@
/*
iOS BetaBuilder - a tool for simpler iOS betas
- Version 1.0, August 2010
+ Version 1.5, January 2011
Condition of use and distribution:
View
@@ -8,7 +8,7 @@
/*
iOS BetaBuilder - a tool for simpler iOS betas
- Version 1.0, August 2010
+ Version 1.5, January 2011
Condition of use and distribution:
@@ -32,6 +32,8 @@
#import "BetaBuilderAppDelegate.h"
#import "BuilderController.h"
+#import "NSFileManager+DirectoryLocations.h"
+
@implementation BetaBuilderAppDelegate
@synthesize window;
@@ -40,7 +42,22 @@ @implementation BetaBuilderAppDelegate
@synthesize builderController;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
- // Insert code here to initialize your application
+ //Copy HTML Template to App Support
+ NSString *applicationSupportPath = [[NSFileManager defaultManager] applicationSupportDirectory];
+ NSString *htmlTemplatePath = [applicationSupportPath stringByAppendingPathComponent:@"index_template.html"];
+
+ NSString *defaultTemplatePath = [[NSBundle mainBundle] pathForResource:@"index_template" ofType:@"html"];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+
+ if (![fileManager fileExistsAtPath:htmlTemplatePath]) {
+ NSLog(@"Copying Index Template");
+
+ if (defaultTemplatePath) {
+ [fileManager copyItemAtPath:defaultTemplatePath toPath:htmlTemplatePath error:nil];
+ }
+ } else {
+ NSLog(@"Index Template Already Exists - Not Copying From Bundle");
+ }
}
- (IBAction)showDeploymentHelpPanel:(id)sender {
View
@@ -59,4 +59,7 @@
- (void)setupFromIPAFile:(NSString *)ipaFilename;
+- (void)populateFieldsFromHistoryForBundleID:(NSString *)bundleID;
+- (void)storeFieldsInHistoryForBundleID:(NSString *)bundleID;
+
@end
View
@@ -29,6 +29,8 @@
3. This notice may not be removed or altered from any source distribution.
*/
+#import "NSFileManager+DirectoryLocations.h"
+
#import "BuilderController.h"
#import "ZipArchive.h"
@@ -101,6 +103,8 @@ - (void)setupFromIPAFile:(NSString *)ipaFilename {
[bundleVersionField setStringValue:[bundlePlistFile valueForKey:@"CFBundleVersion"]];
[bundleIdentifierField setStringValue:[bundlePlistFile valueForKey:@"CFBundleIdentifier"]];
[bundleNameField setStringValue:[bundlePlistFile valueForKey:@"CFBundleDisplayName"]];
+
+ [self populateFieldsFromHistoryForBundleID:[bundlePlistFile valueForKey:@"CFBundleIdentifier"]];
}
//set mobile provision file
@@ -111,6 +115,38 @@ - (void)setupFromIPAFile:(NSString *)ipaFilename {
[generateFilesButton setEnabled:YES];
}
+- (void)populateFieldsFromHistoryForBundleID:(NSString *)bundleID {
+ NSString *applicationSupportPath = [[NSFileManager defaultManager] applicationSupportDirectory];
+ NSString *historyPath = [applicationSupportPath stringByAppendingPathComponent:@"history.plist"];
+
+ NSDictionary *historyDictionary = [NSDictionary dictionaryWithContentsOfFile:historyPath];
+
+ if (historyDictionary) {
+ NSDictionary *historyItem = [historyDictionary valueForKey:bundleID];
+
+ if (historyItem) {
+ [webserverDirectoryField setStringValue:[historyItem valueForKey:@"webserverDirectory"]];
+ } else {
+ NSLog(@"No History Item Found for Bundle ID: %@", bundleID);
+ }
+ }
+}
+
+- (void)storeFieldsInHistoryForBundleID:(NSString *)bundleID {
+ NSString *applicationSupportPath = [[NSFileManager defaultManager] applicationSupportDirectory];
+ NSString *historyPath = [applicationSupportPath stringByAppendingPathComponent:@"history.plist"];
+
+ NSMutableDictionary *historyDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:historyPath];
+ if (!historyDictionary) {
+ historyDictionary = [NSMutableDictionary dictionary];
+ }
+
+ NSDictionary *webserverDirectoryDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[webserverDirectoryField stringValue], @"webserverDirectory", nil];
+ [historyDictionary setValue:webserverDirectoryDictionary forKey:bundleID];
+
+ [historyDictionary writeToFile:historyPath atomically:YES];
+}
+
- (IBAction)generateFiles:(id)sender {
//create plist
NSString *encodedIpaFilename = [[[archiveIPAFilenameField stringValue] lastPathComponent] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //this isn't the most robust way to do this
@@ -121,13 +157,26 @@ - (IBAction)generateFiles:(id)sender {
NSDictionary *outerManifestDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:innerManifestDictionary], @"items", nil];
NSLog(@"Manifest Created");
- //create html file
- NSString *templatePath = [[NSBundle mainBundle] pathForResource:@"index_template" ofType:@"html"];
+ //create html file
+ NSString *applicationSupportPath = [[NSFileManager defaultManager] applicationSupportDirectory];
+ NSString *templatePath = [applicationSupportPath stringByAppendingPathComponent:@"index_template.html"];
NSString *htmlTemplateString = [NSString stringWithContentsOfFile:templatePath encoding:NSUTF8StringEncoding error:nil];
htmlTemplateString = [htmlTemplateString stringByReplacingOccurrencesOfString:@"[BETA_NAME]" withString:[bundleNameField stringValue]];
htmlTemplateString = [htmlTemplateString stringByReplacingOccurrencesOfString:@"[BETA_VERSION]" withString:[bundleVersionField stringValue]];
htmlTemplateString = [htmlTemplateString stringByReplacingOccurrencesOfString:@"[BETA_PLIST]" withString:[NSString stringWithFormat:@"%@/%@", [webserverDirectoryField stringValue], @"manifest.plist"]];
+ //add formatted date
+ NSDateFormatter *shortDateFormatter = [[NSDateFormatter alloc] init];
+ [shortDateFormatter setTimeStyle:NSDateFormatterNoStyle];
+ [shortDateFormatter setDateStyle:NSDateFormatterMediumStyle];
+ NSString *formattedDateString = [shortDateFormatter stringFromDate:[NSDate date]];
+ [shortDateFormatter release];
+ htmlTemplateString = [htmlTemplateString stringByReplacingOccurrencesOfString:@"[BETA_DATE]" withString:formattedDateString];
+
+ //store history
+ if ([webserverDirectoryField stringValue])
+ [self storeFieldsInHistoryForBundleID:[bundleIdentifierField stringValue]];
+
//ask for save location
NSOpenPanel *directoryPanel = [NSOpenPanel openPanel];
[directoryPanel setCanChooseFiles:NO];
@@ -0,0 +1,27 @@
+//
+// NSFileManager+DirectoryLocations.h
+//
+// Created by Matt Gallagher on 06 May 2010
+//
+// Permission is given to use this source code file, free of charge, in any
+// project, commercial or otherwise, entirely at your risk, with the condition
+// that any redistribution (in part or whole) of source code must retain
+// this copyright and permission notice. Attribution in compiled projects is
+// appreciated but not required.
+//
+
+#import <Foundation/Foundation.h>
+
+//
+// DirectoryLocations is a set of global methods for finding the fixed location
+// directoriess.
+//
+@interface NSFileManager (DirectoryLocations)
+
+- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
+ inDomain:(NSSearchPathDomainMask)domainMask
+ appendPathComponent:(NSString *)appendComponent
+ error:(NSError **)errorOut;
+- (NSString *)applicationSupportDirectory;
+
+@end
@@ -0,0 +1,179 @@
+//
+// NSFileManager+DirectoryLocations.m
+//
+// Created by Matt Gallagher on 06 May 2010
+//
+// Permission is given to use this source code file, free of charge, in any
+// project, commercial or otherwise, entirely at your risk, with the condition
+// that any redistribution (in part or whole) of source code must retain
+// this copyright and permission notice. Attribution in compiled projects is
+// appreciated but not required.
+//
+
+#import "NSFileManager+DirectoryLocations.h"
+
+enum
+{
+ DirectoryLocationErrorNoPathFound,
+ DirectoryLocationErrorFileExistsAtLocation
+};
+
+NSString * const DirectoryLocationDomain = @"DirectoryLocationDomain";
+
+@implementation NSFileManager (DirectoryLocations)
+
+//
+// findOrCreateDirectory:inDomain:appendPathComponent:error:
+//
+// Method to tie together the steps of:
+// 1) Locate a standard directory by search path and domain mask
+// 2) Select the first path in the results
+// 3) Append a subdirectory to that path
+// 4) Create the directory and intermediate directories if needed
+// 5) Handle errors by emitting a proper NSError object
+//
+// Parameters:
+// searchPathDirectory - the search path passed to NSSearchPathForDirectoriesInDomains
+// domainMask - the domain mask passed to NSSearchPathForDirectoriesInDomains
+// appendComponent - the subdirectory appended
+// errorOut - any error from file operations
+//
+// returns the path to the directory (if path found and exists), nil otherwise
+//
+- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
+ inDomain:(NSSearchPathDomainMask)domainMask
+ appendPathComponent:(NSString *)appendComponent
+ error:(NSError **)errorOut
+{
+ //
+ // Search for the path
+ //
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(
+ searchPathDirectory,
+ domainMask,
+ YES);
+ if ([paths count] == 0)
+ {
+ if (errorOut)
+ {
+ NSDictionary *userInfo =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ NSLocalizedStringFromTable(
+ @"No path found for directory in domain.",
+ @"Errors",
+ nil),
+ NSLocalizedDescriptionKey,
+ [NSNumber numberWithInteger:searchPathDirectory],
+ @"NSSearchPathDirectory",
+ [NSNumber numberWithInteger:domainMask],
+ @"NSSearchPathDomainMask",
+ nil];
+ *errorOut =
+ [NSError
+ errorWithDomain:DirectoryLocationDomain
+ code:DirectoryLocationErrorNoPathFound
+ userInfo:userInfo];
+ }
+ return nil;
+ }
+
+ //
+ // Normally only need the first path returned
+ //
+ NSString *resolvedPath = [paths objectAtIndex:0];
+
+ //
+ // Append the extra path component
+ //
+ if (appendComponent)
+ {
+ resolvedPath = [resolvedPath
+ stringByAppendingPathComponent:appendComponent];
+ }
+
+ //
+ // Check if the path exists
+ //
+ BOOL exists;
+ BOOL isDirectory;
+ exists = [self
+ fileExistsAtPath:resolvedPath
+ isDirectory:&isDirectory];
+ if (!exists || !isDirectory)
+ {
+ if (exists)
+ {
+ if (errorOut)
+ {
+ NSDictionary *userInfo =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ NSLocalizedStringFromTable(
+ @"File exists at requested directory location.",
+ @"Errors",
+ nil),
+ NSLocalizedDescriptionKey,
+ [NSNumber numberWithInteger:searchPathDirectory],
+ @"NSSearchPathDirectory",
+ [NSNumber numberWithInteger:domainMask],
+ @"NSSearchPathDomainMask",
+ nil];
+ *errorOut =
+ [NSError
+ errorWithDomain:DirectoryLocationDomain
+ code:DirectoryLocationErrorFileExistsAtLocation
+ userInfo:userInfo];
+ }
+ return nil;
+ }
+
+ //
+ // Create the path if it doesn't exist
+ //
+ NSError *error = nil;
+ BOOL success = [self
+ createDirectoryAtPath:resolvedPath
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&error];
+ if (!success)
+ {
+ if (errorOut)
+ {
+ *errorOut = error;
+ }
+ return nil;
+ }
+ }
+
+ if (errorOut)
+ {
+ *errorOut = nil;
+ }
+ return resolvedPath;
+}
+
+//
+// applicationSupportDirectory
+//
+// Returns the path to the applicationSupportDirectory (creating it if it doesn't
+// exist).
+//
+- (NSString *)applicationSupportDirectory
+{
+ NSString *executableName =
+ [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
+ NSError *error;
+ NSString *result =
+ [self
+ findOrCreateDirectory:NSApplicationSupportDirectory
+ inDomain:NSUserDomainMask
+ appendPathComponent:executableName
+ error:&error];
+ if (!result)
+ {
+ NSLog(@"Unable to find or create application support directory:\n%@", error);
+ }
+ return result;
+}
+
+@end
View
@@ -11,7 +11,8 @@
p {font-size:13px;}
.link {background:#ecf5ff;border-top:1px solid #fff;border:1px solid #dfebf8;margin-top:.5em;padding:.3em;}
.link a {text-decoration:none;font-size:15px;display:block;color:#069;}
-
+.last_updated {font-size: x-small;text-align: right;font-style: italic;}
+.created_with {font-size: x-small;text-align: center;}
</style>
</head>
<body>
@@ -29,10 +30,14 @@
Reload this page via your computer browser and download a zipped archive and provisioning profile here:
</p>
-<div class="link"><a href="beta_archive.zip">[BETA_NAME] [BETA_VERSION]<br />Archive w/ Provisioning Profile</a></div>
+<div class="link"><a href="beta_archive.zip">Click Here to Download<br/>[BETA_NAME] [BETA_VERSION]<br />Archive Zip w/ Provisioning Profile</a></div>
<p>These files can then be used to install the beta via iTunes.</p>
-
+
+<p class="last_updated">Last Updated: [BETA_DATE]</p>
+
+<p class="created_with"><a href='http://www.hanchorllc.com/category/ios-betabuilder/'>Created With iOS BetaBuilder</a></p>
+
</div>
</body>

0 comments on commit c36b245

Please sign in to comment.