文章目录
ios平台alternate icon配置注意事项
ios支持动态更换用户的appicon,要实现这个功能,一共需要进行三步操作:
- 将icon文件导入xcode项目中,icon文件需要png格式
- 在info.plist中配置可更换的icon列表
- 增加更换icon代码
当然实际上按apple的要求,还需要一个让用户主动选择使用哪一个icon的界面,由于这是另一个功能,这里就不展开写了。
详细的接入方式在很多文章中都已经有分享了,所以我本文中也不会将具体步骤展开细讲,重点会放在接入过程中所遇到的坑点。下面按照这三个步骤分类逐项说明。
第一步,将icon文件导入xcode项目
这一步操作比较简单,正常将图片文件引入xcode项目中即可,需要注意的是,icon的图片文件不能放在Asset.xcassets里。
但即使看起来简单,但仍然会遇到坑。
理论上来说,icon文件的文件名和尺寸都没有要求,但在实际操作中会遇到下面几个问题:
问题1:提审时因为缺少关键尺寸导致提审失败
-
遇到的问题
我所在的项目在提审时就遇到过下面这样的问题,结果导致提审失败,其原因是缺少了一些关键的icon尺寸。ITMS-90892: Missing recommended icon - The bundle does not contain an alternate app icon for iPad of exactly ‘152x152’ pixels, in .png format for iOS versions >= 7.0. To support older operating systems, the icon may be required in the bundle outside of an asset catalog. Make sure the Info.plist file includes appropriate entries referencing the file. See https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons
-
解决方案
要解决这个问题,就需要在制作时确保所有需要的尺寸都存在。
在苹果官方的设计导航中对所有的icon及尺寸进行了完整说明:human-interface-guidelines/foundations/app-iconsn,但实际所需的跟文档中并不完全一致,不过我们可以从项目的AppIcon中看到。一个常见的同时支持iphone和ipad的app,除去AppStore中需要的一个以外,需要的icon一共18个(iphone和ipad各9个)。一些制作appicon的网站上,也是使用了这样的规则。
问题2:文件名重复,导致build失败
-
遇到的问题
一开始时我在不同的文件夹下存放了同名的icon文件,例如所有icon都以appicon_尺寸
的形式命名,分别存放在自己所在文件夹,最终却导致build失败。
-
解决方案
出现这个错误的原因是因为xcode在build时,会将所有图片都放在ipa的根目录,如果文件名相同,那么将无法对文件进行管理。下图是展开ipa内容后可以看到的结构。
所以在制作icon时,一定要注意保证每个icon的文件名都是唯一的。推荐的命名方式可以参考下一条。
问题3:ios系统找不到图片导致显示没有icon,或是查找的图片尺寸不正确导致icon模糊
- 遇到的问题
虽然理论上文件名不会有问题,但我确实遇到了一些奇怪情况,比如当某文件为“appicon_1.png”这样时,系统找不到图片;
又或者同时包含“appicon-80.png”和“appicon-152.png”这样的文件名时,系统没有使用尺寸最接近的“appicon-152.png”,而是选择了“appicon-80.png”作为appicon导致最终显示模糊。 - 解决方案
这些情况都是我们所不想要的,好在只要使用与默认规则一致的命名规则,就可以避免这些情况的发生。
我在出包后的app中找到了所有被使用的icon,发现命名规则均为AppIcon40x40@2x.png
这种类型,其中AppIcon
为文件名,40x40@2x
为用于标识尺寸的后缀。
当系统发现所需要查找的名称为AppIcon40x40
时,除了AppIcon40x40.png
这个文件本身外,还会自动查找所有AppIcon40x40@2x.png
和AppIcon40x40@3x.png
的文件(如果需要的话)。
此外,对于ipad,还会在尺寸后缀上再加上一个~ipad
用于说明这是ipad上所使用的图片。
我将所有18个icon的后缀和尺寸整理了一遍,制作icon文件时可以一一对照。
{
"20x20@2x" : 40,
"20x20@3x" : 60,
"29x29" : 29,
"40x40@2x" : 80,
"40x40@3x" : 120,
"29x29@2x" : 58,
"29x29@3x" : 87,
"60x60@2x" : 120,
"60x60@3x" : 180,
"20x20~ipad" : 20,
"20x20@2x~ipad" : 40,
"29x29~ipad" : 29,
"29x29@2x~ipad" : 58,
"40x40@2x~ipad" : 80,
"40x40~ipad" : 40,
"76x76~ipad" : 76,
"76x76@2x~ipad" : 152,
"83.5x83.5@2x~ipad" : 167
}
第二步,配置可更换的icon列表
第二步是进行配置。在info.plist中的配置结构和源代码见下方,其中CFBundleIcons
是最外层的入口,在xcode中会显示为Icon files(iOS 5)
,每一个icon及其配置都是一个字典对象,其中key为在代码中更换时所使用的名称;每个value也是一个字典对象,其中key为CFBundleIconFiles
的值包含了一个所引用的图片的列表。图片名查找规则在前文已经进行过说明,不再辍述。
对应的配置源文件如下:
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>app_icon1</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>app_icon160x60</string>
<string>app_icon129x29</string>
<string>app_icon140x40</string>
<string>app_icon120x20</string>
<string>app_icon176x76</string>
<string>app_icon183.5x83.5</string>
</array>
<key>UIPrerenderedIcon</key>
<string>false</string>
</dict>
...此处省略其他项
</dict>
问题4:在ipad上更换icon无效
-
遇到的问题
在完以上面配置后,有可能会遇到仅在iphone上更换成功,但在ipad上更换却无效的问题。 -
解决方案
发生这个问题的原因是在ipad上所使用的配置入口与iphone并不相同。在iphone上使用的入口key为CFBundleIcons
,但在ipad上需要额外增加~ipad
后缀,即CFBundleIcons~ipad
。
因此我们需要增加一个ipad专用的入口,内部配置与iphone所使用的完全一致。
具体配置可以参考以下两个链接:
ios文档 Contents of the CFBundleAlternateIcons Dictionary Entry
stack overflow why-do-my-alternate-icons-work-on-iphone-but-not-on-ipad
第三步,编写替换代码
整体代码非常简单,只需要调用api即可。注意setAlternateIconName
中所使用的iconName
即在上一步中所配置的CFBundleAlternateIcons
的key。
例如上方配置了default
、icon_a
、icon_b
和icon_d
,那么可以使用的iconName
就只有这四个。
此外,当iconName
的值为nil时,将使用应用默认的icon。
NSString * iconName = [NSString stringWithUTF8String:icon];
if (![[UIApplication sharedApplication] supportsAlternateIcons]) {
return;
}
if ([iconName isEqualToString:@""]) {
iconName = nil;
}
[[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"change appicon %@ with error :%@",iconName,error);
}
}];
虽然api很简单,但有时仍会遇到问题。但好在通常都会返回错误信息,根据错误信息调整即可。
问题5:更换icon失败,也没有提示出错
- 遇到的问题
在一些场景下无论如何都无法调用成功,也没有错误提示。
但在xcode中会发现提示要求在主线程中调用。
- 解决方案
在调用更换icon的代码前增加dispatch_async
,强制在主线程中调用。
void setAppIcon(const char* icon)
{
//在主线程中调用
dispatch_async(dispatch_get_main_queue(), ^{
_setAppIcon(icon);
});
}
void _setAppIcon(const char* icon){
NSString * iconName = [NSString stringWithUTF8String:icon];
if (![[UIApplication sharedApplication] supportsAlternateIcons]) {
return;
}
if ([iconName isEqualToString:@""]) {
iconName = nil;
}
[[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"change appicon %@ with error :%@",iconName,error);
}
}];
}
参考: ios documentation setAlternateIconName:completionHandler:
以上就是我在配置ios平台可更换代码时遇到的问题,希望可以给到一些帮助。