> ## Documentation Index
> Fetch the complete documentation index at: https://docs.almedia.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Editor and play mode

> How to integrate the Almedia SDK — synced from the source repository.

`Almedia.Initialize` works inside the Unity Editor by falling back to a deterministic mock bridge that simulates the native layer. The mock fires `OnStatusChanged` / `OnNotificationsReceived` on a timer, so the UI can be exercised without a device build. It also simulates the [screen lifecycle pair](https://docs.almedia.dev/technical/integration-guide/pausing-your-game.md) for every screen, modeling the **webview** linking strategy - starting linking from the popup's CTA fires `OnScreenPresented`/`OnScreenDismissed` around the simulated flow so pause/resume wiring is exercisable in the editor, whereas production configured with the system-browser linking strategy fires no pair for linking.

Static state and event subscribers are cleared on domain reload (`RuntimeInitializeOnLoadMethod` with `SubsystemRegistration` timing). This means:

* Manual unsubscription in `OnDestroy` is not required to avoid leaking handlers *across play-mode entry and exit* - domain reload clears them. **Within a single play session you must still unsubscribe**, though: a `MonoBehaviour` that subscribes to an `Almedia` event and is then destroyed (scene unload, `Destroy(gameObject)`) stays registered. The next callback fires on the destroyed object and throws `MissingReferenceException`, which the bridge swallows to `OnLog` - it does **not** surface through `OnErrorOccurred`. Unsubscribe in `OnDisable`/`OnDestroy` for any component shorter-lived than the SDK.
* Even with domain reload disabled in **Edit → Project Settings → Editor → Enter Play Mode Options**, subscriptions should still happen in `Awake`, because the SDK explicitly resets its own state on the same lifecycle hook.

## Driving non-happy paths

EditorMock auto-simulate covers the happy path only: `Eligible` after `Initialize`, then `Linked` + `OnLinkCompleted` and a first progress snapshot after linking starts, then three mock notifications and a new snapshot when `FetchNotifications` is called. To exercise the rest of the surface - `NotAvailable` / `Blocked` / `Disabled` statuses, every `AlmediaErrorCode`, empty or oversized notification batches, native log forwarding - reach for `AlmediaEditorMock`. It lets host editor code and play-mode tests drive the SDK into any state in one line, so UI branches keyed off those signals become Editor-testable without a device build.

The public surface lives in `AlmediaSDK.Editor.Testing` and consists of these static methods:

* `EmitStatus(AlmediaStatus)` - delivers a status as if native had reported it; `Almedia.Status` and `OnStatusChanged` reflect it immediately. Build the status with its constructor: `EmitStatus(new AlmediaStatus.Linked(false, false))` is a linked player with nothing to open, and `EmitStatus(new AlmediaStatus.NotAvailable("holdout"))` is a holdout player.
* `EmitError(AlmediaErrorCode, string)` - delivers an error; `OnErrorOccurred` fires with the matching code and message.
* `EmitLinkCompleted()` - fires `OnLinkCompleted` with the current UTC timestamp.
* `EmitNotifications(params AlmediaNotification[])` - fires `OnNotificationsReceived`. Pass no arguments for an empty batch; pass many to test scrolling / paging.
* `EmitInGameRewardGrant(string id, params AlmediaInGameReward[])` - fires `OnInGameRewardGrantRequested`. The id is optional (an overload generates one); pass the same id twice to reproduce an at-least-once redelivery. A call with no rewards is dropped by the SDK as malformed.
* `EmitProgress(AlmediaProgress)` - applies a snapshot. `Progress` holds it and `OnProgressUpdated` fires. `null` models the native SDK clearing the snapshot. A null `Username` models a snapshot that clears the previous username.
* `EmitTaskCompleted(string id, AlmediaCompletedTask)` / `EmitBalanceChanged(string id, AlmediaRewardPoints balance, AlmediaRewardPoints change)` - fire the two progress events. The id is optional. Pass the same id twice to reproduce a replay.
* `EmitScreenPresented(AlmediaScreen)` - fires `OnScreenPresented` for the given screen, without a real webview.
* `EmitScreenDismissed(AlmediaScreen, AlmediaInAppScreenResult)` - fires `OnScreenDismissed` for the given screen and result.
* `EmitNativeLog(AlmediaLogLevel, string)` - delivers a forwarded log line through the same path the iOS/Android plugins use.
* `CancelPending()` - stops any pending auto-simulate coroutine started before manual mode flipped.

**Manual mode.** The mock has two modes: auto-simulate (default; canned coroutines drive the happy path) and manual (every `Initialize`, linking start and `FetchNotifications` becomes a no-op so the test owns the scenario). The first call to *any* `AlmediaEditorMock` method flips manual mode for the rest of the play session and cancels any in-flight canned coroutine, so an `EmitStatus(new AlmediaStatus.Blocked())` issued right after `Almedia.Initialize` cannot be clobbered by the delayed `Eligible`. Manual mode resets on domain reload (entering Play mode, recompiling) - there is no public toggle to leave it manually.

**Pre-init contract.** Calling any `Emit*` method before `Almedia.Initialize(...)` throws `InvalidOperationException`. The throw is deliberate: it surfaces test ordering bugs at test-author time instead of swallowing them as a silent no-op.

**Stripping.** `AlmediaEditorMock` lives in the `AlmediaLink.Editor` assembly definition with `includePlatforms:["Editor"]`. It is not compiled for iOS or Android player targets at the assembly level - host code that references it must be wrapped in `#if UNITY_EDITOR`, and the references will fail to compile on a player target rather than crash at runtime.

A minimal play-mode test that verifies UI hides on `Blocked`:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
#if UNITY_EDITOR
using System.Collections;
using AlmediaSDK;
using AlmediaSDK.Editor.Testing;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class RewardsHudPlayModeTests
{
    [UnityTest]
    public IEnumerator RewardsHud_HidesWhenSdkBlocked()
    {
        var hud = Object.Instantiate(Resources.Load<GameObject>("RewardsHud"));

        Almedia.Initialize(new AlmediaConfig
        {
            IosIntegrationKey = "test", AndroidIntegrationKey = "test"
        });
        AlmediaEditorMock.EmitStatus(new AlmediaStatus.Blocked());

        yield return null;

        Assert.IsFalse(hud.activeSelf, "RewardsHud should hide on Blocked status");
    }
}
#endif
```

The package README has a [shorter pointer to the same surface](https://docs.almedia.dev/technical/readme.md#editor-testing); the API reference covers each method in the [Editor testing](https://docs.almedia.dev/technical/api-reference/almedia/editor-testing.md) section.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.