zoukankan      html  css  js  c++  java
  • 动态改变APP图标

    一、iOS动态更换App图标(一):基础使用

    该功能应用的场景

    1、白天/夜间模式切换,在切换App主色调同时切换App图标。

    2、各类皮肤主题(淘宝就可换肤),附带App图标一块更换。

    3、利用App图标表达某种特定功能,如Demo中的,提示当前天气。

    4、图标促销提示,如淘宝京东特定节日:11.11、6.18,提前更换App图标。

    当然该功能(API)当前只支持iOS10.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
    - (void)setAppIconWithName:(NSString *)iconName {
        if (![[UIApplication sharedApplication] supportsAlternateIcons]) {
            return;
        }
        
        if ([iconName isEqualToString:@""]) {
            iconName = nil;
        }
        [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSLog(@"更换app图标发生错误了 : %@",error);
            }
        }];
    }

    配置文件(Info.plist)

    当然也要拖入对应的App图标:

      不过这里我们好像还少配置了App主图标,也就是正常情况下我们的图标。按照文档所说,我们需要在CFBundleIcons里面配置CFBundlePrimaryIcon这个主图标对应的内容,但是实际上,我们还是按照老方法,在Assets.xcassets中配置AppIcon,对应尺寸填上对应图片即可。为什么这样子就可以配置主图标呢?让我们来看看某知名电商的ipa(在AppStore上下载的包)内的Info.plist(位于Payload/XXXXXX/Info.plist):

    拦截弹框

      既然知道了弹框是UIAlertController,那么我们自然而然想到,该弹框是由ViewController通过presentViewController:animated:completion:方法弹出。那么我们就可以通过Method swizzling hook该弹框,不让其进行弹出即可:

    #import "UIViewController+Present.h"
    #import <objc/runtime.h>
    
    @implementation UIViewController (Present)
    
    + (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(dy_presentViewController:animated:completion:));
            
            method_exchangeImplementations(presentM, presentSwizzlingM);
        });
    }
    
    - (void)dy_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;
            } else {
                [self dy_presentViewController:viewControllerToPresent animated:flag completion:completion];
                return;
            }
        }
        
        [self dy_presentViewController:viewControllerToPresent animated:flag completion:completion];
    }
    
    
    @end

    或者

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    
    // 利用runtime来替换展现弹出框的方法
        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(ox_presentViewController:animated:completion:));
            // 交换方法实现
            method_exchangeImplementations(presentM, presentSwizzlingM);
        });
    
    
    
    // 自己的替换展示弹出框的方法
    - (void)ox_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);
            
            // 换图标时的提示框的title和message都是nil,由此可特殊处理
            UIAlertController *alertController = (UIAlertController *)viewControllerToPresent;
            if (alertController.title == nil && alertController.message == nil) {// 是换图标的提示
                return;
            } else {// 其他提示还是正常处理
                [self ox_presentViewController:viewControllerToPresent animated:flag completion:completion];
                return;
            }
        }
        
        [self ox_presentViewController:viewControllerToPresent animated:flag completion:completion];
    }

    这段代码交换了UIViewControllerpresentViewController:animated:completion:方法。通过打印UIAlertController的特征,我们可以发现,更换App图标时的弹框是没有title与message的,但是我们一般使用的UIAlertController都是带title、message的,毕竟不会弹个空白的框给用户玩。

    所以该方法中通过判断title与message来捕捉更换App图标时的弹框,并直接return即可。

    《iOS动态更换App图标(三):动态下载App图标进行更换》短期内应该无法实现

  • 相关阅读:
    ADF中遍历VO中的行数据(Iterator)
    程序中实现两个DataTable的Left Join效果(修改了,网上第二个DataTable为空,所处的异常)
    ArcGIS api for javascript——鼠标悬停时显示信息窗口
    ArcGIS api for javascript——查询,然后单击显示信息窗口
    ArcGIS api for javascript——查询,立刻打开信息窗口
    ArcGIS api for javascript——显示多个查询结果
    ArcGIS api for javascript——用图表显示查询结果
    ArcGIS api for javascript——查询没有地图的数据
    ArcGIS api for javascript——用第二个服务的范围设置地图范围
    ArcGIS api for javascript——显示地图属性
  • 原文地址:https://www.cnblogs.com/fengmin/p/6841818.html
Copyright © 2011-2022 走看看