PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

The cause of

The annual Spring Festival is coming. All major manufacturers’ apps have changed the Icon into the Spring Festival picture. It is strange that the Logo will change if the APP is not updated. Today, let’s talk about this technology point (Taobao, Alipay has been used for several years).

demand

  • Modify Icon in App
  • The silent switch

System apis

First, this technology is only available on iOS 10.3 and above

Let’s show you the system API

Available (iOS 10.3, *) open var supportsAlternateIcons: Bool {get}// Whether the standby logo is supported // Pass 'nil' to use the primary application icon. The Completion handler will be invoked asynchronously on an arbitrary background queue; Be sure to dispatch back to the main queue before doing any further UI work. @available(iOS 10.3, *) open func setAlternateIconName(_ alternateIconName: String? , completionHandler: ((Error?) -> Void)? // If 'nil', the primary application icon is being used. @available(iOS 10.3, *) open var alternateIconName: String? {get}// Name of the current logoCopy the code

The Internet found the way to achieve

Online checked the next information, first said the implementation steps on the Internet:

1. Add icon images

The image is placed in the project directory, not in the system’s resource management Assets file

2. Info.plist configuration

Add keywords to info.plist: Icon Files (iOS 5)

This is what it looks like when it’s added successfully

There seems to be no CFBundleAlternateIcons keyword on the Internet

No, then add it manually, according to the appearance of the post added

It can be seen that the item above corresponds to the name of icon. Multiple items can be added here for adaptation of various devices

This completes the configuration. Remember the name

3. Call code

In the code

if UIApplication.shared.supportsAlternateIcons{ let str = UIApplication.shared.alternateIconName if str ! = "sunshine"{ UIApplication.shared.setAlternateIconName("sunshine") { error in if error ! = nil{ print("\(String(describing: error))") } } } }Copy the code

Note: Sunshine corresponds to the name configured above

4. Summary of online information implementation

In addition, resource management is placed under the project directory. As apple is known for its elegance, it will tolerate such problems. In the spirit of exploration, it has taken a look at the project configuration

A more elegant implementation

Alternate App Icon Sets under Build Settings, Alternate App Icon Sets

1. Now create two AppIcon resource folders under the project resource folder, named sat and GUA respectively, and add resources according to the way of configuring common logo

2. Double-click on the right of the Alternate App Icon Sets item under Build Settings to add sat GUA

3. Use the setup code above

OK, that’s it. Very simple there is no !!!!

Popover problem handling

However, you must have found some problems when using it. In this way, there will be a prompt pop-up window, which is not as elegant as Taobao and Alipay. With the attitude of pursuing perfection, we continued to study and found that the pop-up window is UIAlertController without title and message

This is where the magic comes in, Runtime

Swift language popover processing code

Direct code :Swift

extension UIViewController{ public class func initializeMethod(){ if self ! = UIViewController.self{ return } DispatchQueue.once(token: "ChangeIcon") { let orignal = class_getInstanceMethod(self, #selector(UIViewController.present(_:animated:completion:))) let swizzling = class_getInstanceMethod(self, #selector(UIViewController.ssl_present(_:animated:completion:))) if let old = orignal, let new = swizzling{ method_exchangeImplementations(old, new) } } } @objc private func ssl_present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) { if viewControllerToPresent is UIAlertController{ let vc = viewControllerToPresent as! UIAlertController if vc.title == nil && vc.message == nil{ return } } self.ssl_present(viewControllerToPresent, animated: flag, completion: completion) } } extension DispatchQueue{ private static var _onceTracker = [String]() public class func once(token: String, block:()->()){ objc_sync_enter(self) defer{ objc_sync_exit(self) } if _onceTracker.contains(token){ return } _onceTracker.append(token) block() } }Copy the code

Enable:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  UIViewController.initializeMethod()

  return true
}
Copy the code

OC language popover processing code

Don’t forget old friends, find ObjectC code reference address online

// UIViewController+LQNoPresent.h
#import <UIKit/UIKit.h>
@interface UIViewController (LQNoPresent)
@end
#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
Copy the code

Here is the end, the perfect end of the demand, if there is any deficiency, welcome to correct!!

Record the whole process of iOS dynamic Icon replacement