Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3185,32 +3185,65 @@ private String buildLocalizedIconSelectorObjC() {
mapping.append("@\"").append(entry.getValue()).append("\": @\"").append(entry.getKey()).append("\"");
}
mapping.append(" }");
// Wait for UIApplicationDidBecomeActiveNotification before calling
// -[UIApplication setAlternateIconName:]. Calling from didFinishLaunching --
// even via dispatch_async on the main queue -- routinely fails with
// NSCocoaErrorDomain Code=3072 ("operation was cancelled") because the
// system alert iOS shows for an icon change has no active foreground scene
// to anchor to yet. Deferring to the active state fixes the silent failure
// that the user reported on top of #4870. The completion handler is wired
// up so any remaining bundle-configuration problem surfaces in the device
// log instead of being swallowed (the original nil handler hid this).
return "\n // Codename One localized app icon selection\n"
+ " if ([[UIApplication sharedApplication] respondsToSelector:@selector(setAlternateIconName:completionHandler:)]) {\n"
+ " NSDictionary *cn1LocalizedIcons =\n"
+ mapping + ";\n"
+ " NSString *cn1CurrentIcon = [[UIApplication sharedApplication] alternateIconName];\n"
+ " NSString *cn1TargetIcon = nil;\n"
+ " NSArray *cn1PrefLangs = [NSLocale preferredLanguages];\n"
+ " if (cn1PrefLangs.count > 0) {\n"
+ " NSString *cn1PrefLang = [cn1PrefLangs objectAtIndex:0];\n"
+ " NSArray *cn1LangParts = [cn1PrefLang componentsSeparatedByCharactersInSet:\n"
+ " [NSCharacterSet characterSetWithCharactersInString:@\"-_\"]];\n"
+ " if (cn1LangParts.count >= 2) {\n"
+ " NSString *cn1Key = [NSString stringWithFormat:@\"%@_%@\",\n"
+ " [[cn1LangParts objectAtIndex:0] lowercaseString],\n"
+ " [[cn1LangParts objectAtIndex:1] uppercaseString]];\n"
+ " cn1TargetIcon = [cn1LocalizedIcons objectForKey:cn1Key];\n"
+ " void (^cn1ApplyIcon)(void) = ^{\n"
+ " NSString *cn1CurrentIcon = [[UIApplication sharedApplication] alternateIconName];\n"
+ " NSString *cn1TargetIcon = nil;\n"
+ " NSArray *cn1PrefLangs = [NSLocale preferredLanguages];\n"
+ " if (cn1PrefLangs.count > 0) {\n"
+ " NSString *cn1PrefLang = [cn1PrefLangs objectAtIndex:0];\n"
+ " NSArray *cn1LangParts = [cn1PrefLang componentsSeparatedByCharactersInSet:\n"
+ " [NSCharacterSet characterSetWithCharactersInString:@\"-_\"]];\n"
+ " if (cn1LangParts.count >= 2) {\n"
+ " NSString *cn1Key = [NSString stringWithFormat:@\"%@_%@\",\n"
+ " [[cn1LangParts objectAtIndex:0] lowercaseString],\n"
+ " [[cn1LangParts objectAtIndex:1] uppercaseString]];\n"
+ " cn1TargetIcon = [cn1LocalizedIcons objectForKey:cn1Key];\n"
+ " }\n"
+ " if (cn1TargetIcon == nil && cn1LangParts.count >= 1) {\n"
+ " NSString *cn1Key = [[cn1LangParts objectAtIndex:0] lowercaseString];\n"
+ " cn1TargetIcon = [cn1LocalizedIcons objectForKey:cn1Key];\n"
+ " }\n"
+ " }\n"
+ " if (cn1TargetIcon == nil && cn1LangParts.count >= 1) {\n"
+ " NSString *cn1Key = [[cn1LangParts objectAtIndex:0] lowercaseString];\n"
+ " cn1TargetIcon = [cn1LocalizedIcons objectForKey:cn1Key];\n"
+ " BOOL cn1NeedsUpdate = (cn1TargetIcon == nil && cn1CurrentIcon != nil)\n"
+ " || (cn1TargetIcon != nil && ![cn1TargetIcon isEqualToString:cn1CurrentIcon]);\n"
+ " if (!cn1NeedsUpdate) {\n"
+ " return;\n"
+ " }\n"
+ " }\n"
+ " BOOL cn1NeedsUpdate = (cn1TargetIcon == nil && cn1CurrentIcon != nil)\n"
+ " || (cn1TargetIcon != nil && ![cn1TargetIcon isEqualToString:cn1CurrentIcon]);\n"
+ " if (cn1NeedsUpdate) {\n"
+ " [[UIApplication sharedApplication] setAlternateIconName:cn1TargetIcon completionHandler:nil];\n"
+ " NSString *cn1FinalTarget = cn1TargetIcon;\n"
+ " [[UIApplication sharedApplication] setAlternateIconName:cn1FinalTarget completionHandler:^(NSError * _Nullable cn1IconErr) {\n"
+ " if (cn1IconErr != nil) {\n"
+ " NSLog(@\"[CodenameOne] Failed to set alternate app icon '%@': %@\", cn1FinalTarget ?: @\"(primary)\", cn1IconErr);\n"
+ " } else {\n"
+ " NSLog(@\"[CodenameOne] Set alternate app icon to '%@'\", cn1FinalTarget ?: @\"(primary)\");\n"
+ " }\n"
+ " }];\n"
+ " };\n"
+ " if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {\n"
+ " dispatch_async(dispatch_get_main_queue(), cn1ApplyIcon);\n"
+ " } else {\n"
+ " __block id cn1ActiveObs = nil;\n"
+ " cn1ActiveObs = [[NSNotificationCenter defaultCenter]\n"
+ " addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue]\n"
+ " usingBlock:^(NSNotification *cn1Note) {\n"
+ " if (cn1ActiveObs != nil) {\n"
+ " [[NSNotificationCenter defaultCenter] removeObserver:cn1ActiveObs];\n"
+ " cn1ActiveObs = nil;\n"
+ " }\n"
+ " cn1ApplyIcon();\n"
+ " }];\n"
+ " }\n"
+ " }\n";
}
Expand Down
Loading