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);
BOOL bit_isPreiOS7Environment(void);
NSString *bit_validAppIconStringFromIcons(NSArray *icons);
NSString *bit_validAppIconFilename(NSBundle *bundle);
NSString *bit_validAppIconStringFromIcons(NSBundle *resourceBundle, NSArray *icons);
NSString *bit_validAppIconFilename(NSBundle *bundle, NSBundle *resourceBundle);
/* UIImage helpers */
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
*/
NSString *bit_validAppIconStringFromIcons(NSArray *icons) {
NSString *bit_validAppIconStringFromIcons(NSBundle *resourceBundle, NSArray *icons) {
if (!icons) return nil;
if (![icons isKindOfClass:[NSArray class]]) return nil;
@ -267,16 +267,29 @@ NSString *bit_validAppIconStringFromIcons(NSArray *icons) {
for(NSString *icon in icons) {
// 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)
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) {
if (iconImage.size.height == bestMatchHeight) {
return icon;
} else if (iconImage.size.height < bestMatchHeight &&
iconImage.size.height > currentBestMatchHeight) {
currentBestMatchHeight = iconImage.size.height;
currentBestMatch = icon;
[iconFilenameVariants addObject:[icon stringByDeletingPathExtension]];
[iconFilenameVariants addObject:[NSString stringWithFormat:@"%@@2x", [icon stringByDeletingPathExtension]]];
for (NSString *iconFilename in iconFilenameVariants) {
// this call already covers "~ipad" files
NSString *iconPath = [resourceBundle pathForResource:iconFilename ofType:iconPathExtension];
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;
}
NSString *bit_validAppIconFilename(NSBundle *bundle) {
NSString *bit_validAppIconFilename(NSBundle *bundle, NSBundle *resourceBundle) {
NSString *iconFilename = nil;
NSArray *icons = nil;
icons = [bundle objectForInfoDictionaryKey:@"CFBundleIconFiles"];
iconFilename = bit_validAppIconStringFromIcons(icons);
iconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
if (!iconFilename) {
icons = [bundle objectForInfoDictionaryKey:@"CFBundleIcons"];
if (icons && [icons isKindOfClass:[NSDictionary class]]) {
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
@ -305,7 +318,7 @@ NSString *bit_validAppIconFilename(NSBundle *bundle) {
if (icons && [icons isKindOfClass:[NSDictionary class]]) {
icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"];
}
NSString *iPadIconFilename = bit_validAppIconStringFromIcons(icons);
NSString *iPadIconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
if (iPadIconFilename && !iconFilename) {
iconFilename = iPadIconFilename;
}
@ -314,12 +327,12 @@ NSString *bit_validAppIconFilename(NSBundle *bundle) {
if (!iconFilename) {
NSString *tempFilename = [bundle objectForInfoDictionaryKey:@"CFBundleIconFile"];
if (tempFilename) {
iconFilename = bit_validAppIconStringFromIcons(@[tempFilename]);
iconFilename = bit_validAppIconStringFromIcons(resourceBundle, @[tempFilename]);
}
}
if (!iconFilename) {
iconFilename = bit_validAppIconStringFromIcons(@[@"Icon.png"]);
iconFilename = bit_validAppIconStringFromIcons(resourceBundle, @[@"Icon.png"]);
}
return iconFilename;

View File

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

View File

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