Swift:如果应用程序崩溃,则本机检测到

时间:2016-05-13 22:43:42

标签: ios swift crash nsuserdefaults

我已经四处寻找,但还没有找到一个不会引导我去第三方服务的答案。我不需要复杂的任何内容,只是为了在NSUserDefaults中保存一个值,所以当应用程序下次打开时,我会显示一条警告,说明该应用已崩溃。

感谢。

4 个答案:

答案 0 :(得分:13)

感谢@RyanCollins的一点帮助,我能够自己解决问题。 App Delegate中的函数applicationWillTerminate仅在应用正常关闭时运行。本机检测应用程序崩溃的代码如下所示。

全球定义的变量

let crashedNotificationKey = "com.stackoverflow.crashNotificationKey"
var crashedLastTime = true

应用代表

func applicationWillTerminate(application: UIApplication) {
    crashedLastTime = false
    prefs.setBool(crashedLastTime, forKey: "crash")
}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    crashedLastTime = prefs.boolForKey("crash")
    if crashedLastTime == true {

        crashedLastTime = false
        prefs.setBool(crashedLastTime, forKey: "crash")
        NSNotificationCenter.defaultCenter().postNotificationName(crashedNotificationKey, object: self)

    } else {

        crashedLastTime = true
        prefs.setBool(crashedLastTime, forKey: "crash")

    }

    return true
}

根视图控制器

override func awakeFromNib() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "crashedAlert", name: crashedNotificationKey, object: nil)
}

func crashedAlert() {
    let alert = UIAlertController(title: "The app has crashed!", message: "Sorry about that! I am just a 17 year old highschooler making my first game!", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "It's cool bro.", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alert, animated: true, completion: nil)
}

答案 1 :(得分:2)

详细信息

  • 迅速4.2
  • Xcode 10.1(10B61)

解决方案1 ​​

https://github.com/zixun/CrashEye/blob/master/CrashEye/Classes/CrashEye.swift

解决方案1的完整样本

  

!!!不要忘记复制(或安装POD)解决方案代码!!!

     

AppDelegate.swift

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        CrashEye.add(delegate: self)
        return true
    }
}

extension AppDelegate: CrashEyeDelegate {
    func crashEyeDidCatchCrash(with model: CrashModel) {
        UserDefaults.standard.set(model.reason + "(\(Date()))", forKey: "crash")
    }
}
  

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: CGRect(x: 40, y: 40, width: 80, height: 44))
        button.setTitle("BOOOM", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(boomButtonTouchedUpInside), for: .touchUpInside)
        view.addSubview(button)
    }

    override func viewDidAppear(_ animated: Bool) {
        if let date = UserDefaults.standard.string(forKey: "crash") {
            let alert = UIAlertController(title: "", message: date, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
            present(alert, animated: true)
        }
    }

    @objc func boomButtonTouchedUpInside(_ sender: Any) {
        let arr = [1, 2, 3]
        let elem = arr[4]
    }
}

解决方案2。速溶剂

  

Install Crashlytics

解决方案2的完整样本

  

AppDelegate.swift

import UIKit
import Fabric
import Crashlytics

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        Crashlytics.sharedInstance().delegate = self
        Fabric.with([Crashlytics.self])
        return true
    }
}

extension AppDelegate: CrashlyticsDelegate {
    func crashlyticsDidDetectReport(forLastExecution report: CLSReport) {
        let alert = UIAlertController(title: "\(report.dateCreated)", message: report.identifier, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        DispatchQueue.global(qos: .background).async {
            sleep(3)
            DispatchQueue.main.async {
                self.window?.rootViewController?.present(alert, animated: true)
            }
        }
    }
}
  

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: CGRect(x: 40, y: 40, width: 80, height: 44))
        button.setTitle("BOOOM", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(boomButtonTouchedUpInside), for: .touchUpInside)
        view.addSubview(button)
    }

    @objc func boomButtonTouchedUpInside(_ sender: Any) {
        let arr = [1, 2, 3]
        let elem = arr[4]
    }
}

结果

  1. 启动应用
  2. 按下“ Booom”按钮(应用会崩溃)
  3. 再次提供午餐应用

    enter image description here

答案 2 :(得分:1)

问题是,如果应用程序崩溃了,那么就无法运行代码来写入NSUserDefaults。

我所知道的最佳解决方案是使用PLCrashReporter(https://plcrashreporter.org

答案 3 :(得分:1)

FirebaseCrashlytics

如果不赞成使用Fabric,则需要在Updagte to the Firebase Crashlytics SDK中提到的ViewController中使用以下代码。

我这样使用它:

// 1. import Crashlytics
import FirebaseCrashlytics

class YOUR_ROOT_VIEW_CONTROLLER {

   override viewDidLoad(){
       //...

       // 2. register to get the notifications
       self.configCrashlytics()

       // ...
   }

    func configCrashlytics() {
        /* You must set setCrashlyticsCollectionEnabled to false in order to use
        checkForUnsentReportsWithCompletion. */

        Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(false)

        Crashlytics.crashlytics().checkForUnsentReports { hasUnsentReport in
          let hasUserConsent = false
          // ...get user consent.

          if hasUserConsent && hasUnsentReport {
            Crashlytics.crashlytics().sendUnsentReports()
          } else {
            Crashlytics.crashlytics().deleteUnsentReports()
          }
        }

        // Detect when a crash happens during your app's last run.
        if Crashlytics.crashlytics().didCrashDuringPreviousExecution() {
          // ...notify the user.
            DispatchQueue.main.async {
                let alert = Utils.shared.errorAlert(title: "Sorry!", message: "This App was crashed during last run")
                self.present(alert, animated: true, completion: nil)
            }
        }
        
    }
    // 4. Add a button that run fatallError()
    @IBAction func crashApp(_ sender: UIButton) {
        fatalError()
    }
}