您的位置:首页 > 移动开发 > Swift

swift动态替换应用图标

2017-12-27 14:37 666 查看
近期需求中有一个需要动态替换应用图标的功能,查了下相关资料:在ios10.3之前是无法实现的,你只能提前发布拥有新应用图标的版本,来满足某个节日;节后,再发布一版,改回图标。从ios10.3开始,苹果提供了动态替换应用图标的API。至于api说明,请看苹果帮助,下面我们就按步骤实现这个功能。

1、准备好替换图标,我准备了春、夏、秋、冬四种替换图标,详见Demo。
2、在项目plist文件的根字典中添加如下:

<dict>
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>春</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>春Icon-Small-20</string>
<string>春Icon-60</string>
<string>春Icon-Small-29</string>
<string>春Icon-Small-40</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>夏</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>夏Icon-Small-20</string>
<string>夏Icon-60</string>
<string>夏Icon-Small-29</string>
<string>夏Icon-Small-40</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>秋</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>秋Icon-Small-20</string>
<string>秋Icon-60</string>
<string>秋Icon-Small-29</string>
<string>秋Icon-Small-40</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>冬</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>冬Icon-Small-20</string>
<string>冬Icon-60</string>
<string>冬Icon-Small-29</string>
<string>冬Icon-Small-40</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
</dict>


即下图所示



3、在视图控制器中添加五个按钮:"春"用于替换春字图标,"夏"用于替换夏字图标, "秋"用于替换秋字图标, "冬"用于替换冬字图标,按钮"原始"用于恢复原始标, 点击实现如下:

    
/// 春天图标
@IBAction func 春Clicked(_ sender: UIButton) {

if #available(iOS 10.3, *) {
if UIApplication.shared.supportsAlternateIcons {
print("替换前图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
//当前显示的是原始图标
UIApplication.shared.setAlternateIconName("春", completionHandler: { (error: Error?) in
print("替换后图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
})
}
}
}

/// 夏天图标
@IBAction func 夏Clicked(_ sender: UIButton) {
if #available(iOS 10.3, *) {
if UIApplication.shared.supportsAlternateIcons {
print("替换前图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
//当前显示的是原始图标
UIApplication.shared.setAlternateIconName("夏", completionHandler: { (error: Error?) in
print("替换后图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
})
}
}
}

/// 秋天图标
@IBAction func 秋Clicked(_ sender: UIButton){
if #available(iOS 10.3, *) {
if UIApplication.shared.supportsAlternateIcons {
print("替换前图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
//当前显示的是原始图标
UIApplication.shared.setAlternateIconName("秋", completionHandler: { (error: Error?) in
print("替换后图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
})
}
}
}

/// 冬天图标
@IBAction func 冬Clicked(_ sender: UIButton){
if #available(iOS 10.3, *) {
if UIApplication.shared.supportsAlternateIcons {
print("替换前图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
//当前显示的是原始图标
UIApplication.shared.setAlternateIconName("冬", completionHandler: { (error: Error?) in
print("替换后图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
})
}
}
}

/// 原始图标
@IBAction func primaryClicked(_ sender: UIButton){
if #available(iOS 10.3, *) {
if UIApplication.shared.supportsAlternateIcons {
print("替换前图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
//当前显示的是原始图标
UIApplication.shared.setAlternateIconName(nil, completionHandler: { (error: Error?) in
print("替换后图标:\(UIApplication.shared.alternateIconName ?? "原始图标")")
})
}
}
}


4、运行程序,点击按钮,会出现如下alert, 你切到主屏幕界面会发现应用图标已替换。




  

  




5、对于每次替换图标就弹出个提示,我个人觉得不太爽,需要想办法去掉。替换原理是:因为alert是通过UIViewController的present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Swift.Void)? = nil)方法弹出的,我们只要修改该消息的实现,他就不会弹出了。这里就要用到OC的swizzling method技术,swift默认是静态绑定方法实现的,需要对想拥有动态消息特征的方法添加
@objc dynamic修饰符。这里只谈实现,至于OC的相关技术大家自行了解。

在视图控制器中添加如下三个方法:

    //利用runtime指定方法实现

    func runtimeRemoveAlert() -> Void {        

        if let presentM = class_getInstanceMethod(type(of: self), #selector(present(_:animated:completion:))),

            let presentSwizzlingM = class_getInstanceMethod(type(of: self), #selector(temporary_present(_:animated:completion:))){

            method_exchangeImplementations(presentM, presentSwizzlingM)

        }

    }

    //利用runtime恢复方法实现

    func runtimeResetAlert() -> Void {

        if let presentM = class_getInstanceMethod(type(of: self), #selector(present(_:animated:completion:))),

            let presentSwizzlingM = class_getInstanceMethod(type(of: self), #selector(temporary_present(_:animated:completion:))){

            method_exchangeImplementations(presentM, presentSwizzlingM)

        }

    }

    

    //在自己实现中特殊处理

    @objc dynamic func temporary_present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Swift.Void)? = nil){

        if viewControllerToPresent.isKind(of: UIAlertController.self) {

            if let alertController = viewControllerToPresent as? UIAlertController{

                //通过判断title和message都为nil,得知是替换icon触发的提示。

                if alertController.title == nil && alertController.message == nil {

                    return;

                }

            }

        }

        

        self.temporary_present(viewControllerToPresent, animated: flag, completion: completion)

    }

6、在视图控制器中如下调用:

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)

        self.runtimeRemoveAlert()

    }

    

    override func viewWillDisappear(_ animated: Bool) {

        super.viewWillDisappear(animated)

        self.runtimeResetAlert()

    }

    

7、为了验证对正常的alert展示没有影响,在视图控制器中添加“alert”按钮,对于点击处理如下:

    @IBAction func alertClicked(_ sender: UIButton) {

        let title = "title"

        let msg = "message"

        let cancelTitle = "cancel"

        let okTitle = "ok"

        

        let alertController = UIAlertController(title: title, message: msg, preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) { (action: UIAlertAction) in

            print("cancel")

        }

        

        let okAction = UIAlertAction(title: okTitle, style: .default) { (action: UIAlertAction) in

            print("ok")

        }

        

        alertController.addAction(cancelAction)

        alertController.addAction(okAction)

        

        self.present(alertController, animated: true) {

            

        }

    }

    

    

 8、运行发现替换图标时,提示已不再出现;但是聪明的你会发现,这时completionHandler没被调用,因为他是前面展示的Alert后,点击OK按钮触发的。

 工程下载地址https://github.com/qianlima210210/AlternateIconsDemo.git

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐