Amba

Unity SDK

Unity quickstart for the amba C# SDK — UPM install via git URL or tarball, Amba.ConfigureAsync(), Amba.Events.TrackAsync(), and WebGL events-only caveat.

Amba for Unity is distributed as a UPM (Unity Package Manager) package: com.layers.amba. Add it once; every supported Unity target works.

Supported runtime: Unity 2022.3+ LTS (Mono and IL2CPP).

Supported platforms: iOS, Android, macOS, Windows, and Linux. WebGL builds support events only — auth, collections, storage, and push aren't available on that platform yet. Events are buffered and flushed at exit.

1. Install via Package Manager

Option A — git URL

In the Unity Package Manager (Window → Package Manager) → +Add package from git URL → paste:

https://github.com/layers/amba-sdk-unity.git#v1.0.0

Option B — manifest.json

Edit Packages/manifest.json:

{
  "dependencies": {
    "com.layers.amba": "https://github.com/layers/amba-sdk-unity.git#v1.0.0"
  }
}

Option C — local tarball (offline / private mirrors)

Download the com.layers.amba-1.0.0.tgz tarball from the releases page, drop it in Packages/, and reference it:

{
  "dependencies": {
    "com.layers.amba": "file:com.layers.amba-1.0.0.tgz"
  }
}

The native binaries land under Packages/com.layers.amba/Plugins/<target>/ and Unity's Plugin Importer flags them for the correct target automatically.

2. Configure on startup

Add a bootstrap MonoBehaviour to your initial scene (or use [RuntimeInitializeOnLoadMethod]):

// AmbaBootstrap.cs
using System.Threading.Tasks;
using UnityEngine;
using Layers.Amba;
 
public class AmbaBootstrap : MonoBehaviour
{
    [SerializeField] private string apiKey = "amb_dev_ck_XXXX"; // override in inspector
 
    private async void Awake()
    {
        DontDestroyOnLoad(gameObject);
        try
        {
            await Amba.ConfigureAsync(apiKey: apiKey);
            Debug.Log($"amba: configured, anonymousId={Amba.AnonymousId}");
        }
        catch (System.Exception e)
        {
            Debug.LogError($"amba: configure failed — {e.Message}");
        }
    }
}

Don't ship a hard-coded key in source. Read it from a secrets ScriptableObject, an environment-driven build define, or your secrets framework (Unity Cloud Build supports env-driven defines via [Conditional]).

3. First sign-in (anonymous)

Events.TrackAsync is authenticated server-side — the request needs a session token. Mint one anonymously on first launch:

using Layers.Amba;
 
var session = await Amba.Auth.SignInAnonymouslyAsync();
Debug.Log($"amba: signed in as {session.GetProperty("user").GetProperty("id").GetString()}");

The response is a System.Text.Json.JsonElement — read fields directly with GetProperty(...), or deserialize through your own POCOs with JsonSerializer.Deserialize<MyType>(session.GetRawText()). The session token persists across game launches.

4. First event

Once a session exists, track gameplay events:

using System.Collections.Generic;
using Layers.Amba;
 
await Amba.Events.TrackAsync("game_started", new Dictionary<string, object>
{
    { "level", 1 },
    { "difficulty", "normal" },
});

5. Sign in with Apple (iOS) / Google (Android)

Unity doesn't ship platform OAuth flows; use a third-party plugin and forward the resulting tokens.

For Sign in with Apple on iOS, the Apple Authentication Asset Store package provides the identity token:

// pseudo — adapt to whichever Apple auth plugin you use
var identityToken = await AppleAuthPlugin.SignInAsync();
await Amba.Auth.SignInWithAppleAsync(identityToken);

For Sign in with Google on Android, use Google Play Games Services for Unity and forward idToken:

var idToken = await GooglePlayPlugin.SignInAsync();
await Amba.Auth.SignInWithGoogleAsync(idToken);

(Same signInWithSocial server endpoint as every other SDK — the wrapper API is Amba.Auth.SignInWithGoogleAsync(idToken).)

6. Register for push

Use Unity's Mobile Notifications package to obtain the device token, then forward to amba:

// iOS — APNs
#if UNITY_IOS
using Unity.Notifications.iOS;
 
var request = await iOSNotificationCenter.RequestAuthorizationAsync(
    AuthorizationOption.Alert | AuthorizationOption.Badge | AuthorizationOption.Sound,
    registerForRemoteNotifications: true);
if (request.Granted && !string.IsNullOrEmpty(request.DeviceToken))
{
    await Amba.Push.RegisterAsync(
        token: request.DeviceToken,
        platform: "apns",
        bundleId: Application.identifier);
}
#endif
 
// Android — FCM
#if UNITY_ANDROID
// Use Firebase Unity SDK to obtain the FCM token, then:
await Amba.Push.RegisterAsync(token: fcmToken, platform: "fcm", bundleId: Application.identifier);
#endif

7. First collection insert

using System.Collections.Generic;
using System.Text.Json;
using Layers.Amba;
 
var inserted = await Amba.Collections.InsertAsync("posts", new Dictionary<string, object>
{
    { "title", "Hello amba" },
    { "body", "first post from Unity" },
});
Debug.Log($"amba: inserted {inserted.GetProperty("id").GetString()}");
 
var response = await Amba.Collections.FindAsync("posts", new Dictionary<string, object>
{
    { "order", new[] { new Dictionary<string, object> { { "column", "created_at" }, { "direction", "desc" } } } },
    { "limit", 20 },
});
var data = response.GetProperty("data");
Debug.Log($"amba: got {data.GetArrayLength()} posts");

For typed reads, deserialize through your own POCOs:

public class Post { public string Id { get; set; } public string Title { get; set; } public string Body { get; set; } }
 
var posts = JsonSerializer.Deserialize<List<Post>>(
    response.GetProperty("data").GetRawText(),
    new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

8. AI proxy

var response = await Amba.Ai.Anthropic.Messages.CreateAsync(new Dictionary<string, object>
{
    { "prompt_slug", "support_assistant" },
    { "variables", new Dictionary<string, object> { { "user_query", "How do I cancel?" } } },
    { "max_tokens", 1024 },
});
Debug.Log(response.GetProperty("content").GetRawText());

WebGL caveat (events only)

WebGL builds use a different code path:

  • Amba.Events.TrackAsync works — events are buffered in memory and flushed at exit (or by an explicit Amba.Events.FlushAsync if you add one).
  • Amba.Auth.*, Amba.Collections.*, Amba.Storage.*, Amba.Push.* throw NotSupportedException because the underlying persistence layer requires a filesystem.

The underlying reason is that the WebGL Player runs in an [WebGL sandbox with no localStorage-equivalent that amba can write to safely across sessions. For full surface in the browser, use @layers/amba-web instead and bridge from your WebGL game via Unity → JavaScript interop.

Constructor DI for tests

using Layers.Amba;
using NUnit.Framework;
 
public class FakeNativeMethods : INativeMethods { /* implement with in-memory fakes */ }
 
[Test]
public async Task Tracks_event_through_client()
{
    var client = new AmbaClient(new FakeNativeMethods());
    await client.InitializeAsync("test");
    await client.Events.TrackAsync("test_event");
    // assert on the fake's recorded calls
}

AmbaClient accepts an INativeMethods via the constructor — production code goes through Amba.ConfigureAsync(...) which wires DefaultNativeMethods (native binding).

IL2CPP + AOT considerations

The C# wrapper uses System.Text.Json — fully AOT-compatible under IL2CPP from Unity 2022.3 onward. No link.xml preserves are needed for the SDK itself; the included Layers.Amba.asmdef keeps stripping conservative.

If you've enabled aggressive code stripping (managed stripping level High), add a small link.xml:

<linker>
  <assembly fullname="Amba" preserve="all" />
</linker>

Common pitfalls

  • Amba.ConfigureAsync not awaited before first Amba.* access throws InvalidOperationException("Amba.ConfigureAsync must be called before accessing Amba.*"). Configure in a bootstrap MonoBehaviour with DontDestroyOnLoad.
  • DllNotFoundException: amba_core at runtime — the platform-specific native library wasn't packaged. In the Plugin Importer, verify each Plugins/<target>/libamba_core.* has the matching target checkbox enabled.
  • WebGL build fails with "cannot find amba_core" — expected. WebGL doesn't ship libamba_core; use the events-only code path and gate non-events calls behind #if !UNITY_WEBGL.
  • iOS bitcode warning — if your Xcode project has bitcode enabled (default in Unity 2022.3 LTS is off), strip it before archiving. The shipped libamba_core.a is bitcode-free.

See also