Skip to content

feat(audience): Unity integration, IL2CPP link.xml, and polish (SDK-221)#695

Merged
ImmutableJeffrey merged 7 commits into
mainfrom
feat/sdk-147-singleton-4
Apr 22, 2026
Merged

feat(audience): Unity integration, IL2CPP link.xml, and polish (SDK-221)#695
ImmutableJeffrey merged 7 commits into
mainfrom
feat/sdk-147-singleton-4

Conversation

@ImmutableJeffrey
Copy link
Copy Markdown
Collaborator

@ImmutableJeffrey ImmutableJeffrey commented Apr 21, 2026

Summary

  • Adds the Unity integration layer under a sibling Runtime/Unity/ sub-asmdef (com.immutable.audience.unity).
  • Flips the core asmdef's noEngineReferences to true so the core compiles with zero UnityEngine references at Unity-compile time.
  • Adds link.xml at the package root for IL2CPP stripping resistance (test-matrix verification tracked separately by SDK-148).
  • Wires Application.quitting to ImmutableAudience.Shutdown and provides DefaultPersistentDataPathProvider + LaunchContextProvider via AudienceUnityHooks at SubsystemRegistration.
  • Attaches platform, version, buildGuid, unityVersion to the auto-fired game_launch event (interim; SDK-146 DeviceCollector will replace with full per-event device context).
  • Skips game_launch when consent is None at the time Init completes.
  • Surfaces consent-persistence failures through the OnError callback as AudienceErrorCode.ConsentPersistFailed.
  • Changes ImmutableAudience.DeleteData to return Task (was async void) so callers can await errors.
  • Documents every AudienceErrorCode value with // comments sourced from the raise-sites; converts the existing ConsentPersistFailed /// <summary> to // for file consistency.

Linear: SDK-221, SDK-216 (the //-style convention applied to AudienceErrorCode here is the chosen resolution for SDK-216's "use /// <summary>" ask on the audience surface).

@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch from 3da9923 to a8815e6 Compare April 21, 2026 23:05
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch 2 times, most recently from a6aa7f8 to ad93e87 Compare April 21, 2026 23:08
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch from a8815e6 to 5aefd17 Compare April 21, 2026 23:08
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch from ad93e87 to 4d9a79d Compare April 21, 2026 23:20
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch 2 times, most recently from f9b8af1 to f8279bd Compare April 22, 2026 00:31
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch 2 times, most recently from ac288a1 to e130acf Compare April 22, 2026 00:57
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch 2 times, most recently from e11b0fe to 9dd780b Compare April 22, 2026 01:04
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch 2 times, most recently from 7a7dc9e to f1c32ea Compare April 22, 2026 01:32
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch from 9dd780b to c8a7a52 Compare April 22, 2026 01:32
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch 2 times, most recently from d96cda9 to 058e4d1 Compare April 22, 2026 05:08
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch from b0a2c0f to 57a41d9 Compare April 22, 2026 05:51
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch 2 times, most recently from f305fc6 to fe290fc Compare April 22, 2026 06:02
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-3 branch 2 times, most recently from 69440fe to bb3d45f Compare April 22, 2026 06:14
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch from fe290fc to 9044b9f Compare April 22, 2026 06:14
Base automatically changed from feat/sdk-147-singleton-3 to main April 22, 2026 07:04
ImmutableJeffrey and others added 6 commits April 22, 2026 17:21
…n (SDK-147)

Splits the package into a core asmdef (pure C#, buildable headless
under dotnet) and a Unity sub-asmdef (engine-referencing). The
Unity layer has always belonged here; the fence on the core was
always correct; landing both together makes the partition
enforceable at Unity-compile time.

- Runtime/Unity/AudienceUnityHooks.cs: RuntimeInitializeOnLoadMethod
  wiring. Flushes on pause/quit via Application hooks. Installs
  Debug.Log as Log.Writer for SDK diagnostics.
- Runtime/Unity/com.immutable.audience.unity.asmdef: sibling
  sub-asmdef claiming Runtime/Unity/. Excludes unsupported
  platforms (mobile, consoles) per v1 scope (Windows / macOS /
  Linux). Referenced from the core asmdef's sibling - not the
  other way around, keeping the dependency direction clean.
- Runtime/com.immutable.audience.asmdef: noEngineReferences
  flipped to true. The core has always been pure C# (proven by
  the sibling Audience.Runtime.csproj that compiles the same tree
  headless), but the flag shipped as Unity's Editor-default false.
  Now that the Unity sub-asmdef exists to hold UnityEngine-using
  code, flipping the fence makes the guarantee enforceable at
  Unity-compile time - stray `using UnityEngine` in Core/,
  Events/, Transport/, or Utility/ now breaks the Unity build,
  matching what dotnet already rejects.
- Audience.Runtime.csproj: comment now cross-references the
  asmdef flag as the primary portability fence and the Compile
  Remove as the sibling check for the headless dotnet build.
  Prevents a future cleanup from removing one of the two halves.
Plan §6.6 requires a link.xml at the package root so IL2CPP's
managed-code stripping doesn't remove types the SDK reaches only
at runtime. Preserves the full Immutable.Audience.Runtime assembly
and names the System.Net.Http pipeline pieces used by
HttpTransport / SetConsent / DeleteData. System.IO.Compression
entries are harmless when the gzip scripting define is off.
Plan §5.1 and the Event Reference require game_launch to ship with
platform, version, buildGuid, unityVersion auto-detected. Until the
Day 4 DeviceCollector lands, game_launch was shipping with only the
studio-supplied distributionPlatform.

- ImmutableAudience gets a new internal seam, LaunchContextProvider,
  that returns a Dictionary<string, object> merged into game_launch
  properties. Core stays pure C# - the provider is installed from the
  Unity layer so no UnityEngine import leaks into Runtime/.
- FireGameLaunch wraps the provider call in try/catch with a clear
  warning. A buggy provider must never prevent the launch event from
  firing - game_launch is the most load-bearing attribution event.
- AudienceUnityHooks installs a default provider that reads
  Application.platform, Application.version, Application.buildGUID,
  Application.unityVersion. DeviceCollector (Day 4) can replace or
  extend this without re-wiring.
- config.DistributionPlatform keeps winning over any provider value:
  studios set it explicitly because Unity cannot auto-detect the
  distribution store, and that value is the one the attribution
  pipeline expects.

Three new tests: provider fields make it onto the event, config
overrides provider for distributionPlatform, and a throwing provider
doesn't skip the event. 154 passing.

Linear: SDK-147

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-147)

ConsentStore.Save can fail from transient I/O (disk full, locked file,
permissions). Previously the catch handler at ImmutableAudience.cs:318
logged a warning and returned silently - studios had no programmatic
signal that their consent change wouldn't survive a restart.

Adds AudienceErrorCode.ConsentPersistFailed, distinct from
ConsentSyncFailed (backend PUT) so operators can tell the two failure
modes apart: a Save failure means local state will revert on relaunch,
a Sync failure means the backend audit trail is out of sync but local
state is fine.

In-memory behaviour is unchanged - the new level still applies to the
current session, the purge/downgrade still runs. The callback just
gives studios a hook to warn the player, log to their telemetry, or
retry the persist at a better moment.

New test pre-creates a directory at the consent file path to force
File.Move to fail, then asserts ConsentPersistFailed reaches OnError.
155 passing.

Linear: SDK-147

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DeleteData fires a backend DELETE for GDPR erasure but returned void,
so callers had no handle to know when the erasure completed or
failed. FlushAsync returns Task for the same reason - symmetrising
the lifecycle methods on the singleton.

- Public signature becomes `public static Task DeleteData(string
  userId = null)`.
- All early-return paths (not initialised, no config, no anonymousId)
  return Task.CompletedTask.
- The hot path's Task.Run is just returned directly instead of
  discarded. No change to the actual HTTP request, error surfacing,
  or anonymousId-file-side-effect-avoidance contract.
- Callers that want fire-and-forget still get it by ignoring the
  return value; callers that want to gate on completion can now
  await. Existing void-discarding call sites continue to compile.

Two new tests: awaited task completes after DELETE dispatch, and
the pre-Init guard returns Task.CompletedTask. 158 passing.

Linear: SDK-147

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Runtime/Unity/AudienceUnityHooks.cs: directive only (all references
  come from UnityEngine which is typed conservatively).
- ImmutableAudience.cs: LaunchContextProvider field (added by the
  auto-context commit on top of the already-annotated file) → nullable;
  unityContext local in FireGameLaunch → nullable (receives provider
  result that may be null on exception).

Compile-time annotations only; zero runtime behaviour change.
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch from 9044b9f to 7067bba Compare April 22, 2026 07:27
Comment thread src/Packages/Audience/Runtime/AudienceError.cs Outdated
nattb8
nattb8 previously approved these changes Apr 22, 2026
ImmutableJeffrey added a commit that referenced this pull request Apr 22, 2026
- FlushFailed: local storage read error (batch dropped) or non-2xx/non-4xx server response — typically 5xx (batch retained, retried with backoff).
- ValidationRejected: server 4xx rejects batch; dropped, not retried.
- ConsentSyncFailed: backend PUT /tracking-consent failed; local state already applied.
- NetworkError: HTTP exception, timeout, or non-2xx on data deletion.
- ConsentPersistFailed: converted from /// <summary> to // to match the rest of the codebase.

Wording derived from raise-sites in HttpTransport.cs and ImmutableAudience.cs.

Addresses nattb8's review comment on PR #695.

Linear: SDK-147

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- FlushFailed: local storage read error (batch dropped), or non-2xx/non-4xx response
  — typically 5xx (batch retained, retried with backoff).
- ValidationRejected: server 4xx rejects batch; dropped, not retried.
- ConsentSyncFailed: backend PUT /tracking-consent failed; local state already applied.
- NetworkError: HTTP exception, timeout, or non-2xx on data deletion.
- ConsentPersistFailed: converted from /// <summary> to // to match the rest of the codebase.

Wording derived from raise-sites in HttpTransport.cs and ImmutableAudience.cs.

Addresses nattb8's review comment on PR #695.

Linear: SDK-147

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ImmutableJeffrey ImmutableJeffrey force-pushed the feat/sdk-147-singleton-4 branch from e4b3a68 to 7858115 Compare April 22, 2026 08:31
@nattb8 nattb8 marked this pull request as ready for review April 22, 2026 08:36
@nattb8 nattb8 requested review from a team as code owners April 22, 2026 08:36
@ImmutableJeffrey ImmutableJeffrey merged commit 1ca0773 into main Apr 22, 2026
19 checks passed
@ImmutableJeffrey ImmutableJeffrey deleted the feat/sdk-147-singleton-4 branch April 22, 2026 08:39
@nattb8 nattb8 changed the title feat(audience): Unity integration, IL2CPP link.xml, and polish (SDK-147) feat(audience): Unity integration, IL2CPP link.xml, and polish (SDK-221) Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants