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

该功能应用的场景

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

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

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

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

当然该功能(API)当前只支持iOS10.3以上的系统,所以只能当做一项附加功能来进行使用。下面将详细讲解下如何使用代码来实现此功能。

API方法

  1. @interface UIApplication (UIAlternateApplicationIcons)
  2. // 如果为NO,表示当前进程不支持替换图标
  3. @property (readonly, nonatomic) BOOL supportsAlternateIcons NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));
  4. // 传入nil代表使用主图标. 完成后的操作将会在任意的后台队列中异步执行; 如果需要更改UI,请确保在主队列中执行.
  5. - (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));
  6. // 如果alternateIconName为nil,则代表当前使用的是主图标.
  7. @property (nullable, readonly, nonatomic) NSString *alternateIconName NS_EXTENSION_UNAVAILABLE("Extensions may not have alternate icons") API_AVAILABLE(ios(10.3), tvos(10.2));
  8. @end
  1. - (void)setAppIconWithName:(NSString *)iconName {
  2. if (![[UIApplication sharedApplication] supportsAlternateIcons]) {
  3. return;
  4. }
  5.  
  6. if ([iconName isEqualToString:@""]) {
  7. iconName = nil;
  8. }
  9. [[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
  10. if (error) {
  11. NSLog(@"更换app图标发生错误了 : %@",error);
  12. }
  13. }];
  14. }

配置文件(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该弹框,不让其进行弹出即可:

  1. #import "UIViewController+Present.h"
  2. #import <objc/runtime.h>
  3.  
  4. @implementation UIViewController (Present)
  5.  
  6. + (void)load {
  7.  
  8. static dispatch_once_t onceToken;
  9. dispatch_once(&onceToken, ^{
  10. Method presentM = class_getInstanceMethod(self.class, @selector(presentViewController:animated:completion:));
  11. Method presentSwizzlingM = class_getInstanceMethod(self.class, @selector(dy_presentViewController:animated:completion:));
  12.  
  13. method_exchangeImplementations(presentM, presentSwizzlingM);
  14. });
  15. }
  16.  
  17. - (void)dy_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
  18.  
  19. if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {
  20. NSLog(@"title : %@",((UIAlertController *)viewControllerToPresent).title);
  21. NSLog(@"message : %@",((UIAlertController *)viewControllerToPresent).message);
  22.  
  23. UIAlertController *alertController = (UIAlertController *)viewControllerToPresent;
  24. if (alertController.title == nil && alertController.message == nil) {
  25. return;
  26. } else {
  27. [self dy_presentViewController:viewControllerToPresent animated:flag completion:completion];
  28. return;
  29. }
  30. }
  31.  
  32. [self dy_presentViewController:viewControllerToPresent animated:flag completion:completion];
  33. }
  34.  
  35. @end

或者

  1. #import "ViewController.h"
  2. #import <objc/runtime.h>
  3.  
  4. // 利用runtime来替换展现弹出框的方法
  5. static dispatch_once_t onceToken;
  6. dispatch_once(&onceToken, ^{
  7. Method presentM = class_getInstanceMethod(self.class, @selector(presentViewController:animated:completion:));
  8. Method presentSwizzlingM = class_getInstanceMethod(self.class, @selector(ox_presentViewController:animated:completion:));
  9. // 交换方法实现
  10. method_exchangeImplementations(presentM, presentSwizzlingM);
  11. });
  12.  
  13. // 自己的替换展示弹出框的方法
  14. - (void)ox_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
  15.  
  16. if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {
  17. NSLog(@"title : %@",((UIAlertController *)viewControllerToPresent).title);
  18. NSLog(@"message : %@",((UIAlertController *)viewControllerToPresent).message);
  19.  
  20. // 换图标时的提示框的title和message都是nil,由此可特殊处理
  21. UIAlertController *alertController = (UIAlertController *)viewControllerToPresent;
  22. if (alertController.title == nil && alertController.message == nil) {// 是换图标的提示
  23. return;
  24. } else {// 其他提示还是正常处理
  25. [self ox_presentViewController:viewControllerToPresent animated:flag completion:completion];
  26. return;
  27. }
  28. }
  29.  
  30. [self ox_presentViewController:viewControllerToPresent animated:flag completion:completion];
  31. }

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

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

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

动态改变APP图标的更多相关文章

  1. 【转】【iOS】动态更换App图标

    原文网址:http://www.cocoachina.com/ios/20170619/19557.html 前言 动态更换App图标这件事,在用户里总是存在需求的:有些用户喜欢“美化”自己的手机.至 ...

  2. Android动态改变App在Launcher里面的icon

    如果呆萌的产品童鞋让你动态更换App在Launcher里面的Icon,你怎么回答他,下文就提出一种实现该效果的方法. 原理1--activity-alias 在AndroidMainifest中,有两 ...

  3. iOS 10.3+ 动态修改 App 图标

    支持系统: iOS 10.3+ tvOS 10.2+ Apple 官方文档 官方 API: @interface UIApplication (UIAlternateApplicationIcons) ...

  4. 动态改变actionbar上menu的图标

    工作中遇到了一个需求是,在滚动的时候让actionbar上的图标进行变色.实现后在这里总结下思路. 一.先在主题中定义好Actionbar的style <style name="App ...

  5. 如何在运行时改变App的图标

    在你完成应用程序的beta版本后,最后会有些人去帮你测试,使你去完善应用程序……或者会有投资青睐.但是如果测试人员有一种简单地方式去检查构建版本的应用程序会不会有帮助呢? 这个教程将会向你展示这些,向 ...

  6. android 动态改变listview的内容

    本文模拟:点击一个按钮,为已有的listview添加一行数据 <?xml version="1.0" encoding="utf-8"?> < ...

  7. Windows Phone 动态改变ListBox样式

    使用ListBox时通常会借助ItemTemplate帮助我们实现更复杂多样的样式显示,体现了Xaml的灵活.如何动态改变变ListBox的样式,实现类似电脑资源管理器中列表显示和图标显示形式的替换. ...

  8. WPF动态改变主题颜色

    原文:WPF动态改变主题颜色 国内的WPF技术先行者周银辉曾介绍过如何动态改变应用程序的主题样式,今天我们来介绍一种轻量级的改变界面风格的方式--动态改变主题色. 程序允许用户根据自己的喜好来对界面进 ...

  9. vue router 修改title(IOS 下动态改变title失效)

    在ios下app  设置document.title = "titleName" 失效,原因是在IOS webview中网页标题只加载一次,动态改变是无效的. 在路由配置中添加   ...

随机推荐

  1. C# 线程本地存储 调用上下文 逻辑调用上下文

    线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...

  2. python全栈开发day40-浮动的四大特性,浮动带来的问题和解决问题,文本属性、字体属性和颜色介绍

    一.昨日内容总结 1.盒模型及其属性 2.文本级标签.行内块.块级标签 3.继承性.层叠性.权重 4.浮动四大特性 # 浮动元素脱离标准文档流 # 贴靠 # 字围效果 # 自动收缩或紧缩 二.今日内容 ...

  3. Codeforces 1102F Elongated Matrix 状压dp

    Elongated Matrix 预处理一下两两之间的最小值, 然后直接dp. #include<bits/stdc++.h> #define LL long long #define f ...

  4. Python6 - 函数总结

    一.函数的基本知识 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 1.1函数定义规则 ...

  5. 解决linux下“XX不在 sudoers 文件中。此事将被报告"的问题

    在使用sudo命令时,经常性会提示出“不在 sudoers 文件中.此事将被报告”的错误信息. 这是因为当前登录的账号不在sudo权限里面. sudo命令可以让你以root身份执行命令,来完成一些我们 ...

  6. Effective Java 第三版——57. 最小化局部变量的作用域

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  7. 利用FutureTask进行超时设置方法

    public class Test {   public static void main(String[] args) { ExecutorService executor = Executors. ...

  8. MongoDB--集群

    为什么需要集群 为了让数据安全 高(24* 7)数据可用性 灾难恢复 无停机维护(如备份,索引重建,压实) 读缩放(额外的副本读取) 副本集对应用程序是透明 设置集群 准备工作 在MongoDB的集群 ...

  9. 搭建elasticsearch可视化插件

    一,搭建本地elasticsearch服务 具体搭建流程,可以参考博客:https://www.cnblogs.com/vipchenwei/p/9156668.html elasticsearch搭 ...

  10. BZOJ.3598.[SCOI2014]方伯伯的商场之旅(贪心 数位DP)

    题目链接 先考虑,对于确定的一个数,怎样移动代价最少(或者移到哪个位置最优)? 假设我们都移到下标\(1\)位置(设集合点为\(1\)),那么移动到下标\(2\)与\(1\)相比代价差为:\(下标&l ...