From 32d8943849aca859be6183185c886f48887af47a Mon Sep 17 00:00:00 2001 From: Natalie Bunduwongse Date: Wed, 6 May 2026 16:01:50 +1200 Subject: [PATCH] feat(audience-sdk): add EnableMobileAttribution + SKAdNetworkIds config (SDK-305) Entry-point ticket for the mobile attribution stretch work. Adds two opt-in surfaces; downstream tickets (SDK-306/308/309/315) wire them up: - AudienceConfig.EnableMobileAttribution (default false): runtime gate for whether attribution data is collected and emitted on game_launch. - AudienceConfig.SKAdNetworkIds: optional list, read by the iOS post-processor at build time when the scripting define is set. XML doc on EnableMobileAttribution documents the two-gate model: studios opt in via both the AUDIENCE_MOBILE_ATTRIBUTION scripting define and this runtime flag. Without the define, no AD_ID permission, no native attribution code, NSPrivacyTracking false; with define + flag false, native code compiled in but no data collected; with both, full flow. --- .../Audience/Runtime/AudienceConfig.cs | 34 +++++++++++++++ .../Tests/Runtime/AudienceConfigTests.cs | 41 +++++++++++++++++++ .../Tests/Runtime/AudienceConfigTests.cs.meta | 11 +++++ 3 files changed, 86 insertions(+) create mode 100644 src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs create mode 100644 src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs.meta diff --git a/src/Packages/Audience/Runtime/AudienceConfig.cs b/src/Packages/Audience/Runtime/AudienceConfig.cs index c26815096..d0dd7090a 100644 --- a/src/Packages/Audience/Runtime/AudienceConfig.cs +++ b/src/Packages/Audience/Runtime/AudienceConfig.cs @@ -49,6 +49,40 @@ public class AudienceConfig /// public bool Debug { get; set; } = false; + /// + /// Opts into mobile install-attribution signals (iOS ATT / IDFA / + /// SKAdNetwork, Android Advertising ID / Install Referrer). Default + /// false. + /// + /// + /// Two gates control attribution; both must be set for any data to + /// ship: + /// + /// 1. Build-time: add AUDIENCE_MOBILE_ATTRIBUTION to Player + /// Settings → Other Settings → Scripting Define Symbols. Controls + /// the AD_ID Android manifest permission, the iOS Privacy Manifest + /// variant (NSPrivacyTracking), and whether native + /// attribution code is compiled into the binary. + /// + /// 2. Runtime: this flag. Controls whether attribution data is + /// collected at runtime. Without the define, this setter is a + /// no-op. + /// + /// Studios who set neither ship a clean binary — no AD_ID permission, + /// no native attribution code, NSPrivacyTracking = false. + /// + public bool EnableMobileAttribution { get; set; } = false; + + /// + /// SKAdNetwork IDs the iOS post-processor injects into Info.plist + /// at build time. Ignored on Android. + /// + /// + /// Read only when and the + /// AUDIENCE_MOBILE_ATTRIBUTION scripting define are both set. + /// + public string[]? SKAdNetworkIds { get; set; } + /// /// Interval between automatic flushes to the backend, in seconds. /// diff --git a/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs b/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs new file mode 100644 index 000000000..84a198a19 --- /dev/null +++ b/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs @@ -0,0 +1,41 @@ +#nullable enable + +using NUnit.Framework; + +namespace Immutable.Audience.Tests +{ + [TestFixture] + internal class AudienceConfigTests + { + [Test] + public void EnableMobileAttribution_DefaultsToFalse() + { + // Default-off matters: a studio that never opts in must ship a + // clean binary, no AD_ID permission, NSPrivacyTracking false. + var config = new AudienceConfig(); + Assert.IsFalse(config.EnableMobileAttribution); + } + + [Test] + public void SKAdNetworkIds_DefaultsToNull() + { + var config = new AudienceConfig(); + Assert.IsNull(config.SKAdNetworkIds); + } + + [Test] + public void EnableMobileAttribution_RoundTrips() + { + var config = new AudienceConfig { EnableMobileAttribution = true }; + Assert.IsTrue(config.EnableMobileAttribution); + } + + [Test] + public void SKAdNetworkIds_RoundTrips() + { + var ids = new[] { "abc123.skadnetwork", "def456.skadnetwork" }; + var config = new AudienceConfig { SKAdNetworkIds = ids }; + Assert.AreSame(ids, config.SKAdNetworkIds); + } + } +} diff --git a/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs.meta b/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs.meta new file mode 100644 index 000000000..ea8a73821 --- /dev/null +++ b/src/Packages/Audience/Tests/Runtime/AudienceConfigTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7a0b1d2e3f4a5b6c7d8e9f0a1b2c3d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: