Search code examples
iosxcodeunity-game-enginecrashtestflight

(Unity 2019.2) iOS build crashes 5 seconds after the application is killed by the user


Description

The application presents a crash 2~5 seconds after it's terminated by the user (i.e. force kill the app). This happens only on iOS builds on multiple unity versions (see details below). Most of the crashes reports are not arriving on Crashlytics. There are very few crashes on the console, even though we're consistently reproducing this error on a daily basis. The Android builds don't present the same error.

Steps to reproduce

  1. Open the game
  2. Wait until the loading scene is about to finish or until the game scene is fully loaded
  3. Kill the application
  4. Wait 2~5 seconds and see the crash report window

  • Reproduction rate: 80%
  • Devices used to test: iPhone SE, iPhone 7, iPhone 8, iPad Mini 4
  • Also observed the crash on: iPhone XS, iPhone XR

Additional information

  • The issue is iOS specific. We have the same build on Android working without issues.
  • Crash reports are not being captured by Crashlytics on most cases (see some of the crashes below).
  • Crashes happen only on the final steps of the loading, where the external SDKs are being initialized.
  • On TestFlight, the crash count is 0 for almost all builds, including the ones the users are reporting the crashes.
  • Using a debug button that calls the Application.Quit() method of Unity doesn't cause the application to crash, even though it takes a while to close.
  • The crash seems to be invariante to OS version and iOS device.

Technical information

Explorations

Here's a list of all solution attempts without success so far:

  • Remove GameAnalytics plugin
  • Remove IronSource plugin
  • Remove UnityIAP plugin
  • Workaround on PostProcess iOS
  • Set minimum OS version to 9.0
  • Comment all OnApplicationPause/Quit implementations (plugins included)
  • Enable Bitcode

Solution

  • Solution

    Description: The general problem is to have any piece of code that blocks the Main Thread on iOS when the application is finalizing (see this document for more information). In our case it is happening because of ongoing requests when the player kills the application. As we save the player progress on the server when the application is terminated (using Dispose() method), the request blocked the main thread, causing the crash. The solution is to remove this particular save. We tested a build including this fix and, so far, we have no crashes on 20 attempts of killing the game after the Game Scene is loaded. We haven't thought about this before because this piece of code is there since August of 2019 and it hasn't been touched since then. The problem started to happen only in February of 2020.

    More information: Since the piece of problematic code was in the project since August of 2019 and the problem started to happen only on February of 2020, it's possible that the iOS version has something to do with it. We haven't investigate the changelog yet, but the oldest iOS version presenting the crash so far is iOS 13.2, released on October 28th, 2019.

    Another possibility is that some change on our backend code caused the request to hang. As we use BestHTTP, by default all requests are aborted when the application is terminated. We haven't investigate if the execution order of Dispose vs. OnDisable/OnApplicationQuit can be the issue. Also, by default, the requests aborted by BestHTTP during Application Quit still call the callbacks. In our case, the callback for that Save Player is null, so this might not be the problem.

    Related crashes: We're still facing some crashes on the loading scene. As far as we've seen, they happen when there's a request going on. The reproduction rate of those issues are way lower than the problem on Game Scene.

    Hints: We had difficulty to retrieve the logs on Crashlytics, because most of them weren't being send. Here's a step-by-step of how to retrieve the log from the iOS device itself:

    1. Open the Settings app on your iPhone/iPad device
    2. Go to Privacy (appears below Battery on iOS 13)
    3. Scroll to the bottom and open Analytics & Improvements
    4. Open Analytics Data
    5. Find the logs for the desired application