App lifecycle
JestSDK.Instance.Lifecycle reports when the game document is hidden or shown and when
the player asks to leave through Jest's platform controls.
The events are System.Action events, so subscribe with += and unsubscribe with -=. Each
event supports multiple handlers.
JestSDK.Instance.Lifecycle exists before Init() is called, so subscribe from OnEnable and
unsubscribe from OnDisable. Handlers only start firing once Init() completes, and pairing the
Unity callbacks this way keeps the subscription tied to the component's own lifetime:
using com.jest.sdk;
using UnityEngine;
public class LifecycleListener : MonoBehaviour
{
// Your game's own pause system, not an SDK type.
[SerializeField] private GamePause m_pause;
[SerializeField] private int m_currentCheckpoint;
private void OnEnable()
{
JestSDK.Instance.Lifecycle.OnHide += HandleHide;
JestSDK.Instance.Lifecycle.OnShow += HandleShow;
JestSDK.Instance.Lifecycle.OnExitRequested += HandleExitRequested;
}
private void OnDisable()
{
JestSDK.Instance.Lifecycle.OnHide -= HandleHide;
JestSDK.Instance.Lifecycle.OnShow -= HandleShow;
JestSDK.Instance.Lifecycle.OnExitRequested -= HandleExitRequested;
}
private void HandleHide()
{
m_pause.PauseForVisibility();
}
private void HandleShow()
{
m_pause.ResumeForVisibility();
}
private void HandleExitRequested()
{
JestSDK.Instance.Player.Set("checkpoint", m_currentCheckpoint);
}
}
GamePause here is your game's own pause system, and that separation is the point: route hide and show
through whatever already owns pausing instead of writing Time.timeScale or AudioListener.pause from
the handler. Those are global, and a handler that overwrites them fights every other system that pauses
— slow motion, a settings menu, another lifecycle handler — with the outcome decided by subscription
order. A pause system that counts its reasons for pausing can absorb a visibility pause without
discarding the rest.
Put the component on an object that lives as long as the session, such as a DontDestroyOnLoad object,
so the subscription spans the whole game. A hide event fires on the visibility transition only, so a
component that is disabled and re-enabled while the document is still hidden receives no replacement
event — leave it enabled rather than trying to reconstruct the hidden state from the Unity callbacks.
If you prefer to subscribe once initialization has finished, keep the handlers and the -= calls as
members of the component rather than locals of the initializing method — Unity only calls OnDestroy
on the component itself, and a local OnDestroy never runs. The component can also be destroyed
while Init() is still awaited, so check that it is still alive before subscribing:
private async void Start()
{
await JestSDK.Instance.Init();
if (this == null)
{
return;
}
JestSDK.Instance.Lifecycle.OnHide += HandleHide;
}
private void OnDestroy()
{
JestSDK.Instance.Lifecycle.OnHide -= HandleHide;
}
Removing a handler that was never added is a no-op, so teardown is safe even when initialization never completed. Handlers stay attached to the SDK singleton until they are removed, so a destroyed component that never unsubscribes keeps receiving events.
Lifecycle.OnHide
Fires when the browser changes the game document from visible to hidden, such as when the player switches tabs, backgrounds the browser, or locks the device. It does not fire for the document's initial visibility state.
Use it to pause the game loop, physics, animation, and audio.
Lifecycle.OnShow
Fires when the game document changes from hidden back to visible. It does not fire on
initial startup; await JestSDK.Instance.Init() is the startup boundary.
Use it to resume work stopped by OnHide, refresh time-sensitive state, and reconcile
elapsed time.
Lifecycle.OnExitRequested
Fires when the platform begins an exit flow, including its exit control and browser Back or mobile swipe-back navigation that Jest can intercept. It fires before the exit confirmation is resolved. The player can still choose to stay, and handlers cannot cancel or delay navigation.
This event only represents an exit flow the platform can intercept. Closing the tab, terminating the browser, or an operating-system shutdown may not produce a final event. Back navigation that leaves the Jest document directly, such as returning to an external referral page, may not produce one either.
Because of that, treat this event as a last chance to save rather than the only place you save.
Player.Set sends the update as soon as it is called, unless an
earlier update is still unacknowledged, in which case it goes out with the next message. Persist
progress as the player earns it, and use this event to capture whatever has changed since the last
save.