美文网首页
切换icon和启动页广告实践 - 2021-11-17 周三

切换icon和启动页广告实践 - 2021-11-17 周三

作者: 勇往直前888 | 来源:发表于2022-03-27 08:33 被阅读0次

icon切换

版本限制

在iOS 10.3之后,苹果官方提供了相关的API来实现这个功能

@interface UIApplication (UIAlternateApplicationIcons)
// 如果为NO,表示当前进程不支持替换图标
@property (readonly, nonatomic) BOOL supportsAlternateIcons NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));

// 传入nil代表使用主图标. 完成后的操作将会在任意的后台队列中异步执行; 如果需要更改UI,请确保在主队列中执行.
- (void)setAlternateIconName:(nullable NSString *)alternateIconName completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));

// 如果alternateIconName为nil,则代表当前使用的是主图标.
@property (nullable, readonly, nonatomic) NSString *alternateIconName NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));
@end

所以,APP的最低支持版本最好是iOS11以上。现在iOS15都出来了,最低支持iOS11也是很合理的。

使用样例

网络上大神给出的使用例子是很合理的,大多数情况可以直接套用。

- (void)changeAppIconWithName:(NSString *)iconName {
    if (![[UIApplication sharedApplication] supportsAlternateIcons]) {
        NSLog(@"不支持切换图标");
        return;
    }
    
    if ([iconName isEqualToString:@""]) {
        iconName = nil;
    }
    [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"更换app图标发生错误了 : %@",error);
        }
    }];
}

先检查是否支持icon切换(iOS15模拟器就不支持),然后再设置;给控字符串的话,在内部改成nil,就是切换到主icon

图片资源

  • 主icon:一般默认放在Assets.xcassets中,名字默认是AppIcon,并且分辨率都有要求,不要圆角。图片不规范的话,会有警告(XCode13)。
主icon
  • 备用icon不能放在Assets.xcassets中。实际试了一下,切换API setAlternateIconName可以执行成功,但是没效果。
备用icon不能放Assets.xcassets
  • 备用icon应该以图片的形式放在工程中,是Assets.xcassets出来以前的老的方式,命名包括@2x和@3x两种。
备用icon以图片形式存放

配置plist文件

  • 需要将备用icon的相关信息配置再plist文件中,否则会报出“The file doesn’t exist.”(文件不存在)的错误。
文件不存在错误
  • 备用icon的文件信息需要通过plist文件进行配置,几个key的名字是固定的,并且XCode没有提示。
    在 Icon files(iOS 5)内添加一个Key: CFBundleAlternateIcons ,类型为字典,在这个字典里配置我们所有需要动态修改的icon:键为icon的名称,值为一个字典(这个字典里包含两个键:CFBundleIconFiles,其值类型为Array,内容为icon的名称;
plist配置

至于其他分辨率的图片,如果给了,那么就按照实际情况添加就好了,比如下面的例子:至于这些额外配置的图片有没有起作用,暂时还没有验证。

更多图片

关于弹窗

只要API执行成功,那么就会跳出一个弹窗,提示用户icon已经被更改。就算没有效果,弹窗也会弹的,这是很蛋疼的一点。到底有没有切换成功,需要人为查看一下。

弹窗提示

一般icon换就换了,还多余地跳出一个弹窗,苹果的设计人员真是愚蠢到家了。网上大神脑洞大开,用runtime大法让这个弹窗不显示。(这个弹窗是title和message都是nil的UIAlertController)

// UIViewController+LQNoPresent.h
#import <UIKit/UIKit.h>

@interface UIViewController (LQNoPresent)

@end


// UIViewController+LQNoPresent.m

#import "UIViewController+LQNoPresent.h"
#import <objc/runtime.h>

@implementation UIViewController (LQNoPresent)

+ (void)load {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method presentM = class_getInstanceMethod(self.class, @selector(presentViewController:animated:completion:));
        Method presentSwizzlingM = class_getInstanceMethod(self.class, @selector(lq_presentViewController:animated:completion:));
        
        method_exchangeImplementations(presentM, presentSwizzlingM);
    });
}

- (void)lq_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    
    if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {
//        NSLog(@"title : %@",((UIAlertController *)viewControllerToPresent).title);
//        NSLog(@"message : %@",((UIAlertController *)viewControllerToPresent).message);
        
        UIAlertController *alertController = (UIAlertController *)viewControllerToPresent;
        if (alertController.title == nil && alertController.message == nil) {
            return;
        }
    }
    
    [self lq_presentViewController:viewControllerToPresent animated:flag completion:completion];
}


@end

iOS15模拟器

  • iOS13.7的模拟器能够执行成功。

  • iOS15的真机能够执行成功。但是会有报错信息

2021-11-23 13:54:44.536599+0800 IconDemo[482:41679] [default] +[LSApplicationProxy applicationProxyFor*] is not a supported method for getting the LSApplicationProxy for the current process, use +[LSBundleProxy bundleProxyForCurrentProcess] instead.
2021-11-23 13:54:44.539473+0800 IconDemo[482:41679] [default] LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=264, _LSFunction=-[_LSDReadClient getServerStoreWithCompletionHandler:]}
2021-11-23 13:54:44.539646+0800 IconDemo[482:41679] [default] Attempt to map database failed: permission was denied. This attempt will not be retried.
2021-11-23 13:54:44.539866+0800 IconDemo[482:41679] [db] Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=264, _LSFunction=-[_LSDReadClient getServerStoreWithCompletionHandler:]}
2021-11-23 14:01:32.350521+0800 IconDemo[482:41679] Writing analzed variants.
2021-11-23 14:01:32.359309+0800 IconDemo[482:41679] Writing analzed variants.

出错信息看不出具体的原因。

  • iOS15的模拟器不能执行成功,并且还有出错信息
2021-11-23 14:05:54.402051+0800 IconDemo[19546:238285] [db] _LSSchemaConfigureForStore failed with error Error Domain=NSOSStatusErrorDomain Code=-10817 "(null)" UserInfo={_LSFunction=_LSSchemaConfigureForStore, ExpectedSimulatorHash={length = 32, bytes = 0x8367042c 5a0d3739 c4750e92 134b458d ... 2bd5ba9c f73141f5 }, _LSLine=405, WrongSimulatorHash={length = 32, bytes = 0x2bea4bde a7079a50 310364fe 5294f4b1 ... 1a2344cc eb36b0fc }}
2021-11-23 14:05:54.403289+0800 IconDemo[19546:238285] [db] Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-10817 "(null)" UserInfo={_LSFunction=_LSSchemaConfigureForStore, ExpectedSimulatorHash={length = 32, bytes = 0x8367042c 5a0d3739 c4750e92 134b458d ... 2bd5ba9c f73141f5 }, _LSLine=405, WrongSimulatorHash={length = 32, bytes = 0x2bea4bde a7079a50 310364fe 5294f4b1 ... 1a2344cc eb36b0fc }}
2021-11-23 14:05:54.430781+0800 IconDemo[19546:238285] 更换app图标发生错误了 : Error Domain=NSCocoaErrorDomain Code=3328 "The requested operation couldn’t be completed because the feature is not supported."

这里的出错信息很明确指出不支持这个特性。

模拟器差异

参考文章

iOS动态修改app 图标icon
iOS 动态更换app图标AppIcon

相关文章

网友评论

      本文标题:切换icon和启动页广告实践 - 2021-11-17 周三

      本文链接:https://www.haomeiwen.com/subject/jdvltrtx.html