Fix some best app icon finding issues

In some cases the algorithm didn't find any icon, even if they are there
This commit is contained in:
Andreas Linde 2014-07-08 21:03:26 +02:00
parent 0181e8c724
commit 53edf21c5d
4 changed files with 40 additions and 26 deletions

View File

@ -48,8 +48,8 @@ NSString *bit_UUID(void);
NSString *bit_appAnonID(void); NSString *bit_appAnonID(void);
BOOL bit_isPreiOS7Environment(void); BOOL bit_isPreiOS7Environment(void);
NSString *bit_validAppIconStringFromIcons(NSArray *icons); NSString *bit_validAppIconStringFromIcons(NSBundle *resourceBundle, NSArray *icons);
NSString *bit_validAppIconFilename(NSBundle *bundle); NSString *bit_validAppIconFilename(NSBundle *bundle, NSBundle *resourceBundle);
/* UIImage helpers */ /* UIImage helpers */
UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize);

View File

@ -245,7 +245,7 @@ BOOL bit_isPreiOS7Environment(void) {
@return NSString with the valid app icon or nil if none found @return NSString with the valid app icon or nil if none found
*/ */
NSString *bit_validAppIconStringFromIcons(NSArray *icons) { NSString *bit_validAppIconStringFromIcons(NSBundle *resourceBundle, NSArray *icons) {
if (!icons) return nil; if (!icons) return nil;
if (![icons isKindOfClass:[NSArray class]]) return nil; if (![icons isKindOfClass:[NSArray class]]) return nil;
@ -267,16 +267,29 @@ NSString *bit_validAppIconStringFromIcons(NSArray *icons) {
for(NSString *icon in icons) { for(NSString *icon in icons) {
// Don't use imageNamed, otherwise unit tests won't find the fixture icon // Don't use imageNamed, otherwise unit tests won't find the fixture icon
// and using imageWithContentsOfFile doesn't load @2x files with absolut paths (required in tests) // and using imageWithContentsOfFile doesn't load @2x files with absolut paths (required in tests)
NSData *imgData = [[NSData alloc] initWithContentsOfFile:icon];
UIImage *iconImage = [[UIImage alloc] initWithData:imgData]; NSString *iconPathExtension = ([[icon pathExtension] length] > 0) ? [icon pathExtension] : @"png";
NSMutableArray *iconFilenameVariants = [NSMutableArray new];
if (iconImage) { [iconFilenameVariants addObject:[icon stringByDeletingPathExtension]];
if (iconImage.size.height == bestMatchHeight) { [iconFilenameVariants addObject:[NSString stringWithFormat:@"%@@2x", [icon stringByDeletingPathExtension]]];
return icon;
} else if (iconImage.size.height < bestMatchHeight && for (NSString *iconFilename in iconFilenameVariants) {
iconImage.size.height > currentBestMatchHeight) { // this call already covers "~ipad" files
currentBestMatchHeight = iconImage.size.height; NSString *iconPath = [resourceBundle pathForResource:iconFilename ofType:iconPathExtension];
currentBestMatch = icon;
NSData *imgData = [[NSData alloc] initWithContentsOfFile:iconPath];
UIImage *iconImage = [[UIImage alloc] initWithData:imgData];
if (iconImage) {
if (iconImage.size.height == bestMatchHeight) {
return iconFilename;
} else if (iconImage.size.height < bestMatchHeight &&
iconImage.size.height > currentBestMatchHeight) {
currentBestMatchHeight = iconImage.size.height;
currentBestMatch = iconFilename;
}
} }
} }
} }
@ -284,19 +297,19 @@ NSString *bit_validAppIconStringFromIcons(NSArray *icons) {
return currentBestMatch; return currentBestMatch;
} }
NSString *bit_validAppIconFilename(NSBundle *bundle) { NSString *bit_validAppIconFilename(NSBundle *bundle, NSBundle *resourceBundle) {
NSString *iconFilename = nil; NSString *iconFilename = nil;
NSArray *icons = nil; NSArray *icons = nil;
icons = [bundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]; icons = [bundle objectForInfoDictionaryKey:@"CFBundleIconFiles"];
iconFilename = bit_validAppIconStringFromIcons(icons); iconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
if (!iconFilename) { if (!iconFilename) {
icons = [bundle objectForInfoDictionaryKey:@"CFBundleIcons"]; icons = [bundle objectForInfoDictionaryKey:@"CFBundleIcons"];
if (icons && [icons isKindOfClass:[NSDictionary class]]) { if (icons && [icons isKindOfClass:[NSDictionary class]]) {
icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"]; icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"];
} }
iconFilename = bit_validAppIconStringFromIcons(icons); iconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
} }
// we test iPad structure anyway and use it if we find a result and don't have another one yet // we test iPad structure anyway and use it if we find a result and don't have another one yet
@ -305,7 +318,7 @@ NSString *bit_validAppIconFilename(NSBundle *bundle) {
if (icons && [icons isKindOfClass:[NSDictionary class]]) { if (icons && [icons isKindOfClass:[NSDictionary class]]) {
icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"]; icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"];
} }
NSString *iPadIconFilename = bit_validAppIconStringFromIcons(icons); NSString *iPadIconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
if (iPadIconFilename && !iconFilename) { if (iPadIconFilename && !iconFilename) {
iconFilename = iPadIconFilename; iconFilename = iPadIconFilename;
} }
@ -314,12 +327,12 @@ NSString *bit_validAppIconFilename(NSBundle *bundle) {
if (!iconFilename) { if (!iconFilename) {
NSString *tempFilename = [bundle objectForInfoDictionaryKey:@"CFBundleIconFile"]; NSString *tempFilename = [bundle objectForInfoDictionaryKey:@"CFBundleIconFile"];
if (tempFilename) { if (tempFilename) {
iconFilename = bit_validAppIconStringFromIcons(@[tempFilename]); iconFilename = bit_validAppIconStringFromIcons(resourceBundle, @[tempFilename]);
} }
} }
if (!iconFilename) { if (!iconFilename) {
iconFilename = bit_validAppIconStringFromIcons(@[@"Icon.png"]); iconFilename = bit_validAppIconStringFromIcons(resourceBundle, @[@"Icon.png"]);
} }
return iconFilename; return iconFilename;

View File

@ -294,7 +294,7 @@
} }
[self updateAppStoreHeader]; [self updateAppStoreHeader];
NSString *iconFilename = bit_validAppIconFilename([NSBundle mainBundle]); NSString *iconFilename = bit_validAppIconFilename([NSBundle mainBundle], [NSBundle mainBundle]);
if (iconFilename) { if (iconFilename) {
BOOL addGloss = YES; BOOL addGloss = YES;
NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"]; NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"];

View File

@ -93,8 +93,9 @@
- (void)testValidAppIconFilename { - (void)testValidAppIconFilename {
NSString *resultString = nil; NSString *resultString = nil;
NSBundle *mockBundle = mock([NSBundle class]); NSBundle *mockBundle = mock([NSBundle class]);
NSString *validIconPath = [[NSBundle bundleForClass:self.class] pathForResource:@"AppIcon" ofType:@"png"]; NSBundle *resourceBundle = [NSBundle bundleForClass:self.class];
NSString *validIconPath2x = [[NSBundle bundleForClass:self.class] pathForResource:@"AppIcon@2x" ofType:@"png"]; NSString *validIconPath = @"AppIcon";
NSString *validIconPath2x = @"AppIcon@2x";
// No valid icons defined at all // No valid icons defined at all
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:nil];
@ -102,7 +103,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:@"invalidFilename.png"]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:@"invalidFilename.png"];
resultString = bit_validAppIconFilename(mockBundle); resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, nilValue()); assertThat(resultString, nilValue());
// CFBundleIconFiles contains valid filenames // CFBundleIconFiles contains valid filenames
@ -111,7 +112,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle); resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue()); assertThat(resultString, notNilValue());
// CFBundleIcons contains valid dictionary filenames // CFBundleIcons contains valid dictionary filenames
@ -126,7 +127,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:@{@"CFBundlePrimaryIcon":@{@"CFBundleIconFiles":@[validIconPath, validIconPath2x]}}]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:@{@"CFBundlePrimaryIcon":@{@"CFBundleIconFiles":@[validIconPath, validIconPath2x]}}];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle); resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue()); assertThat(resultString, notNilValue());
// CFBundleIcons contains valid filenames // CFBundleIcons contains valid filenames
@ -135,7 +136,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle); resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue()); assertThat(resultString, notNilValue());
// CFBundleIcon contains valid filename // CFBundleIcon contains valid filename
@ -144,7 +145,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:validIconPath]; [given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:validIconPath];
resultString = bit_validAppIconFilename(mockBundle); resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue()); assertThat(resultString, notNilValue());
} }