iOS swift : Send log information to iOS app from iOS framework

标签 ios swift crashlytics

我正在尝试了解如何将日志信息从我的 iOS 框架发送到我的 iOS 应用程序。在我的 iOS 应用程序中,我有 Crashlytics 设置,并且每当我从应用程序以及 iOS 框架获取一些日志时,我都希望使用 Crashlytics.sharedInstance().recordError(error)

我阅读了多个答案,提到Crashlytics只能在应用程序中初始化一次,不建议在框架中再次初始化。 (例如 Link 1 ), Link 2 , Link 3 )

有人有针对这种要求的有效解决方案吗?

编辑1(从我的框架中添加更多代码,我需要从中获取错误)

public final class MyAppSession {

    public fileprivate(set) var isValid: Bool = false

    let itemKey = MyAppSession.MyAppKeychainAccount
    let keychainAccessGroupName = MyAppConfigured?.keyChainGroup

    /**
     Attempts to restore a locally stored session.
     */
    public static func savedSession() -> MyAppSession? {

        do {

            let itemKey = MyAppSession.MyAppKeychainAccount
            let keychainAccessGroupName = MyAppConfigured?.keyChainGroup

            let queryLoad: [String: AnyObject] = [
                kSecClass as String: kSecClassGenericPassword,
                kSecAttrAccount as String: itemKey as AnyObject,
                kSecReturnData as String: kCFBooleanTrue,
                kSecMatchLimit as String: kSecMatchLimitOne,
                kSecAttrAccessGroup as String: keychainAccessGroupName as AnyObject
            ]

            var result: AnyObject?

            let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
                SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
            }

            if resultCodeLoad == noErr {
                if let result = result as? Data {
                    if let arrayFromData = NSKeyedUnarchiver.unarchiveObject(with: result) as? NSDictionary {
                        // Found successfully
                        return MyAppSession(accessToken: (arrayFromData["accessToken"] as? String)!, refreshToken: (arrayFromData["refreshToken"] as? String)!)
                    }
                }
            } else {
                MyApp.log("No Keychain elements present.", logLevel: .verbose)
                MyAppLogger.sendLogs(message: "Logger Test. No Keychain elements present.")
            }

            let keychainData = try Locksmith.loadDataForUserAccount(userAccount: MyAppSession.MyAppKeychainAccount)
            if let accessToken = keychainData?[MyAppSession.accessTokenKeychainKey] as? String,
                let refreshToken = keychainData?[MyAppSession.refreshTokenKeychainKey] as? String {

                MyApp.log("Restored saved session.", logLevel: .verbose)

                return MyAppSession(accessToken: accessToken, refreshToken: refreshToken)

            }
            else {
                return nil
            }

        }
        catch {
            return nil
        }

    }

    init?(accessToken: String, refreshToken: String) {

        // Save credentials to the keychain.
        do {

            try Locksmith.updateData(
                data: [MyAppSession.accessTokenKeychainKey: accessToken as AnyObject, MyAppSession.refreshTokenKeychainKey: refreshToken as AnyObject],
                forUserAccount: MyAppSession.MyAppKeychainAccount)

            if let configuration = MyAppConfigured {
                if configuration.keyChainGroup == "" {
                    let valueData = [MyAppSession.accessTokenKeychainKey: accessToken as AnyObject, MyAppSession.refreshTokenKeychainKey: refreshToken as AnyObject]

                    let data = NSKeyedArchiver.archivedData(withRootObject: valueData)

                    let queryAdd: [String: AnyObject] = [
                        kSecClass as String: kSecClassGenericPassword,
                        kSecAttrAccount as String: itemKey as AnyObject,
                        kSecValueData as String: data as AnyObject,
                        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
                    ]

                    let resultCode = SecItemAdd(queryAdd as CFDictionary, nil)

                    if resultCode != noErr {
                        MyApp.log("Keychain groupname empty: \(resultCode)", logLevel: .verbose)
                    }
                    else {
                        MyApp.log("KeyChain Saving Success", logLevel: .verbose)
                    }

                }

                else {
                    let valueData = [MyAppSession.accessTokenKeychainKey: accessToken as AnyObject, MyAppSession.refreshTokenKeychainKey: refreshToken as AnyObject]

                    let data = NSKeyedArchiver.archivedData(withRootObject: valueData)

                    let queryAdd: [String: AnyObject] = [
                        kSecClass as String: kSecClassGenericPassword,
                        kSecAttrAccount as String: itemKey as AnyObject,
                        kSecValueData as String: data as AnyObject,
                        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
                        kSecAttrAccessGroup as String: keychainAccessGroupName as AnyObject
                    ]

                    let resultCode = SecItemAdd(queryAdd as CFDictionary, nil)

                    if resultCode != noErr {
                        MyApp.log("Error saving to Keychain: \(resultCode)", logLevel: .verbose)
                    }
                    else {
                        MyApp.log("KeyChain Saving Success", logLevel: .verbose)
                    }
                }
            }

            isValid = true

            MyApp.log("Created new session.")

        }
        catch {
            return nil
        }

    }
}

最佳答案

一种选择是将错误日志记录委托(delegate)给您的应用程序。这使得它更加灵活。

例如:

protocol MyFrameworkErrorHandlingDelegate: AnyObject {
    func didReceiveError(_ error: Error)
}

然后在您的应用程序中,您可以创建此默认扩展

extension MyFrameworkErrorHandlingDelegate {
     func didReceiveError(_ error: Error) {
         Crashlytics.sharedInstance().recordError(error)
     }
}

这种方法的问题是决定在哪里使用它或在哪里分配委托(delegate),这取决于您的框架的作用以及您的应用程序如何使用该框架。

编辑:

免责声明:这不是最有效的方法,但它是最直接的方法。

protocol MyFrameworkErrorHandlingDelegate: AnyObject {
    func didReceiveError(_ error: Error)
}

class MyAppLogger {

    static var delegate: MyFrameworkErrorHandlingDelegate?

    static func log(_ error: Error) {
        delegate?.didReceiveError(error)
    }
}

class AppDelegate: UIApplicationDelegate, MyFrameworkErrorHandlingDelegate

稍后在您的 AppDelegate 中

MyAppLogger.delegate = self

关于iOS swift : Send log information to iOS app from iOS framework,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58592948/

相关文章:

ios - Kingfisher 默认缓存行为是什么?

file-type - 无法让 "Open in MyApp"在我的 iOS 应用程序中处理 PNG 或 JPG 邮件附件

ios - Swift 2 中的内存字符串压缩

android - 如何通过正确的 Crashlytics 错误分组获得更好的 RxJava 堆栈跟踪

ios - 为 iOS 应用程序中的 UIWebView 预填充 HTML5 离线应用程序缓存

swift - 通用 [T.Generator.Element] 初始值设定项

c++ - 在 XCode 中桥接 C++ 和 Swift,正确的build设置是什么?

ios - 了解 Fabrics 的崩溃日志

ios - 缺少 DSYM 以处理崩溃

ios - swift 中的 CollectionViewFlowLayout 的 collectionViewContentSize()