I am writing codes for a project where i can not use several crash reporting tools due to some privacy issue. So i am searching to manage a send email having crash report if crash occurs without the involvement of third party reporting tool.
In your application delegate declare API like:
void uncaughtExceptionHandler(NSException * exception)
{
// Here you can:
// 1. Set some boolean in user defaults that app crashed.
// 2. Dump this data (below) in some file in documents directory.
NSLog(#"Uncaught Exception: %#", exception.reason);
NSLog(#"CrashSymbols: %#", exception.callStackSymbols);
}
Then set in "application:didFinishLaunchingWithOptions:":
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
Then when your application next launches, if boolean (1) is set in user defaults, read this data (2) and email.
You can use PLCrashReporter framework in your iOS application, whenever the application is started, it should search for saved crash logs then send email using MFMailViewComposer.
https://www.plcrashreporter.org/
Related
How to report on iOS a non-fatal exception using Firebase Crash Reporting? In Android, we can do something like this:
FirebaseCrash.report(new Exception("My first Firebase non-fatal error on Android"));
You can now log non-fatal exceptions in Firebase Crashlytics
The accepted answer is therefore no longer correct. Non-fatal exceptions can be logged with the following Firebase Crashlytics method:
Crashlytics.crashlytics().record(error: error)
From the documentation:
This allows you to record a non-fatal event, described by an NSError object. These events will be grouped and displayed similarly to crashes. Keep in mind that this method can be expensive. Also, the total number of NSErrors that can be recorded during your app's life-cycle is limited by a fixed-size circular buffer. If the buffer is overrun, the oldest data is dropped. Errors are relayed to Crashlytics on a subsequent launch of your application.
Example usage:
let userInfo: [String: String] = [
"deviceId": "someDeviceId",
"localizedDescription": yourException.localizedDescription,
"anotherKey": "anotherValue"
]
let domain = "METHOD: some/domain/that/just/had-an-exception"
let code = 404
let error = NSError(domain: domain, code: code, userInfo: userInfo)
Crashlytics.crashlytics().record(error: error)
Where domain is some pretty identifier for use in Firebase (e.g. method + request path), code is the status code of the exception (a 404 here), and userInfo additional data are converted to key-value pairs and displayed in the keys/logs section within an individual issue.
Note: Logged errors are grouped by the NSError domain and code (unlike fatals, which are grouped in Firebase by their stack trace).
Example output in Firebase Console > Crashlytics:
Issue details page in the console (showing userInfo key-value pairs):
Jen's answer is correct. There are a few alternatives you can consider, though:
Log a Firebase Analytics event. While this won't give you all the stack tracey goodness you get from Firebase Crash Reporting, you can at least keep track of how often a particular exception is happening over time.
Use the FIRCrashMessage() method to make note of any errors that occur in your app. You will only see these log methods in crash reports that end up getting reported to Firebase Crash Reporting, but given that errors often lead to crashes, this isn't such a bad idea.
Try Crashlytics. They have a reportError() method that's specifically designed for reporting non-fatal errors. It's fine to use Crashlytics for your crash reporting while continuing to use other features of Firebase within your app -- it's all the same parent company these days. :)
According to the documentation, you can only report fatal errors on iOS at this time.
I'm developing an iOS app using MFP 7.0.
Each screen (i.e., view controller) has a unique ID, and I am supposed to use Operational Analytics to send the following info to the server:
How long the user spent on each screen
On which screen the app crashed
Regarding #1, I guess I am supposed to use WLAnalytics's
- (void) log:(NSString*)message withMetadata:(NSDictionary*)metadata;
(right?)
How can I manage #2? Should I just log the screen ID (using the method above) every time a transition occurs, and expect the last logged id to be passed when the crash log is sent? Or is there any other way to add custom information to crash logs?
Correct you can follow Custom Data, Custom Charts here https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/7.0/moving-production/operational-analytics/
Crash log is detected and sent automatically post crash next time app is started. There is no way to add custom data to that report. Usually the place where the error happen could be deduced form the crash data stack, if this is not sufficient, you can apply the technique you are describing.
The main idea is to catch the crash log (or the reason of the error) and send it to a server.
I know that iTunes does log the crashes from the users' devices but I need to find if there's a way to get it and store it on our server.
I was trying "PlCrashReporter" and i finished implementing it (as they did on this link https://www.plcrashreporter.org/documentation/api/v1.0/example_usage_iphone.html).
Problem
The function applicationDidFinishLaunching is not called when the crash occurs.
Am I on the right track?
Is there a specific function which is called upon a crash in AppDelegate ?
Thanks in advance
EDIT
I've also tried the solution of the following question:
iOS crash log catch, debug info.. Catch and send via email to the Dev team
It actually works but there are some errors that are cause by Swift and not Objective-C (Like Error while unwrapping optional value) were not caught..
Any suggestions?
You should use Crashlytics. You then can use a custom web hook to receive the crash reports.
When running an iOS app in the simulator, there's an environment variable NSObjCMessageLoggingEnabled that causes all objc_msgSend calls to be logged out to a file. (Detailed explanation).
I'm trying to trace out all the messages that are being sent in my app, but I can't run it in the simulator. It has to be on a physical device because I'm interacting with hardware through the lightning connector. For the same reason, I can't attach a debugger to the process.
It would be helpful to write a log to disk like the one created with NSObjCMessageLoggingEnabled, but write it locally in my app's Documents directory, or similar.
Is this possible?
All NSObjCMessageLoggingEnabled does is cause CoreFoundation to automatically call instrumentObjcMessageSends at startup and shutdown.
The problem is that Apple has intentionally hidden that function in the native iOS SDK, so you can't just call it.
But it still exists in the dylib at runtime, so you can always do this:
#include <dlfcn.h>
typedef void functype(BOOL);
void *libobjc = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY);
functype *instrumentObjcMessageSends = dlsym(libobjc, "instrumentObjcMessageSends");
if (!instrumentObjcMessageSends) {
NSLog(#"Couldn't get instrumentObjcMessageSends");
exit(1);
}
instrumentObjcMessageSends(YES);
NSLog(#"Did it");
I have no idea where, if anywhere, the logs are being written to. I assume you're going to want to call logObjcMessageSends to register your own ObjCLogProc, as explained in the post you linked to.
I have an app in the app store and am using a logging service to get crash logs and associated log data. I am seeing an intermittent crash (low # of users affected and low # of crashes per user) but it is baffling me.
What happens in these crashes is the following:
App launches and initializes Core Data stack
App attempts to add a SQL store to the NSPersistentStoreCoordinator with the following code (storeURL is valid):
NSDictionary *options = #{
NSMigratePersistentStoresAutomaticallyOption : #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)
};
sqlStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error];
One of the following errors occur when adding this store:
NSError:
Domain=NSCocoaErrorDomain
Code=256 "The operation couldn’t be completed. (Cocoa error 256.)"
UserInfo=0x1dd946a0 {NSUnderlyingException=authorization denied, NSSQLiteErrorDomain=23}
or
NSError:
Domain=NSCocoaErrorDomain
Code=256 "The operation couldn’t be completed. (Cocoa error 256.)"
UserInfo=0xc6525d0 {NSUnderlyingException=disk I/O error, NSSQLiteErrorDomain=10}
After this condition, the app will crash b/c the SQL store is required for the app to function. I could attempt to gracefully handle this failure by trying a new storeURL but I don't want the user to lose existing data. Also, I have never personally reproduced this issue and based on the low number of users affected and crash logs I believe it is a low impact problem and does not recur on a subsequent app launch.
I'm hoping there's a Core Data guru out there with some suggestions on how to debug and prevent/handle these conditions. My core data stack initialization code is straight from the xcode project generator and I have ruled out any concurrency issues in that the persistent store coordinator is only initialized once (on launch) and this error occurs in this initialization.
Happy to provide more code/info if relevant.
thanks!
It looks like XJones and I have been able to locate the cause of this. It appears to be an iOS edge-case bug or undocumented behavior. I've filed this under Apple bug ID 12935031.
There is an unaccounted for scenario where an application using Core Location significant location change or region monitoring can fail to launch properly (or have other unintended consequences) due to the fact that as of iOS 5, Core Data stores use data protection (encryption) by default.
Steps to Reproduce:
1) Turn on pass code protection on the device
2) Create an application that starts Significant Location Monitoring or Region Monitoring and keeps it started even when in the background. Ie. An app that uses background significant location change or region monitoring.
3) Wait for the battery on the device to run out (there may be other causes as well)
4) The device will shut down
5) Connect the device to the Mac
6) Once the charge is adequate, the device will boot. Important: Do not unlock device at this time.
7) Exit or enter the monitored range or cause a significant change in location to occur. The device will now automatically relaunch the application, because it registered for Significant Location Monitoring or Region Monitoring
8) However, since the device has not been unlocked by the user (pass code not yet entered), the application will not be able to read any of its protected data files. In a Core Data application, this will cause the persistent store coordinator to fail to add the persistent store file to the managed object context. This will cause the app to crash or depending on the code used by the developer even attempt to reset the database. In other apps it may cause crashes for other reasons as this is an unexpected, undocumented side effect of the data protection feature being turned on by default for Core Data stores in iOS 5 and later.
The solution or workaround until Apple corrects this or at least documents it is to either make sure your application stops monitoring significant location changes/regions in applicationWillTerminate or to turn off the default data protection feature by setting NSFileProtectionNone for the NSFileProtectionKey key in the options dictionary when adding the Core Data store to the persistent store coordinator. to wait for the file store to become available using a while() loop that checks for the protected data to become available. There may be other ways of doing this using KVO, but this method works reliably and is easiest to insert into existing code without reworking your entire application startup process.
Update: looks like just setting that key is not enough if data protection is already active on the store. You have to manually set it:
[[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey] ofItemAtPath:storePath error:nil];
Here's the fix for apps that need background location monitoring, thanks to more input from XJones and a bit more research in Apple's scattered docs:
while(![[UIApplication sharedApplication] isProtectedDataAvailable]) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]];
}
This code goes in before you attempt to add the store data file to the persistent store coordinator.
Update 2015: You can also set NSPersistentStoreFileProtectionKey to NSFileProtectionNone. This will properly disable file protection (if you don't need it) and just work without requiring any workarounds. The reason it did not work in previous attempts is because the dictionary key I was testing with was incorrect.
I just noticed the following notifications in the UIApplication docs:
UIApplicationProtectedDataDidBecomeAvailable
UIApplicationProtectedDataWillBecomeUnavailable
These are available in iOS 4.0 and later. #lupinglade, I think you need to observe these notifications and only access your protected files (i.e. the store) after you recieve UIApplicationProtectedDataDidBecomeAvailable.
The solution #lupinglade pretty much worked in my case (VoIP app had when starting up from a reboot), but I would also like to point out that there's a delegate function for AppDelegate that is called when protected data becomes available:
applicationProtectedDataDidBecomeAvailable:
This made it a bit easier to implement the solution in my case.
According to the header file it's available from iOS 4 onwards.
Same problem here, still have not been able to find a solution. I've found it seems to be related to having a lock code set on the device. WIthout the lock code I could never reproduce the error, now I have been able to a bunch of times. Console log is:
Error is: Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x1fd80110 {NSUnderlyingException=authorization denied, NSSQLiteErrorDomain=23}
File does exist and not using any encryption.