最近我们遇到了一个情况,想要查看用户在设备上使用的应用程序的调试信息。因此,我正在寻找一种方法,在设备上查找日志,将其作为内联文本粘贴到邮件中,并允许用户发送它。
有什么想法吗?以下是问题: 1)在设备上找到调试日志 2)打开文件并将文件内容附加为内联文本到电子邮件中。 3)允许用户在下次应用程序启动时发送邮件。
谢谢!
感谢大家的所有建议。我把你们的解决方案合并成一个,以解决我的问题。这是我做出来的东西...当然,我没有编译代码,它只是半成品...但是一旦我在我的代码中实现它,我很快就会完善它。
将NSLog记录到文件中 如何将NSLog记录到文件中 LOG2FILE
#if TARGET_IPHONE_SIMULATOR == 0
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
#endif
捕获崩溃并将其记录到文件中
首先,创建一个函数来处理错误并将其输出到控制台(以及任何其他您想要执行的操作):
void uncaughtExceptionHandler(NSException *exception) {
NSLog(@"CRASH: %@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
// Internal error reporting
}
接下来,在您的应用程序委托中添加异常处理程序:
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:
(NSDictionary*)launchOptions
{
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); // Normal launch stuff
}
在info.plist中设置一个名为“Crashed”的变量,然后通过以下方式进行读写操作
- (void)readPlist
{
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"];
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:localizedPath];
NSString *crashed;
crashed = [plistDict objectForKey:@"Crashed"];
}
- (void)writeToPlist
{
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:@"YES" forKey:@"Crashed"];
[plistDict writeToFile:filePath atomically: YES];
}
应用程序启动后读取 info.plist 文件并提示用户提交崩溃日志。
{
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;[mailComposer setSubject:@"Crash Log"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:@"first@example.com"];
[mailComposer setToRecipients:toRecipients];
// Attach the Crash Log..
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
NSData *myData = [NSData dataWithContentsOfFile:logPath];
[mailComposer addAttachmentData:myData mimeType:@"Text/XML" fileName:@"Console.log"];
// Fill out the email body text
NSString *emailBody = @"Crash Log";
[mailComposer setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:mailComposer animated:YES];
}
NSUserDefaults
呢? - Houman如果要记录自己的数据,请使用Cocoalumberjack。它比NSLog快得多,并且可以动态地打开/关闭。它还提供将数据保存到文件的选项。NSLog会减慢您的应用程序并填充控制台日志。另外,一般情况下不要记录太多日志。当崩溃发生时,您无法安全地进行日志记录。因此,一旦确定了问题区域,请在那里添加更多日志,并尝试通过使用自动化测试框架(如KIF)来重现它。
要捕获崩溃报告,您应该使用基于开源框架PLCrashReporter的解决方案,它可以安全地捕获崩溃,即使您的应用程序已经在应用商店中!不建议像其他人建议的异常捕获方法,请查看这篇文章以了解原因!
iTunes Connect也提供了查看一些崩溃报告的功能,但需要等待长达2周才能看到一些报告,而且远远不能看到所有报告,例如Camera+ developers指出的那样。所以最好使用自己的解决方案。
PLCrashReporter将向您发送标准的苹果格式的崩溃报告,可供符号化使用,因此您知道在代码中发生了崩溃,包括行号。
基于PLCrashReporter的一些解决方案包括:
所提出的解决方案都可以自动在下次启动时发送数据,或者通过询问用户是否同意发送来进行。
如果你需要在 Swift 下进行日志记录和分析,可以使用 SwiftyBeaver。它是一个功能齐全的日志平台,包括开源的 Swift 2 和 Objective-C 框架、加密云存储和 Mac 应用程序。
框架(支持):https://github.com/SwiftyBeaver/SwiftyBeaver
免责声明:我是创始人。
// on load
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
void uncaughtExceptionHandler(NSException *exception) {
NSLog(@"CRASH: %@", exception);
NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
// Internal error reporting
}
更新 我进行了一些回溯,Zane Claes在问题Xcode 4.2 debug doesn't symbolicate stack call中提供了这个解决方案。
他在第二条评论中提供了一个通用的解决方案。"我发现将崩溃日志写入文件并提示用户在下一次启动时提交(仅在发布模式下,以不妨碍调试)非常有用。这让我得到了很好的错误报告......而且用户知道他们的问题正在得到解决"。我明白并不是每个人都愿意向用户提出这个要求,但有些超级用户会乐意提供帮助。
当然,您可以包括一个“永远不再显示此提示”按钮,以便人们不会因为报告机制而感到沮丧。
或者, 您可以使用信息联系服务器(不确定它是否会工作,因为它正在崩溃,但保存它并偶尔尝试使用详细信息POST到服务器)
请参考如何查看iPhone .app文件中的NSLog语句中Ryan的答案,使用苹果提供的免费工具。
但这仍然不是一个方便的解决方案。如果你能负担得起新的构建,你应该在应用程序内部更改日志记录。Jano在如何将NSLog记录到文件中中提出了一些非常好的想法。特别是选项2应该不需要太多的努力。
总的来说,我建议在项目开始时无论使用什么编程语言,都将本地日志记录设施隐藏在门面或类似设计后面。
我已经使用以下代码来捕获调试日志 - Swift 4.1
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let fileName = "Logfile.txt"
let logFilePath = (documentsDirectory as NSString).appendingPathComponent(fileName)
freopen(logFilePath.cString(using: String.Encoding.ascii)!, "a+", stderr)