Unity OnApplicationQuit() doesn't work on android all the time

Viewed 3962

Android has been designed in a way that OnApplicationPause corresponds to onPause/onResume events of the activity.OnApplicationQuit corresponds to onDestroy event of activity lifecycle.

According to android docs, you are guaranteed to get a call back for onPause but anything after it may not be called. Therefore, you may not get a call to OnApplicationQuit if Android destroys the activity after onPause(Pre Honeycomb) or onStop.

Any idea how do I check if the application is being quit on android on Unity that works on all devices and all android versions

3 Answers

You need to act like OnPause will close the application! Waiting for OnApplicationQuit on Android will not let you act accordingly. Attach both methods OnPause and OnApplicationQuit as Quit or act as examples below:

If you are making a Single-Player game - just save all the content of the game just in case. If the activity will resume it all good, if not you have the backup.

If you are making a Multi-Player game - checking "Run in the Background" will let you keep a connection while the application is paused, but the user can kill your app anytime. I would make a coroutine and wait (around 30 seconds) and kill the connection. If you do not intend to make it work in the background, just kill the connection.

Quote from Android Developers on onDestroy() which is mapped to OnApplicationQuit if paused

onDestroy

Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.

Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.

You can use Application.quitting event to check if the application is quitting.

    static Example(){
        Application.quitting += Quit;
    }

    static void Quit(){
        Debug.Log("Quitting the Application");
    }

Or you can use OnApplicationQuit() method in this way:

    bool isApplicationQuitting = false;
   
    void OnApplicationQuit() {
        isApplicationQuitting = true;
    }

OnApplicationQuit is called when you explicitly call Application.Quit() which is usually done by either back button or an exit dialogue.

void Update () 
{
    if (Input.GetKeyDown(KeyCode.Escape) 
    {
        Application.Quit();
    }
} 

OnApplicationQuit will not be called when user press Home button or task list button and closes your game afterward, a phone battery die or game crash. none of the above.

To do any operation on user exit, I recommend implementing OnFocus or OnPause which happens when user press home button or tasks list on android. remember if user does tasks list and immediately close your game any write on disk operation will halt and results in unfinished and corrupted save file. and next time you load that file, it fails to read the stream and throws exception. you can prevent that by specifying a temporary name for your save file during the write operation and when it's finished replace the temporary file with the save file. an extra disk operation but a fail safe, or categorize your save file into chunks of data less than 10kb, by doing that no matter how fast user goes from task list button to close all button, there was enough time to write 10kb to disk.

other alternative to that is creating a service using this

or create another activity beside unity activity and set a process name for it too in AndroidManifest.xml

https://answers.unity.com/questions/780406/androidunity-launching-activity-from-unity-activit.html

void StartPackage(string package){    
          AndroidJavaClass activityClass;
         AndroidJavaObject activity, packageManager;
          AndroidJavaObject launch;
          
         
          activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
          activity = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
          packageManager = activity.Call<AndroidJavaObject>("getPackageManager");
          launch = packageManager.Call<AndroidJavaObject>("getLaunchIntentForPackage",package);
          activity.Call("startActivity",launch);
     }

and in AndroidManifest.xml

<activity
   android:name=".YourActivity"
   android:process=".YourActivity" />
Related