美文网首页
动态变更iOS iCON(无弹框版)

动态变更iOS iCON(无弹框版)

作者: ios_wong | 来源:发表于2019-12-25 17:05 被阅读0次

iOS 10.3 提供了动态变更icon的API;

这里整理了一些注意事项和使用过程中的问题;
注意事项:
1、icon添加的位置;

不在Assets.xcassets中,在项目下创建文件夹添加各icon,

image.png

如图,如果添加了两套icon,2020和spring,则在相应文件夹下添加不同尺寸的图片;


image.png

2、info.plist 添加方式;
建议文本编辑器打开项目info.plist,然后直接贴上如下代码,替换中间的icon的key和对应的图片数组;

<key>CFBundleIcons</key>
    <dict>
        <key>CFBundleAlternateIcons</key>
        <dict>
            <key>2020</key>
            <dict>
                <key>CFBundleIconFiles</key>
                <array>
                    <string>2020_60X60</string>
                    <string>2020_29X29</string>
                    <string>2020_40X40</string>
                    <string>2020_58X58</string>
                    <string>2020_76X76</string>
                    <string>2020_80X80</string>
                    <string>2020_87X87</string>
                    <string>2020_120X120</string>
                    <string>2020_152X152</string>
                    <string>2020_167X167</string>
                    <string>2020_180X180</string>
                    <string>2020_1024X1024</string>
                </array>
                <key>UIPrerenderedIcon</key>
                <false/>
            </dict>
            <key>normal</key>
            <dict>
                <key>CFBundleIconFiles</key>
                <array>
                    <string>normal_60X60</string>
                    <string>normal_20X20</string>
                    <string>normal_40X40</string>
                    <string>normal_29X29</string>
                    <string>normal_58X58</string>
                    <string>normal_60X60</string>
                    <string>normal_76X76</string>
                    <string>normal_80X80</string>
                    <string>normal_87X87</string>
                    <string>normal_120X120</string>
                    <string>normal_152X152</string>
                    <string>normal_167X167</string>
                    <string>normal_180X180</string>
                    <string>normal_1024X1024</string>
                </array>
                <key>UIPrerenderedIcon</key>
                <false/>
            </dict>
            <key>spring</key>
            <dict>
                <key>CFBundleIconFiles</key>
                <array>
                    <string>spring_60X60</string>
                    <string>spring_29X29</string>
                    <string>spring_58X58</string>
                    <string>spring_76X76</string>
                    <string>spring_80X80</string>
                    <string>spring_87X87</string>
                    <string>spring_120X120</string>
                    <string>spring_152X152</string>
                    <string>spring_167X167</string>
                    <string>spring_180X180</string>
                    <string>spring_1024X1024</string>
                </array>
                <key>UIPrerenderedIcon</key>
                <false/>
            </dict>
        </dict>
        <key>CFBundlePrimaryIcon</key>
        <dict>
            <key>CFBundleIconFiles</key>
            <array>
                <string>normal</string>
            </array>
        </dict>
    </dict>

默认使用的过程中会有如下问题:
1、如果在viewDidLoad/viewDidAppear 方法中使用,提示:“Error Domain=NSCocoaErrorDomain Code=3072 操作已取消”

延迟1秒钟操作,附上更换的代码

override func viewDidLoad() {
        super.viewDidLoad()
        delay(0.1) { [weak self]() in
            guard let `self` = self else {return}
            self.changeIcons()
        }
}

func delay(_ delay:Double, closure:@escaping ()->()) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

func changeIcons() {
        if #available(iOS 10.3, *) {
            //判断是否支持替换图标, false: 不支持
            guard UIApplication.shared.supportsAlternateIcons else { return }
            
            //如果支持, 替换icon
            DispatchQueue.main.async {
                UIViewController.runtimeReplaceAlert()
            }
//name即为info.plist中添加的各个key值
            UIApplication.shared.setAlternateIconName("2020", completionHandler: nil)
        }
    }

2、默认使用API,会有默认UIAlertController提示;如上代码,可能发现出现了一段UIViewController.runtimeReplaceAlert()的方法调用;根据弹出框无title,无message来替换系统的present方法,但是这里也要注意一点,替换完使用完,记得恢复默认,不然app中其它UIAlertController的弹出会有问题;

extension UIViewController {
    
    public class func runtimeReplaceAlert() {
           DispatchQueue.once(token: "UIAlertController") {
               let originalSelector = #selector(self.present(_:animated:completion:))
               let swizzledSelector = #selector(self.noAlert_present(_:animated:completion:))
               let originalMethod = class_getInstanceMethod(self, originalSelector)
               let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

               let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))

               if didAddMethod{
                   class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
               }else{
                   if originalMethod != nil {
                       method_exchangeImplementations(originalMethod!, swizzledMethod!)
                   }
               }
           }
       }
    
    public class func runtimeResetAlert() {
        DispatchQueue.once(token: "UIResetAlertController") {
            let swizzledSelector = #selector(self.present(_:animated:completion:))
            let originalSelector  = #selector(self.noAlert_present(_:animated:completion:))
            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))

            if didAddMethod{
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
            }else{
                if originalMethod != nil {
                    method_exchangeImplementations(originalMethod!, swizzledMethod!)
                }
            }
        }
    }

       @objc fileprivate func noAlert_present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Swift.Void)? = nil) {
           //判断是否是alert弹窗
           if viewControllerToPresent.isKind(of: UIAlertController.self) {
               print("title: \(String(describing: (viewControllerToPresent as? UIAlertController)?.title))")
               print("message: \(String(describing: (viewControllerToPresent as? UIAlertController)?.message))")

               // 换图标时的提示框的title和message都是nil,由此可特殊处理
               let alertController = viewControllerToPresent as? UIAlertController
               if alertController?.title == nil && alertController?.message == nil {
                   //更换完恢复系统默认present方法
                    DispatchQueue.main.async {
                        UIViewController.runtimeResetAlert()
                    }
                   return
               } else {
                   //其他的弹框提示正常处理
                   noAlert_present(viewControllerToPresent, animated: flag, completion: completion)
               }
           }
           noAlert_present(viewControllerToPresent, animated: flag, completion: completion)
       }

}

相关文章

网友评论

      本文标题:动态变更iOS iCON(无弹框版)

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