Reputation: 2721
We built an app using React Native to improve UX and features of our previous Cordova app.
Everything went fine. Several months of development, QA, App review and then we published to App Store. It worked on all devices we tried, from iPhone 4s to iPhone 6s+, we tested on iOS 8.3 (earliest simulator you can download through xCode) to 10.0.
After release lots of users started reporting that app crashes before splash screen even goes away. Behaviour we haven't seen in the app review, testing or anywhere else before.
We investigated "crashes" in xCode and they obviously didn't show up, because hundreds of users experienced a crash and we were able to only see few - which seemed unrelated to startup.
We released an updated version with Crashlytics integrated, but that didn't help either. We do not get Crashlytics errors for this specific problem either, meaning that problem is probably happening before
Any ideas where should I look next? We really do not want to revert to the old version and lose months of work.
The app uses around ~100MB of memory when everything is loaded, so that shouldn't be a problem I presume. It is happening on all versions of iOS across all devices. We cannot isolate the error to only specific users.
Upvotes: 11
Views: 4316
Reputation: 1779
When there doesn't seem to be any other avenue of analysis, I resort to the humble fall-back of logging.
I have previously used the following technique in production iOS apps. This is a bit of work to set up, but once going it is tremendously useful for many other problems in the future. Not just crashes, but any other strange behaviour that users report which you cannot replicate in your testing environments.
Many variations on this are possible. Including things like only enable logging if the user has configured a setting for it. You may have to add a whole lot of logging around particular areas of code sometimes when a user reports a particular problem, and then delete it again after the problem is resolved (if you are concerned about the performance/storage issues around logging).
For my (Objective-C) app, the places for including my code to write startup status to defaults were as below (there may be better places more suitable for your app):
application:didFinishLaunchingWithOptions:
viewDidAppear
(NOT viewWillAppear
! there's a lot of stuff can go wrong between these two being sent)UPDATE:
Logging in iOS is a LOT better than it used to be when this post was first written, so I've removed the clunky custom Objective-C NSLog() and stdout file redirection instructions I originally had in this post. Instead I now (using Swift) do something like this, at the global level (eg, in AppDelegate
):
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "app")
(Optionally, you can have multiple loggers which will identify themselves in each log line. I also have another one in one of my apps to which I redirecdt all JavaScript logging from a web view, like:
let jsLogger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "JS")
Then to actually write to the logs, use something like:
logger.log("Some message being logged: \(some variable, privacy: .public)")
Then to gather actual logs (eg, if the user hit's the 'Send Logs' button in a 'Diagnostics' view of the 'Settings' UI):
guard let logStore = try? OSLogStore(scope: .currentProcessIdentifier) else { return }
let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
guard let allEntries = try? logStore.getEntries(at: oneHourAgo) else { return }
let filteredEntries = allEntries.compactMap { $0 as? OSLogEntryLog }.filter { $0.subsystem == Bundle.main.bundleIdentifier! }
var logText = ""
for entry in filteredEntries {
logText.append(contentsOf: "\(entry.date): \(entry.composedMessage)\n")
}
let logData = Data(logText.utf8)
Then attach the logData
to an email ready to send to support (eg, using a MFMailComposeViewController
.)
Upvotes: 6
Reputation: 1270
I had this issue and my case might be quite specific but I'll share my experience anyway.
The point here is the app only crashes in production, so it's something that's fired only on production that is messing up the build. In our case, the culprit was one of the React's dependencies that does minification.
Things to take away:
Upvotes: 0
Reputation: 2721
The problem took so long to resolve because of bad communication between us and our users. App was actually NOT crashing, just not starting up (which is the same in the eyes of some users).
After we discovered that, we realized that one of the events is not firing (the one that hides extended splash screen) and this is where users got stuck. One of the libraries we were using didn't correctly handle the error scenario and it made our job much harder. I was lucky to get into that state while testing and I could continue from there.
I updated the code to handle that scenario and the issue is now resolved.
Upvotes: 3