我正在尝试了解如何将日志信息从我的 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/