diff --git a/content/docs/images/gc_unity.jpg b/content/docs/images/gc_unity.jpg new file mode 100644 index 0000000..3530426 Binary files /dev/null and b/content/docs/images/gc_unity.jpg differ diff --git a/content/docs/images/unity-game-controller-support-placeholder.svg b/content/docs/images/unity-game-controller-support-placeholder.svg new file mode 100644 index 0000000..7b53287 --- /dev/null +++ b/content/docs/images/unity-game-controller-support-placeholder.svg @@ -0,0 +1,9 @@ + + Screenshot placeholder + Paywall editor game controller support screenshot placeholder. + + + SCREENSHOT NEEDED + Paywall editor settings + Game Controller Support set to ENABLED + diff --git a/content/docs/images/unity-package-manager-git-url-placeholder.svg b/content/docs/images/unity-package-manager-git-url-placeholder.svg new file mode 100644 index 0000000..6bc8a19 --- /dev/null +++ b/content/docs/images/unity-package-manager-git-url-placeholder.svg @@ -0,0 +1,9 @@ + + Screenshot placeholder + Unity Package Manager add package from git URL screenshot placeholder. + + + SCREENSHOT NEEDED + Unity Package Manager + Add package from git URL with Superwall-Unity URL + diff --git a/content/docs/images/upm_add.jpg b/content/docs/images/upm_add.jpg new file mode 100644 index 0000000..eb970de Binary files /dev/null and b/content/docs/images/upm_add.jpg differ diff --git a/content/docs/meta.json b/content/docs/meta.json index 0136e01..463681e 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -16,7 +16,8 @@ "android", "expo", "flutter", + "unity", "react-native", "community" ] -} \ No newline at end of file +} diff --git a/content/docs/unity/changelog.mdx b/content/docs/unity/changelog.mdx new file mode 100644 index 0000000..4d77297 --- /dev/null +++ b/content/docs/unity/changelog.mdx @@ -0,0 +1,86 @@ +--- +title: "Changelog" +description: "Changelog for the Superwall Unity SDK beta." +--- + +# Changelog + +All notable changes to this package will be documented in this file. + +## [0.2.3] + +### Breaking Changes + +- `Configure` completion signature changed from `Action` to `Action` to match the native SDKs' `Result` semantics. The result exposes `IsSuccess` and a typed `FailedResult.Error` on failure. Android now propagates SDK init errors through this; iOS still always signals success since SuperwallKit's completion has no failure variant. + +### Cleanup + +- Renamed asmdef files to `Superwall.*` + +## [0.2.1] + +## Enhancements + +### New APIs + +- `SetLocalResources(Dictionary)` - map asset names to local file paths for paywall WebViews (Android only) + +### Delegate Fixes + +- Android: added `willRedeemLink`, `didRedeemLink`, `userAttributesDidChange` delegate callbacks +- iOS: added `handleSuperwallDeepLink`, `userAttributesDidChange` delegate callbacks +- iOS: added `ShowAlert` no-op stub to prevent missing symbol crash + +## [0.2.0] + +### Android Support + +- Full Android support via bundled `.androidlib` Gradle module - no manual `mainTemplate.gradle` setup needed +- Kotlin bridge compiled with Kotlin 2.0.21 to match Superwall Android SDK 2.x +- Custom `ActivityProvider` for Unity ensures paywall presentation works correctly +- AndroidManifest with required activity declarations merged automatically + +### New APIs + +- `Purchase(productId, callback)` - programmatic purchase without a paywall +- `GetProducts(productIds, callback)` - fetch product details by ID +- `GetAssignments(callback)` - get experiment assignments without confirming +- `ShowAlert(title, message, ...)` - show alerts on the current paywall +- `RefreshConfiguration()` - force SDK config refresh + +### Options + +- Full `SuperwallOptions` parsing on both platforms (was incomplete) +- Added `PaywallOptions.UseCachedTemplates` and `PaywallOptions.TimeoutAfter` +- `TestModeBehavior`, `NetworkEnvironment`, `Paywalls.*`, `Logging.Scopes` now properly passed to native SDKs + +### Delegate & Callbacks + +- All `ISuperwallDelegate` callbacks now receive deserialized objects instead of null +- `SubscriptionStatus` getter properly deserializes native state (was always returning Unknown) +- All async getters (`Entitlements`, `CustomerInfo`, `PaywallInfo`, `PresentationResult`, `ConfirmedAssignment`, `RestorationResult`) now deserialize correctly +- Fixed async callback mechanism - was dropping response data, causing `Configure` completion to always return false + +### iOS + +- Purchase controller flow implemented with async continuations +- Integration attributes mapping implemented +- Full options parity with Android + +### Cleanup + +- Removed legacy `com.ian_unity558.com.superwall.sdk` package +- Removed stale `EnsureAndroidGradleDependency` editor script (replaced by `.androidlib`) + +## [0.1.1] + +- Android package support +- Handler callback arguments +- More properties implemented +- Improved option support + +## [0.1.0] + +### This is the first release of _<com.superwall.sdk>_. + +- iOS support, registering and callbacks diff --git a/content/docs/unity/guides/advanced-configuration.mdx b/content/docs/unity/guides/advanced-configuration.mdx new file mode 100644 index 0000000..0822cd6 --- /dev/null +++ b/content/docs/unity/guides/advanced-configuration.mdx @@ -0,0 +1,221 @@ +--- +title: "Advanced Configuration" +description: "Configure beta Superwall Unity SDK options and advanced APIs." +--- + +`SuperwallOptions` lets you tune paywall behavior, logging, locale, test mode, and platform-specific +behavior at configuration time. + +```csharp C# +using System.Collections.Generic; +using Superwall; + +var options = new SuperwallOptions +{ + NetworkEnvironment = NetworkEnvironment.Release, + TestModeBehavior = TestModeBehavior.Automatic, + IsGameControllerEnabled = true, + Logging = new Logging + { + Level = LogLevel.Debug, + Scopes = new List { LogScope.PaywallPresentation } + }, + Paywalls = new PaywallOptions + { + ShouldPreload = true, + AutomaticallyDismiss = true, + ShouldShowPurchaseFailureAlert = true, + RestoreFailed = new RestoreFailed + { + Title = "No Subscription Found", + Message = "We couldn't find an active subscription for your account.", + CloseButtonTitle = "Okay" + } + } +}; + +Superwall.Configure("MY_PUBLIC_API_KEY", options: options); +``` + +## `SuperwallOptions` + + + +## `PaywallOptions` + +", + description: "Maps product names in paywalls to specific store product identifiers.", + default: "null", + }, + ShouldShowWebPurchaseConfirmationAlert: { + type: "bool", + description: "Shows the web purchase confirmation alert.", + default: "false", + }, + UseCachedTemplates: { + type: "bool", + description: "Uses cached paywall templates when available.", + default: "false", + }, + TimeoutAfter: { + type: "float?", + description: "Optional paywall request timeout in seconds.", + default: "null", + }, + }} +/> + +## Preloading + +```csharp C# +Superwall.Shared.PreloadAllPaywalls(); + +Superwall.Shared.PreloadPaywallsForPlacements(new List +{ + "onboarding", + "upgrade" +}); +``` + +## Locale + +```csharp C# +Superwall.Shared.LocaleIdentifier = "es_ES"; +``` + +## Local Resources + +Android builds can map paywall asset names to local file paths. + +```csharp C# +Superwall.Shared.SetLocalResources(new Dictionary +{ + { "hero_image", "/absolute/path/to/hero.png" } +}); +``` + +`SetLocalResources` is Android-only in the current beta. It is a no-op on iOS. + +## Programmatic Purchase and Products + +```csharp C# +Superwall.Shared.GetProducts(new List { "monthly", "annual" }, products => +{ + foreach (var product in products) + { + Debug.Log($"{product.Key}: {product.Value.LocalizedPrice}"); + } +}); + +Superwall.Shared.Purchase("monthly", result => +{ + Debug.Log($"Purchase result: {result.Type}"); +}); +``` + +For normal paywall flows, prefer `RegisterPlacement`. diff --git a/content/docs/unity/guides/custom-purchase-controller.mdx b/content/docs/unity/guides/custom-purchase-controller.mdx new file mode 100644 index 0000000..c544498 --- /dev/null +++ b/content/docs/unity/guides/custom-purchase-controller.mdx @@ -0,0 +1,72 @@ +--- +title: "Custom Purchase Controller" +description: "Use a custom purchase controller with the Unity SDK beta." +--- + +By default, Superwall handles purchase and restore flows through the native iOS and Android SDKs. +Most Unity integrations should start there. + +Use `IPurchaseController` only when another system, such as your own store abstraction or a third +party purchase SDK, must complete purchases and restores. + +## Implement `IPurchaseController` + +```csharp C# +using System; +using Superwall; + +public sealed class GamePurchaseController : IPurchaseController +{ + public void PurchaseFromAppStore(string productId, Action completion) + { + // Complete the App Store purchase with your purchase system. + // Then call completion with the result. + completion(PurchaseResult.Purchased()); + } + + public void PurchaseFromGooglePlay( + string productId, + string basePlanId, + string offerId, + Action completion + ) + { + // Complete the Google Play purchase with your purchase system. + // Use basePlanId and offerId if your catalog needs them. + // Then call completion with the result. + completion(PurchaseResult.Purchased()); + } + + public void RestorePurchases(Action completion) + { + // Restore purchases with your purchase system. + completion(RestorationResult.Restored()); + } +} +``` + +Pass the controller when configuring Superwall: + +```csharp C# +Superwall.Configure( + "MY_PUBLIC_API_KEY", + purchaseController: new GamePurchaseController() +); +``` + +## Keep Subscription Status in Sync + +When your purchase system is the source of truth, update Superwall whenever access changes. + +```csharp C# +Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateActive(entitlements); +``` + +Or clear access: + +```csharp C# +Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateInactive(); +``` + +See [Tracking Subscription State](/unity/quickstart/tracking-subscription-state) for a complete +example. diff --git a/content/docs/unity/guides/game-controller-input.mdx b/content/docs/unity/guides/game-controller-input.mdx new file mode 100644 index 0000000..2c60a93 --- /dev/null +++ b/content/docs/unity/guides/game-controller-input.mdx @@ -0,0 +1,59 @@ +--- +title: "Game Controller Input" +description: "Enable game controller support for Unity paywalls." +--- + +Unity games often need paywalls that work with touch and controller input. Superwall supports +controller-triggered paywall actions when both the SDK and paywall template are configured for it. + +## Enable Controller Support in the SDK + +Set `IsGameControllerEnabled` when configuring Superwall. + +```csharp C# +using System.Collections.Generic; +using Superwall; + +var options = new SuperwallOptions +{ + IsGameControllerEnabled = true, + Logging = new Logging + { + Level = LogLevel.Debug, + Scopes = new List { LogScope.GameControllerManager } + } +}; + +Superwall.Configure("MY_PUBLIC_API_KEY", options: options); +``` + +## Enable Controller Support on the Paywall + +In the paywall editor, open the paywall settings and set **Game Controller Support** to **ENABLED**. + +![Paywall editor Game Controller Support setting enabled](/images/gc_unity.jpg) + +After this setting is enabled, click behavior controls can map an action to one of these controller +buttons: + +- `a` +- `b` +- `x` +- `y` +- `l1` +- `l2` +- `r1` +- `r2` +- `menu` +- `options` + +## Test on Device + +Controller support depends on the native iOS or Android runtime. The Unity Editor only logs SDK +method calls, so test with a controller connected to a real device, simulator, or emulator that +supports controller input. + + + If touch input works but controller input does not, verify both settings: + `IsGameControllerEnabled` in Unity and **Game Controller Support** in the paywall editor. + diff --git a/content/docs/unity/guides/using-superwall-delegate.mdx b/content/docs/unity/guides/using-superwall-delegate.mdx new file mode 100644 index 0000000..c4a25f4 --- /dev/null +++ b/content/docs/unity/guides/using-superwall-delegate.mdx @@ -0,0 +1,104 @@ +--- +title: "Using the Superwall Delegate" +description: "Receive Superwall lifecycle callbacks in Unity." +--- + +Implement `ISuperwallDelegate` when your game needs callbacks for paywall lifecycle events, +subscription changes, custom paywall actions, deep links, or SDK logs. + +## Set a Delegate + +Attach a delegate `MonoBehaviour` after `Superwall.Configure(...)`. + +```csharp C# +using System.Collections.Generic; +using UnityEngine; +using Superwall; + +public sealed class SuperwallEvents : MonoBehaviour, ISuperwallDelegate +{ + private void Start() + { + Superwall.Shared.SetDelegate(this); + } + + public void SubscriptionStatusDidChange(SubscriptionStatus from, SubscriptionStatus to) + { + Debug.Log($"Subscription: {from.Type} -> {to.Type}"); + } + + public void HandleSuperwallEvent(SuperwallEventInfo eventInfo) + { + Debug.Log($"Superwall event: {eventInfo.EventType}"); + } + + public void HandleCustomPaywallAction(string name) + { + Debug.Log($"Custom action: {name}"); + } + + public void WillPresentPaywall(PaywallInfo paywallInfo) { } + public void DidPresentPaywall(PaywallInfo paywallInfo) { } + public void WillDismissPaywall(PaywallInfo paywallInfo) { } + public void DidDismissPaywall(PaywallInfo paywallInfo) { } + + public void PaywallWillOpenURL(string url) + { + Application.OpenURL(url); + } + + public void PaywallWillOpenDeepLink(string url) + { + Application.OpenURL(url); + } + + public void HandleLog( + string level, + string scope, + string message, + Dictionary info, + string error + ) + { + if (level == "error") + { + Debug.LogError($"[Superwall] {scope}: {message} {error}"); + } + } + + public void WillRedeemLink() { } + public void DidRedeemLink(RedemptionResult result) { } + + public void HandleSuperwallDeepLink( + string fullURL, + List pathComponents, + Dictionary queryParameters + ) { } + + public void CustomerInfoDidChange(CustomerInfo from, CustomerInfo to) { } + public void UserAttributesDidChange(Dictionary newAttributes) { } +} +``` + +## Custom Paywall Actions + +Use custom actions when a paywall button should trigger game-specific behavior instead of a +purchase, restore, or close action. + +```csharp C# +public void HandleCustomPaywallAction(string name) +{ + if (name == "open_level_preview") + { + OpenLevelPreview(); + } +} +``` + +## Removing the Delegate + +Set the delegate to `null` when the object should no longer receive callbacks. + +```csharp C# +Superwall.Shared.SetDelegate(null); +``` diff --git a/content/docs/unity/index.mdx b/content/docs/unity/index.mdx new file mode 100644 index 0000000..598d6c0 --- /dev/null +++ b/content/docs/unity/index.mdx @@ -0,0 +1,61 @@ +--- +title: "Welcome" +description: "Welcome to the Superwall Unity SDK beta documentation." +--- + + + The Unity SDK is in beta. APIs, platform requirements, and package behavior may change before a + stable release. + + +The Superwall Unity SDK lets Unity mobile games present Superwall paywalls on iOS and Android. It is +a Unity package with a C# API that bridges to the native [Superwall iOS SDK](https://github.com/superwall/Superwall-iOS) +and [Superwall Android SDK](https://github.com/superwall/Superwall-Android). + +## Quick Links + + + + Add the beta package through Unity Package Manager. + + + Configure the SDK once when your game starts. + + + Register placements from C# and unlock game features. + + + Enable controller-aware paywall actions for mobile games. + + + Review the beta C# API surface. + + + View the Unity package source. + + + +## How It Works + +The package exposes a `Superwall` C# namespace for Unity scripts. At runtime: + +1. Your game calls `Superwall.Configure(...)` once with a Superwall Public API Key. +2. The Unity package creates a persistent `SuperwallBridge` GameObject for callbacks. +3. C# calls are forwarded to native iOS or Android bridge code. +4. The native Superwall SDK fetches campaigns, evaluates placements on device, presents the paywall, and returns callbacks to Unity. +5. Your C# `feature` callback runs when the user has access. + +On iOS, the package's post-build processor adds `SuperwallKit` to the generated Xcode project through CocoaPods. On Android, the package includes a Gradle `.androidlib` module that pulls the Superwall Android SDK and Google Play Billing dependencies. + +## Requirements + +- Unity 6+ (`6000.4+`) +- iOS 16.0+ +- Android `minSdkVersion` 25+ +- CocoaPods for iOS builds +- A Superwall project with mobile app credentials and at least one placement + + + The Unity Editor uses stubbed native calls and logs method names. Test paywall presentation, + purchases, and native callbacks on an iOS or Android build. + diff --git a/content/docs/unity/meta.json b/content/docs/unity/meta.json new file mode 100644 index 0000000..b7b3efc --- /dev/null +++ b/content/docs/unity/meta.json @@ -0,0 +1,27 @@ +{ + "title": "Unity SDK", + "description": "Beta", + "icon": "Puzzle", + "root": true, + "pages": [ + "index", + "changelog", + + "---Quickstart---", + "quickstart/install", + "quickstart/configure", + "quickstart/present-paywalls", + "quickstart/user-management", + "quickstart/tracking-subscription-state", + + "---Guides---", + "guides/game-controller-input", + "guides/using-superwall-delegate", + "guides/custom-purchase-controller", + "guides/advanced-configuration", + + "---SDK Reference---", + "sdk-reference/index", + "[GitHub Repository](https://github.com/superwall/Superwall-Unity)" + ] +} diff --git a/content/docs/unity/quickstart/configure.mdx b/content/docs/unity/quickstart/configure.mdx new file mode 100644 index 0000000..34ff41f --- /dev/null +++ b/content/docs/unity/quickstart/configure.mdx @@ -0,0 +1,74 @@ +--- +title: "Configure the SDK" +description: "Configure Superwall once when your Unity game starts." +--- + +Configure Superwall as early as possible in your first scene. A common pattern is to create a +bootstrap `MonoBehaviour`, attach it to a GameObject in the first scene, and keep that object alive. + +```csharp C# +using UnityEngine; +using Superwall; + +public sealed class SuperwallBootstrap : MonoBehaviour +{ + [Header("Superwall API Keys")] + [SerializeField] private string iosApiKey = "MY_IOS_PUBLIC_API_KEY"; + [SerializeField] private string androidApiKey = "MY_ANDROID_PUBLIC_API_KEY"; + + private void Awake() + { + DontDestroyOnLoad(gameObject); + + var apiKey = Application.platform == RuntimePlatform.IPhonePlayer + ? iosApiKey + : androidApiKey; + + var options = new SuperwallOptions + { + Logging = new Logging { Level = LogLevel.Warn }, + Paywalls = new PaywallOptions + { + ShouldPreload = true, + AutomaticallyDismiss = true + } + }; + + Superwall.Configure(apiKey, options: options, completion: result => + { + if (result.IsSuccess) + { + Debug.Log("[Superwall] Configured"); + return; + } + + if (result is ConfigurationResult.FailedResult failed) + { + Debug.LogError($"[Superwall] Configuration failed: {failed.Error}"); + } + }); + } +} +``` + +## Public API Keys + +Use the **Public API Key** from your Superwall dashboard app settings. If your Unity game ships on +both iOS and Android, create or use the matching Superwall app for each platform and choose the key +at runtime. + + + In the current beta, Android reports configuration failures through `ConfigurationResult`. iOS + reports success when the native `SuperwallKit` configuration callback completes. + + +## Configuration Options + +`SuperwallOptions` mirrors the native mobile SDK options for paywall behavior, logging, test mode, +locale, and other advanced settings. See [Advanced Configuration](/unity/guides/advanced-configuration) +for the full beta option surface. + + + After configuring Superwall, continue to [Presenting + Paywalls](/unity/quickstart/present-paywalls). + diff --git a/content/docs/unity/quickstart/install.mdx b/content/docs/unity/quickstart/install.mdx new file mode 100644 index 0000000..8476a37 --- /dev/null +++ b/content/docs/unity/quickstart/install.mdx @@ -0,0 +1,66 @@ +--- +title: "Install the SDK" +description: "Install the Superwall Unity SDK beta through Unity Package Manager." +--- + +## Overview + +Install the Unity SDK from the [Superwall-Unity GitHub repository](https://github.com/superwall/Superwall-Unity). The beta package name is `com.superwall.sdk`. + +## Requirements + +- Unity 6+ (`6000.4+`) +- iOS 16.0+ +- Android `minSdkVersion` 25+ +- CocoaPods installed locally for iOS builds + +## Add the Package + +In Unity, open **Window > Package Manager**. Click **+**, choose **Add package from git URL**, then paste: + +```text +https://github.com/superwall/Superwall-Unity.git +``` + +![Unity Package Manager Add package from git URL](/images/upm_add.jpg) + +After Unity resolves the package, your scripts can import the SDK: + +```csharp C# +using Superwall; +``` + +## iOS Build Setup + +The package includes an iOS post-build processor. When you build for iOS, it: + +1. Creates a `Podfile` if the generated Xcode project does not have one. +2. Adds `pod 'SuperwallKit', '~> 4.0'` to the `UnityFramework` target. +3. Sets the iOS deployment target to `16.0`. +4. Runs `pod install` in the generated Xcode project directory. + +If `pod install` fails, run it manually in the generated Xcode project folder and reopen the `.xcworkspace`. + + + If your Unity project already customizes the generated `Podfile`, make sure the `UnityFramework` + target includes the `SuperwallKit` pod. + + +## Android Build Setup + +No manual Android SDK setup is required for the default Unity Gradle export. The package includes a +Gradle `.androidlib` module that declares the Superwall paywall activities and pulls: + +- `com.superwall.sdk:superwall-android:2.+` +- Google Play Billing `8.0.0` +- Material Components `1.12.0` +- Kotlin coroutines for Android `1.9.0` + +The included Android manifest adds the internet, network state, notification, and Google Play Billing permissions, plus the Superwall paywall and debug activities. + + + If your project uses custom Gradle templates, keep `google()` and `mavenCentral()` enabled and do + not remove the generated Superwall `.androidlib` dependency. + + +After installing, continue to [Configure the SDK](/unity/quickstart/configure). diff --git a/content/docs/unity/quickstart/present-paywalls.mdx b/content/docs/unity/quickstart/present-paywalls.mdx new file mode 100644 index 0000000..9069282 --- /dev/null +++ b/content/docs/unity/quickstart/present-paywalls.mdx @@ -0,0 +1,111 @@ +--- +title: "Presenting Paywalls" +description: "Register Superwall placements from Unity C# scripts." +--- + +Placements are the main way to present paywalls. [Create a placement](/dashboard/dashboard-campaigns/campaigns-placements#adding-a-placement) +in the Superwall dashboard, add it to a campaign, then register the same placement name from your +Unity code. + +## Register a Placement + +Call `RegisterPlacement` when the user tries to access a feature that may be paywalled. + +```csharp C# +using System.Collections.Generic; +using UnityEngine; +using Superwall; + +public sealed class LevelGate : MonoBehaviour +{ + [SerializeField] private int levelNumber = 3; + + public void OnStartLevelPressed() + { + var handler = new PaywallPresentationHandler + { + OnPresent = info => + { + Debug.Log($"Paywall presented: {info.Name}"); + }, + OnDismiss = (info, result) => + { + Debug.Log($"Paywall dismissed: {result.Type}"); + }, + OnError = error => + { + Debug.LogError($"Paywall error: {error}"); + }, + OnSkip = reason => + { + Debug.Log($"Paywall skipped: {reason}"); + } + }; + + Superwall.Shared.RegisterPlacement( + "start_level", + parameters: new Dictionary + { + { "level", levelNumber }, + { "source", "level_select" } + }, + handler: handler, + feature: StartLevel + ); + } + + private void StartLevel() + { + Debug.Log("Feature unlocked"); + // Load the premium level, award the item, start the mode, etc. + } +} +``` + +## When the `feature` Callback Runs + +Superwall decides whether the placement should show a paywall based on the campaign configuration +downloaded at app start. + +The `feature` callback runs when the user has access: + +- The user already has an active subscription. +- The user purchases or restores from a gated paywall. +- The paywall is configured as non-gated. +- No paywall is configured for the placement. + +If a gated paywall is dismissed without a purchase or restore, the `feature` callback does not run. + +## Check the Presentation Result + +Use `GetPresentationResult` when you need to inspect what Superwall would do for a placement without +presenting it. In games, this is useful for keeping unlockable UI in sync with your dashboard +configuration, such as showing lock icons on levels, dimming premium cosmetics, or adding an upgrade +badge to a game mode before the player taps it. + +```csharp C# +Superwall.Shared.GetPresentationResult("start_level", completion: result => +{ + switch (result.Type) + { + case PresentationResult.ResultType.Paywall: + Debug.Log("A paywall is available for this placement."); + break; + case PresentationResult.ResultType.Holdout: + Debug.Log("The user is in a holdout."); + break; + case PresentationResult.ResultType.NoAudienceMatch: + Debug.Log("No audience matched."); + break; + case PresentationResult.ResultType.PlacementNotFound: + Debug.LogWarning("Placement was not found in the dashboard."); + break; + } +}); +``` + + + `GetPresentationResult` uses the same campaign and audience logic that would decide whether a + paywall appears. Use it to render upsell UI ahead of time, then call `RegisterPlacement` when the + player actually tries to unlock or start the gated content. + diff --git a/content/docs/unity/quickstart/tracking-subscription-state.mdx b/content/docs/unity/quickstart/tracking-subscription-state.mdx new file mode 100644 index 0000000..aa71b16 --- /dev/null +++ b/content/docs/unity/quickstart/tracking-subscription-state.mdx @@ -0,0 +1,85 @@ +--- +title: "Tracking Subscription State" +description: "Read or set subscription status from a Unity game." +--- + +If you do not pass a custom purchase controller, Superwall uses the native iOS and Android SDKs to +manage purchases and subscription-related state. + +## Read Subscription Status + +```csharp C# +using Superwall; + +var status = Superwall.Shared.SubscriptionStatus; + +if (status.Type == SubscriptionStatus.StatusType.Active) +{ + var active = (SubscriptionStatus.ActiveStatus)status; + Debug.Log($"Active entitlements: {active.Entitlements.Count}"); +} +``` + +You can also fetch customer info asynchronously: + +```csharp C# +Superwall.Shared.GetCustomerInfo(info => +{ + Debug.Log($"Customer: {info.UserId}"); + Debug.Log($"Entitlements: {info.Entitlements.Count}"); +}); +``` + +## Set Subscription Status Manually + +Set subscription status manually when another purchase system is the source of truth for access. In +a complete custom purchase integration, configure Superwall with an +[`IPurchaseController`](/unity/guides/custom-purchase-controller) so paywall purchase and restore +actions are routed to your purchase code, then update `SubscriptionStatus` whenever the player's +entitlements change. + + + If you are using Superwall-managed purchases, do not set `SubscriptionStatus` directly. The native + iOS and Android SDKs update it automatically after purchases, restores, and receipt checks. + + +```csharp C# +using System.Collections.Generic; +using Superwall; + +var entitlements = new List +{ + new Entitlement + { + Id = "pro", + IsActive = true, + Type = EntitlementType.ServiceLevel + } +}; + +Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateActive(entitlements); +``` + +Set the status to inactive when the player loses access: + +```csharp C# +Superwall.Shared.SubscriptionStatus = SubscriptionStatus.CreateInactive(); +``` + +## Listen for Changes + +Implement `ISuperwallDelegate` when you need callbacks for subscription or customer changes. + +```csharp C# +public void SubscriptionStatusDidChange(SubscriptionStatus from, SubscriptionStatus to) +{ + Debug.Log($"Subscription status changed: {from.Type} -> {to.Type}"); +} + +public void CustomerInfoDidChange(CustomerInfo from, CustomerInfo to) +{ + Debug.Log($"Customer info changed for {to.UserId}"); +} +``` + +See [Using the Superwall Delegate](/unity/guides/using-superwall-delegate) for setup. diff --git a/content/docs/unity/quickstart/user-management.mdx b/content/docs/unity/quickstart/user-management.mdx new file mode 100644 index 0000000..cb74060 --- /dev/null +++ b/content/docs/unity/quickstart/user-management.mdx @@ -0,0 +1,73 @@ +--- +title: "User Management" +description: "Identify, reset, and attach attributes to Unity players." +--- + +Superwall starts with an anonymous user ID. Identify players after login or account creation so +paywall assignments and analytics follow the same user across devices. + +## Identify a User + +```csharp C# +using Superwall; + +public void OnLoginComplete(string userId) +{ + Superwall.Shared.Identify(userId); +} +``` + +If you want Superwall to restore paywall assignments after identifying the user, pass +`IdentityOptions`. + +```csharp C# +Superwall.Shared.Identify( + "user_123", + new IdentityOptions { RestorePaywallAssignments = true } +); +``` + +## Reset on Logout + +Call `Reset` when the player logs out. + +```csharp C# +public void OnLogout() +{ + Superwall.Shared.Reset(); +} +``` + +## Set User Attributes + +Use attributes to target audiences and personalize paywalls. + +```csharp C# +using System.Collections.Generic; +using Superwall; + +Superwall.Shared.SetUserAttributes(new Dictionary +{ + { "player_level", 42 }, + { "guild_id", "north_star" }, + { "completed_tutorial", true } +}); +``` + +You can read the current attributes from Unity: + +```csharp C# +var attributes = Superwall.Shared.GetUserAttributes(); +``` + +## Read Identity State + +```csharp C# +var userId = Superwall.Shared.UserId; +var isLoggedIn = Superwall.Shared.IsLoggedIn; +``` + + + Avoid sending personally identifiable information as plain user attributes unless your privacy + policy and data processing setup allow it. + diff --git a/content/docs/unity/sdk-reference/index.mdx b/content/docs/unity/sdk-reference/index.mdx new file mode 100644 index 0000000..5f64a87 --- /dev/null +++ b/content/docs/unity/sdk-reference/index.mdx @@ -0,0 +1,175 @@ +--- +title: "SDK Reference" +description: "Reference for the Superwall Unity SDK beta C# API." +--- + +The Unity SDK exposes the `Superwall` namespace. Configure the SDK once with the static +`Superwall.Configure(...)` method, then use `Superwall.Shared` for placement registration, user +management, subscription state, and paywall utilities. + +## `Superwall.Configure` + +```csharp C# +public static Superwall Configure( + string apiKey, + SuperwallOptions options = null, + IPurchaseController purchaseController = null, + Action completion = null +) +``` + +", + description: "Optional callback invoked after native configuration completes.", + default: "null", + }, + }} +/> + +## `RegisterPlacement` + +```csharp C# +public void RegisterPlacement( + string placement, + Dictionary parameters = null, + PaywallPresentationHandler handler = null, + Action feature = null +) +``` + +", + description: "Optional placement parameters for audience filters and paywall variables.", + default: "null", + }, + handler: { + type: "PaywallPresentationHandler", + description: + "Optional callbacks for paywall presentation, dismissal, errors, skips, and custom callbacks.", + default: "null", + }, + feature: { + type: "Action", + description: "Callback that runs when the user has access to the feature.", + default: "null", + }, + }} +/> + +## Common Methods and Properties + + attributes)", + description: "Sets user attributes for targeting and personalization.", + }, + SubscriptionStatus: { + type: "SubscriptionStatus", + description: "Gets or sets the current subscription status.", + }, + GetCustomerInfo: { + type: "void GetCustomerInfo(Action completion)", + description: "Fetches customer info asynchronously.", + }, + GetPresentationResult: { + type: "void GetPresentationResult(string placement, Dictionary parameters = null, Action completion = null)", + description: "Checks what Superwall would do for a placement without presenting it.", + }, + PreloadAllPaywalls: { + type: "void PreloadAllPaywalls()", + description: "Preloads all paywalls from the current configuration.", + }, + PreloadPaywallsForPlacements: { + type: "void PreloadPaywallsForPlacements(List placementNames)", + description: "Preloads paywalls for the provided placement names.", + }, + HandleDeepLink: { + type: "bool HandleDeepLink(string url)", + description: "Passes a URL to the native SDK for deep link handling.", + }, + Dismiss: { + type: "void Dismiss()", + description: "Dismisses the currently presented paywall.", + }, + Purchase: { + type: "void Purchase(string productId, Action completion)", + description: "Purchases a product directly without presenting a paywall.", + }, + GetProducts: { + type: "void GetProducts(List productIds, Action> completion)", + description: "Fetches store product details by product ID.", + }, + RefreshConfiguration: { + type: "void RefreshConfiguration()", + description: "Forces a configuration refresh.", + }, + IsConfigured: { + type: "bool", + description: "Whether the native SDK is configured.", + }, + IsPaywallPresented: { + type: "bool", + description: "Whether a paywall is currently presented.", + }, + }} +/> + +## Presentation Handler + +```csharp C# +public class PaywallPresentationHandler +{ + public Action OnPresent; + public Action OnDismiss; + public Action OnError; + public Action OnSkip; + public Func OnCustomCallback; +} +``` + +## Related Guides + +- [Install the SDK](/unity/quickstart/install) +- [Configure the SDK](/unity/quickstart/configure) +- [Presenting Paywalls](/unity/quickstart/present-paywalls) +- [Advanced Configuration](/unity/guides/advanced-configuration) +- [Custom Purchase Controller](/unity/guides/custom-purchase-controller) diff --git a/src/lib/llms.ts b/src/lib/llms.ts index 180be1b..6090775 100644 --- a/src/lib/llms.ts +++ b/src/lib/llms.ts @@ -19,6 +19,10 @@ export const llmsSectionConfigs = { label: "Expo", urlPrefix: "/docs/expo", }, + unity: { + label: "Unity", + urlPrefix: "/docs/unity", + }, "react-native": { label: "React Native", urlPrefix: "/docs/react-native", @@ -62,6 +66,7 @@ function getExamplePathForSection(section: string): string { android: "/docs/android/guides/advanced/game-controller-support.md", flutter: "/docs/flutter/guides/advanced/game-controller-support.md", expo: "/docs/expo/guides/advanced/game-controller-support.md", + unity: "/docs/unity/guides/game-controller-input.md", "react-native": "/docs/react-native/guides/advanced/game-controller-support.md", dashboard: "/docs/dashboard/dashboard-settings/overview-settings-apple-search-ads.md", integrations: "/docs/integrations/amplitude.md", @@ -77,7 +82,7 @@ export function buildLLMSummaryTextFromPages(pages: LLMPageLike[], section?: str // Add Superwall description lines.push( - "Superwall is a platform for remotely configuring and A/B testing mobile app paywalls — no app update required. It provides SDKs for iOS, Android, Flutter, Expo, and React Native, plus a dashboard for managing paywall presentation, experiments, and subscription analytics.", + "Superwall is a platform for remotely configuring and A/B testing mobile app paywalls — no app update required. It provides SDKs for iOS, Android, Flutter, Expo, Unity, and React Native, plus a dashboard for managing paywall presentation, experiments, and subscription analytics.", "", ); diff --git a/src/lib/sitemap.ts b/src/lib/sitemap.ts index cf7293d..fa2ac21 100644 --- a/src/lib/sitemap.ts +++ b/src/lib/sitemap.ts @@ -38,6 +38,7 @@ export function getSitemapEntries(pagePaths: string[], now = new Date()): Sitema toSitemapEntry("/android", 0.9, nowIso), toSitemapEntry("/flutter", 0.9, nowIso), toSitemapEntry("/expo", 0.9, nowIso), + toSitemapEntry("/unity", 0.9, nowIso), ]; const pageEntries = pagePaths.map((pagePath) => toSitemapEntry(pagePath, 0.8, nowIso)); diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 075d14c..4cb29e6 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -155,6 +155,12 @@ const sdkCards: DocCard[] = [ href: buildDocsPath("flutter"), icon: , }, + { + title: "Unity (Beta)", + description: "Integrate Superwall into your Unity mobile game.", + href: buildDocsPath("unity"), + icon: , + }, { title: "React Native (Legacy)", description: "Legacy SDK for React Native. Migrate to the Expo SDK for new projects.",