levibostian / iOSBlanky

My opinionated iOS app boilerplate
MIT License
6 stars 5 forks source link

Fix Fabric/Crashlytics #10

Closed levibostian closed 5 years ago

levibostian commented 6 years ago

I created an app that started from this project's setup. As it turned out, I released it to the store and every app crashed for every user when they updated it on their devices.

I did not get notified from Fabric/Crashlytics because of the way I had it installed. I looked more into the fabric docs and found out what to do to fix it.

  1. Edit AppDelegate to be like this:
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        ... stuff here for setup. 

        // Make sure fabric is last. 
        #if !DEBUG
            Fabric.with([Crashlytics.self])
            DDLog.add(CrashlyticsCocoaLumberjackLogger.sharedInstance)
        #endif

        return true
    }

Also in the AppDelegate, remove the crashlytics delegate stuff.

That's pretty much it. This is a better way to install Fabric and install it only on release builds.

  1. Add better crash logging support using CocoaLumberjack.
//
//  CrashlyticsCocoaLumberjackLogger.swift
//
//  Created by Levi Bostian on 10/30/17.
//  Copyright © 2017 Curiosity IO. All rights reserved.
//
import Foundation
import CocoaLumberjack
import Crashlytics

class DefaultCrashlyticsLogFormatter: NSObject, DDLogFormatter {
    func format(message logMessage: DDLogMessage) -> String? {
        // Formatter found: https://github.com/CocoaLumberjack/CocoaLumberjack/blob/master/Framework/iOSSwift/Formatter.swift
        let threadUnsafeDateFormatter = DateFormatter()
        threadUnsafeDateFormatter.formatterBehavior = .behavior10_4
        threadUnsafeDateFormatter.dateFormat = "HH:mm:ss.SSS"
        let dateAndTime = threadUnsafeDateFormatter.string(from: logMessage.timestamp)

        var logLevel: String
        let logFlag = logMessage.flag
        if logFlag.contains(.error) {
            logLevel = "E"
        } else if logFlag.contains(.warning) {
            logLevel = "W"
        } else if logFlag.contains(.info) {
            logLevel = "I"
        } else if logFlag.contains(.debug) {
            logLevel = "D"
        } else if logFlag.contains(.verbose) {
            logLevel = "V"
        } else {
            logLevel = "?"
        }

        let formattedLog = "\(dateAndTime) |\(logLevel)| [\(logMessage.fileName) \(logMessage.function ?? "nil")] #\(logMessage.line): \(logMessage.message)"

        return formattedLog
    }
}

class CrashlyticsCocoaLumberjackLogger: DDAbstractLogger {
    static let sharedInstance = CrashlyticsCocoaLumberjackLogger()

    let formatter: DDLogFormatter = DefaultCrashlyticsLogFormatter()

    override func log(message logMessage: DDLogMessage) {
        let formattedMessage = formatter.format(message: logMessage)
        CLSLogv("%@", getVaList([formattedMessage ?? "(unknown log message)"]))
    }

}

So now, when you want to log errors in the app, use DDLogError() and it will be reported to Crashlytics.

levibostian commented 5 years ago

No need for this. Crashlytics has been updated to no longer need this setup.