动态替换App icon

领导提了个定时替换icon的需求,简单记录一下
怎么把备用icon添加到项目就不多说了
1.替换icon的方法

class func replaceAppIcon(iconName: String) {
        if #available(iOS 10.3, *) {
            if UIApplication.shared.supportsAlternateIcons {
                debugPrint("you can change this app's icon")
            } else {
                debugPrint("you cannot change this app's icon")
                return
            }
            
            if let name = UIApplication.shared.alternateIconName {
                // 传 nil 恢复默认 icon 也就是Assets里AppIcon
//                UIApplication.shared.setAlternateIconName(nil) { (err:Error?) in
//                    print("set icon error:\(String(describing: err))")
//                }
                debugPrint("the alternate icon's name is \(name)")
            } else {
                // 指定icon图标 备用icon
                UIApplication.shared.setAlternateIconName(iconName) { (err:Error?) in
                    debugPrint("set icon error:\(String(describing: err))")
                }
            }
        }
    }

2.禁止系统弹窗提示
交换方法还是得慎用,不得已用修改完后一定要充分测试,不然线上出问题就难受了

// 替换AppIcon禁止弹框
extension UIViewController {
    public class func replaceSystemPresent(){
        let originalSelector = #selector(UIViewController.hzpresent(viewControllerToPresent:animated:completion:))
        let swizzledSelector = #selector(UIViewController.present(_:animated:completion:))

        let originalMethod = class_getInstanceMethod(self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

        //在进行 Swizzling 的时候,需要用 class_addMethod 先进行判断一下原有类中是否有要替换方法的实现
        let didAddMethod: Bool = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
        //如果 class_addMethod 返回 yes,说明当前类中没有要替换方法的实现,所以需要在父类中查找,这时候就用到 method_getImplemetation 去获取 class_getInstanceMethod 里面的方法实现,然后再进行 class_replaceMethod 来实现 Swizzing
        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
        } else {
            method_exchangeImplementations(originalMethod!, swizzledMethod!)
        }
    }

    @objc func hzpresent(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?) {
        if let alertC = viewControllerToPresent as? UIAlertController {
            if alertC.title == nil && alertC.message == nil {
                // 查看私有属性
                if let contentViewController = alertC.value(forKey: "_contentViewController") {
                    // 判断_contentViewController的值是否为_UIAlternateApplicationIconsAlertContentViewController
                    let tempStr = "_UIAlternateApplicationIconsAlertContentViewController"
                    let classStr = String(describing: contentViewController.self)
                    if classStr.contains(tempStr) {
                        if completion != nil {
                            completion!()
                        }
                        return
                    }
                }
            }
        }
        self.hzpresent(viewControllerToPresent: viewControllerToPresent, animated: animated, completion: completion)
    }
}

3.获取私有属性


func getBridgedPropertyList(anyClass: AnyClass) -> Set {
        var propertyList = Set()
        if let superClass = class_getSuperclass(anyClass), superClass != NSObject.self {
            propertyList = propertyList.union(getBridgedPropertyList(anyClass: superClass))
        }
        let count = UnsafeMutablePointer.allocate(capacity: 1)
        if let props = class_copyPropertyList(anyClass, count) {
            for i in 0 ..< count.pointee {
                let name = String(cString: property_getName(props.advanced(by: Int(i)).pointee))
                propertyList.insert(name)
            }
            free(props)
        }
        #if swift(>=4.1)
        count.deallocate()
        #else
        count.deallocate(capacity: 1)
        #endif
        return propertyList
    }

你可能感兴趣的:(动态替换App icon)