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图标进行更换》短期内应该无法实现

  • 相关阅读:
    mitmproxy抓包工具
    java基础|int和Integer的区别
    Vue|退出功能
    Vue|分页处理
    apt-get本地软件源搭建
    rqt_plot报错
    创建ROS 工作空间时出现:程序“catkin_init_workspace”尚未安装,程序“catkin_make”尚未安装。
    ubuntu16.04安装ROS
    debian及Ubuntu各版本下载地址获取
    解决sudo rosdep init和rosdep update的错误
  • 原文地址:https://www.cnblogs.com/fengmin/p/6841818.html
Copyright © 2011-2022 走看看