From acb257d4b18032822936148bb28856c15d17ce89 Mon Sep 17 00:00:00 2001 From: bitsandfoxes Date: Fri, 30 Oct 2026 10:19:47 +0100 Subject: [PATCH 1/2] docs(unity): Add Unity as a Library page Document the experimental NativeInitializationType.External for games embedded into an iOS or Android app that runs its own Sentry SDK (getsentry/sentry-unity#2885, getsentry/sentry-unity#2895): setting up the app and the game, what the export leaves out, what the game shares with the app, the two Android process layouts, and known limitations. List External alongside the other initialization types. --- .../programmatic-configuration/index.mdx | 5 +- docs/platforms/unity/native-support/index.mdx | 11 +- .../unity-as-a-library/index.mdx | 131 ++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 docs/platforms/unity/native-support/unity-as-a-library/index.mdx diff --git a/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx b/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx index 45e71f9d67d25..33c0f45d717d6 100644 --- a/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx +++ b/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx @@ -54,13 +54,16 @@ public override void Configure(SentryUnityOptions options) ### Initialize Native SDKs first when targeting iOS or Android On mobile, the Unity SDK automatically modifies the generated Xcode and Gradle project to also contain the Cocoa and Java SDK respectively. These SDKs are capable of self-initializing before the Unity engine itself is started. This allows us to capture bugs/crashes happening within the engine itself. -There are two initialization types: +There are three initialization types: - `NativeInitializationType.Runtime`: Native SDKs initialize during runtime alongside the C# SDK - `NativeInitializationType.BuildTime`: Native SDKs initialize before Unity engine starts +- `NativeInitializationType.External`: The app that embeds the game initializes the native SDKs, when using Unity as a Library ### Runtime Initialization (Default) + With runtime initialization, the native SDKs are initialized at runtime alongside the C# SDK. This allows all options to be dynamically configured through C# code during execution. ### Build Time Initialization + When using build time initialization, the native SDKs are configured during build time and initialize before the Unity engine starts. This means the options are baked into the outputted projects and cannot be modified at runtime via C# code. Changes to properties like `Release` and `Environment` will not apply to events generated by the native SDKs. diff --git a/docs/platforms/unity/native-support/index.mdx b/docs/platforms/unity/native-support/index.mdx index 8a35bba0cd9fa..9f595c483d0e0 100644 --- a/docs/platforms/unity/native-support/index.mdx +++ b/docs/platforms/unity/native-support/index.mdx @@ -15,19 +15,22 @@ The native crash support for Android and iOS is provided by adding platform-spec ### Initialization of the Native SDKs The [iOS SDK](/platforms/apple/guides/ios/) and [Android SDK](/platforms/android/) are capable of self-initializing before the Unity engine itself is started. This allows us to capture bugs/crashes happening within the engine itself. -There are two initialization types: +There are three initialization types: - `NativeInitializationType.Runtime`: Native SDKs initialize during runtime alongside the C# SDK - `NativeInitializationType.BuildTime`: Native SDKs initialize before Unity engine starts +- `NativeInitializationType.External`: The app that embeds the game initializes the native SDKs, when using Unity as a Library ### Runtime Initialization (Default) With runtime initialization, the native SDKs are initialized at runtime alongside the C# SDK. This allows all options to be dynamically configured through C# code during execution. #### Android + At build time, the SDK modifies the generated Gradle project to include the Android SDK but sets `io.sentry.auto-init` in the `AndroidManifest.xml` to `false`. The Unity SDK will then initialize the Android SDK when it initializes itself. #### iOS + At built time, the SDK modifies the generated Xcode project to include the iOS SDK but will not modify the `main.m` file or write the options to file. The Unity SDK will then initialize the iOS SDK when it initializes itself. ### Build Time Initialization @@ -35,13 +38,19 @@ At built time, the SDK modifies the generated Xcode project to include the iOS S When using build time initialization, the native SDKs are configured during build time and initialize before the Unity engine starts. This means the options are baked into the outputted projects and cannot be modified at runtime via C# code. Changes to properties like `Release` and `Environment` will not apply to events generated by the native SDKs. #### Android + The SDK modifies the generated Gradle project to include the Android SDK. At build time, it will also write the options to the `AndroidManifest.xml`. These options cannot be changed at runtime. Changes to the options in the configuration callback will not affect the Android SDK. #### iOS + The SDK modifies the generated Xcode project to include the iOS SDK. It adds the initialization code to the `main.m` and generates the options provided by the editor configuration window as `SentryOptions.m`. The SDK also copies the `SentryNativeBridge` that enables the C# layer to communicate with the iOS SDK. This means that there's no need to use the Unity [built-in crash reporting](https://docs.unity3d.com/ScriptReference/CrashReport.html) functionality. The [iOS SDK](/platforms/apple/guides/ios/) supports capturing Objective-C exceptions which are disabled in the generated Xcode project by default. Consider enabling them in the "Build Settings" tab by setting `GCC_ENABLE_OBJC_EXCEPTIONS` to true. +### External Initialization + +When your game runs inside an iOS or Android app with Unity as a Library, the app owns the native SDK. The Unity SDK doesn't bundle or initialize it, but attaches to the one the app initialized. Learn more in Unity as a Library. + ## Desktop The native support is configured and enabled as early as possible by the C# layer, right after the Unity engine starts. This is slightly different from on mobile where we inject native initialization code that runs before the Unity engine runs. diff --git a/docs/platforms/unity/native-support/unity-as-a-library/index.mdx b/docs/platforms/unity/native-support/unity-as-a-library/index.mdx new file mode 100644 index 0000000000000..b3ab29c79d510 --- /dev/null +++ b/docs/platforms/unity/native-support/unity-as-a-library/index.mdx @@ -0,0 +1,131 @@ +--- +title: Unity as a Library +description: "Learn how to use the Unity SDK when your game runs inside an iOS or Android app with Unity as a Library." +sidebar_order: 10 +--- + +With [Unity as a Library](https://docs.unity3d.com/Manual/UnityasaLibrary.html), you export your game and embed it into a native iOS or Android app. When that app already uses Sentry, the Unity SDK attaches to the app's sentry-cocoa or sentry-android SDK instead of bundling and starting its own. Both report to Sentry together: native crashes in the game carry the game's context and breadcrumbs, and the game's C# events use the app's release, environment, user, and trace. + + + +Support for Unity as a Library is experimental. Its behavior may change between releases. + + + +## Requirements + +- Unity SDK 4.12.0 or later +- On iOS: an app that uses the [Sentry Apple SDK](/platforms/apple/guides/ios/) (sentry-cocoa) 9.25.0 or later +- On Android: an app that depends on `io.sentry:sentry-android` 8.59.0 or later, and a game built with IL2CPP + +## Set Up the App + +The app initializes Sentry before it loads the game. Use the same DSN as in the game, so all events end up in one project and get symbolicated with the debug symbols uploaded for both. + +```swift {tabTitle:iOS (Swift)} {mdExpandTabs} +import Sentry + +func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + SentrySDK.start { options in + options.dsn = "___PUBLIC_DSN___" + } + + // Load UnityFramework afterwards + return true +} +``` + +```kotlin {tabTitle:Android (Kotlin)} +import android.app.Application +import android.os.Build +import io.sentry.android.core.SentryAndroid +import java.io.File + +class MyApplication : Application() { + override fun onCreate() { + super.onCreate() + + // Only in the main process, so the game starts its own SDK when it runs in a separate process + if (!isMainProcess()) return + + SentryAndroid.init(this) { options -> + options.dsn = "___PUBLIC_DSN___" + } + } + + private fun isMainProcess(): Boolean { + val processName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + Application.getProcessName() + } else { + File("/proc/self/cmdline").readText().trimEnd('\u0000') + } + return processName == packageName + } +} +``` + +On Android, the app's Gradle project depends on `io.sentry:sentry-android` and includes the exported `unityLibrary`. Also: + +- Initialize Sentry in the main process only, as shown above. `Application.onCreate` runs in every process of the app, so otherwise a game running in a separate process attaches to an SDK started with the app's options. +- When the game runs in a separate process, don't set a custom `cacheDirPath`. + +To learn more about setting up the app, see the [Apple](/platforms/apple/guides/ios/) and [Android](/platforms/android/) SDK docs, and Unity's guides for [iOS](https://docs.unity3d.com/Manual/UnityasaLibrary-iOS.html) and [Android](https://docs.unity3d.com/Manual/UnityasaLibrary-Android.html). + +## Set Up the Game + +Set the native initialization type to `External` through [programmatic configuration](/platforms/unity/configuration/options/programmatic-configuration/), and keep native support enabled in **Tools > Sentry > Advanced > Native Support**: + +```csharp +public override void Configure(SentryUnityOptions options) +{ + options.IosNativeInitializationType = NativeInitializationType.External; + options.AndroidNativeInitializationType = NativeInitializationType.External; +} +``` + +The SDK also reads this setting when it builds and exports the game. Set it unconditionally, or behind a compile-time symbol such as a custom scripting define for your Unity as a Library exports, but not behind a runtime check like `Application.isEditor`. Otherwise, the export includes the Sentry native SDK as if it were a standalone game. + +If the game runs in the app's process and the app hasn't initialized Sentry by the time the game starts, the SDK logs `The native SDK is expected to be initialized by the app but it is not` and only reports C# events, with the release and environment set in Unity. + +## What Changes in the Export + +On iOS: + +- The export doesn't include the Sentry framework. The game uses the app's sentry-cocoa. +- Debug symbols get uploaded from the `UnityFramework` target. +- When you switch to or from `External`, export with **Replace** instead of **Append**. + +On Android: + +- The exported `unityLibrary` doesn't contain the Sentry AARs or any `io.sentry` entries in its `AndroidManifest.xml`, since its manifest merges into the app's. +- The SDK's ProGuard rules stay in the library's consumer ProGuard files. +- Debug symbols get uploaded when the app builds `unityLibrary`. The app minifies the code, so it uploads its own ProGuard mapping, for example with the [Sentry Android Gradle Plugin](/platforms/android/configuration/gradle/). + +## What the Game Shares With the App + +On iOS, and on Android when the game runs in the app's main process, the game attaches to the app's SDK: + +- **Release and environment**: The game's events use the app's release and environment, unless you set them in Unity, through the **Override Release** and **Override Environment** fields or programmatically. +- **User**: The game's events use the app's user (ID, username, email, and IP address). A user that the game sets takes precedence for its own events, but doesn't reach the app, so native crashes carry the app's user. +- **Trace**: The game's events and logs continue the app's trace. Transactions that you start with `SentrySdk.StartTransaction` and a name and operation, as well as the SDK's automatic startup and scene loading transactions, join it. Transactions started with a `TransactionContext` start their own trace. +- **Scope**: The game's breadcrumbs, tags, extras, and Unity contexts go into the app's scope, so native crashes in the game carry them. Tags set by the game also show up on the app's events. +- **Sessions**: The app tracks sessions, so the game doesn't. + +Options that you set in Unity don't apply to the app's native SDK. + +## Android: Main Process or Separate Process + +On Android, the game can run in the app's main process, or in a separate process like `:Unity`, as in Unity's sample. + +- **Main process**: The game attaches to the sentry-android SDK that the app initialized. The app's SDK reports native crashes on the next launch of the app. +- **Separate process**: The app's SDK isn't running in the game's process, so the game initializes sentry-android there with the options set in Unity. + - The game takes the app's release and environment when it starts, and the app's user and trace when it starts and whenever it resumes. It reads them from the app's SDK cache, which requires the same DSN. + - The game's user, breadcrumbs, tags, and contexts go to the game's own SDK. Its native crashes carry them, and the app's events don't get the game's tags. + - The game's SDK reports native crashes the next time the game starts, so a crash isn't reported if the game never gets opened again. On Android 11 and later, the app's SDK reports ANRs for both processes. + +## Known Limitations + +- Changes to the app's user reach the game's logs the next time the game resumes. +- In a separate process, the game doesn't keep the app's sampling decision for the trace it continues. +- Unloading the game keeps the Unity SDK running, and reloading doesn't initialize it again. From 4b003c344ce866481a418a205233837519fa4e50 Mon Sep 17 00:00:00 2001 From: bitsandfoxes Date: Fri, 30 Oct 2026 11:02:35 +0100 Subject: [PATCH 2/2] docs(unity): Fix Unity as a Library statements found in fact-check --- .../programmatic-configuration/index.mdx | 2 +- docs/platforms/unity/native-support/index.mdx | 4 ++-- .../unity-as-a-library/index.mdx | 22 +++++++++++-------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx b/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx index 33c0f45d717d6..4c5e2b9bb8420 100644 --- a/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx +++ b/docs/platforms/unity/configuration/options/programmatic-configuration/index.mdx @@ -58,7 +58,7 @@ There are three initialization types: - `NativeInitializationType.Runtime`: Native SDKs initialize during runtime alongside the C# SDK - `NativeInitializationType.BuildTime`: Native SDKs initialize before Unity engine starts -- `NativeInitializationType.External`: The app that embeds the game initializes the native SDKs, when using Unity as a Library +- `NativeInitializationType.External`: The app that embeds the game provides and initializes the native SDKs, when using Unity as a Library ### Runtime Initialization (Default) diff --git a/docs/platforms/unity/native-support/index.mdx b/docs/platforms/unity/native-support/index.mdx index 9f595c483d0e0..ead41cac08872 100644 --- a/docs/platforms/unity/native-support/index.mdx +++ b/docs/platforms/unity/native-support/index.mdx @@ -19,7 +19,7 @@ There are three initialization types: - `NativeInitializationType.Runtime`: Native SDKs initialize during runtime alongside the C# SDK - `NativeInitializationType.BuildTime`: Native SDKs initialize before Unity engine starts -- `NativeInitializationType.External`: The app that embeds the game initializes the native SDKs, when using Unity as a Library +- `NativeInitializationType.External`: The app that embeds the game provides and initializes the native SDKs, when using Unity as a Library ### Runtime Initialization (Default) @@ -49,7 +49,7 @@ The [iOS SDK](/platforms/apple/guides/ios/) supports capturing Objective-C excep ### External Initialization -When your game runs inside an iOS or Android app with Unity as a Library, the app owns the native SDK. The Unity SDK doesn't bundle or initialize it, but attaches to the one the app initialized. Learn more in Unity as a Library. +When your game runs inside an iOS or Android app with Unity as a Library, the app owns the native SDK. The Unity SDK doesn't bundle it and attaches to the one the app initialized. On Android, a game running in a separate process initializes it there. Learn more in Unity as a Library. ## Desktop diff --git a/docs/platforms/unity/native-support/unity-as-a-library/index.mdx b/docs/platforms/unity/native-support/unity-as-a-library/index.mdx index b3ab29c79d510..343ee2d91f537 100644 --- a/docs/platforms/unity/native-support/unity-as-a-library/index.mdx +++ b/docs/platforms/unity/native-support/unity-as-a-library/index.mdx @@ -4,7 +4,7 @@ description: "Learn how to use the Unity SDK when your game runs inside an iOS o sidebar_order: 10 --- -With [Unity as a Library](https://docs.unity3d.com/Manual/UnityasaLibrary.html), you export your game and embed it into a native iOS or Android app. When that app already uses Sentry, the Unity SDK attaches to the app's sentry-cocoa or sentry-android SDK instead of bundling and starting its own. Both report to Sentry together: native crashes in the game carry the game's context and breadcrumbs, and the game's C# events use the app's release, environment, user, and trace. +With [Unity as a Library](https://docs.unity3d.com/Manual/UnityasaLibrary.html), you export your game and embed it into a native iOS or Android app. When that app already uses Sentry, the Unity SDK doesn't bundle its own sentry-cocoa or sentry-android SDK. It attaches to the app's SDK or, when the game runs in a separate Android process, starts one there. Both report to Sentry together: native crashes in the game carry the game's context and breadcrumbs, and the game's C# events use the app's release, environment, user, and trace. @@ -24,15 +24,19 @@ The app initializes Sentry before it loads the game. Use the same DSN as in the ```swift {tabTitle:iOS (Swift)} {mdExpandTabs} import Sentry +import UIKit -func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - SentrySDK.start { options in - options.dsn = "___PUBLIC_DSN___" - } +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + SentrySDK.start { options in + options.dsn = "___PUBLIC_DSN___" + } - // Load UnityFramework afterwards - return true + // Load UnityFramework afterwards + return true + } } ``` @@ -122,7 +126,7 @@ On Android, the game can run in the app's main process, or in a separate process - **Separate process**: The app's SDK isn't running in the game's process, so the game initializes sentry-android there with the options set in Unity. - The game takes the app's release and environment when it starts, and the app's user and trace when it starts and whenever it resumes. It reads them from the app's SDK cache, which requires the same DSN. - The game's user, breadcrumbs, tags, and contexts go to the game's own SDK. Its native crashes carry them, and the app's events don't get the game's tags. - - The game's SDK reports native crashes the next time the game starts, so a crash isn't reported if the game never gets opened again. On Android 11 and later, the app's SDK reports ANRs for both processes. + - The game's SDK reports native crashes the next time the game starts, so a crash isn't reported if the game never gets opened again. On Android 11 and later, the app's SDK reports ANRs of both processes the next time the app starts. ## Known Limitations