- Last Updated
Guides you through environment setup, build configuration, and SDK Config registration after adding the SDK.
Development Environment Setup
Environment Definitions
The STOVE platform consists of two environments: Sandbox for development and testing, and Live for actual service. The two environments have completely separate data, accounts, and consoles, so the SDK must also be configured for each environment.
| Category | Sandbox | Live |
|---|---|---|
| Purpose | Development / QA / testing | Actual service |
| Partners | partners.gate8.com | partners.onstove.com |
| API Host | api.gate8.com | api.onstove.com |
| PC launcher | Launcher 3.0 Sandbox + developer mode available | Launcher 3.0 Live |
| Account / data | Operated independently. No impact on live service | Operated independently. Switched over after QA |
Partners access by environment
ㅁ Partners has a different access URL per environment. Each environment can only be accessed via a VPN account.
ㅁ All registration tasks, such as SDK Config and app registration, must be done separately in each environment's Partners.
- Switching environments
Which environment the SDK calls is determined by the environment setting value of the client build.
It is generally branched by build type (debug / release) or an SDK initialization option.
- Development/QA build: Sandbox
- Store release build: Live
Environment synchronization caution
ㅁ The client's environment setting and the environment where the SDK Config is registered in Partners must always match.
ㅁ If a Sandbox client looks up a Live SDK Config, SDK init fails.
Adding the SDK per Platform
This is how to add SDK modules and configure the build environment per platform. For SDK downloads, please refer to the SDK Download and Installation guide first.
Just follow the one section for your environment, top to bottom
ㅁ Applying the section for your environment (MobileSDK / PC SDK) in order completes the environment setup. MobileSDK is subdivided into sub-sections by build environment (Android / iOS / Unity / Unreal).
ㅁ The example code is based on SDK 2.9.0. Check the latest module versions in SDK Download and Installation.
ㅁ The keys for each authentication Provider (facebook_app_id, google_web_client_id, naver_client_id, etc.) are covered per Provider in the Sign-in Guide.
Mobile SDK
This is the SDK that runs on mobile (Android / iOS). Follow the sub-section that matches your build environment. Even within mobile, the setup differs by build tool (native / Unity / Unreal), so it is split into four.
Unity
After importing the .unitypackage, proceed through Unity STOVE environment setup + Android Custom Gradle Template + UnityPlayerActivity extra setup + iOS Xcode post-processing. (Unity 2022.3.10f1 or higher)
1) Import the Unity package
- Unzip the
.unitypackageobtained from SDK Download and Installation - Import via Unity → Assets → Import Package → Custom Package…
2) STOVE environment setup (Zone)
Separately from StoveEnvironment in the iOS Info.plist, Unity sets the environment directly in the editor Inspector.
- Click Unity → Stove → Edit Settings
- Set the
Zoneitem in the Inspector window —live/sandbox
3) Android — Enable the 5 Custom Gradle Templates
In Project Settings → Player → Android → Publishing Settings, check all 5 below.
- Custom Main Gradle Template →
Assets/Plugins/Android/mainTemplate.gradle - Custom Launcher Gradle Template →
launcherTemplate.gradle - Custom Base Gradle Template →
baseProjectTemplate.gradle - Custom Gradle Properties Template →
gradleTemplate.properties - Custom Settings Gradle Template →
settingsTemplate.gradle
baseProjectTemplate.gradle — specify the Plugin version
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
//**BUILD_SCRIPT_DEPS**
}
task clean(type: Delete) {
delete rootProject.buildDir
}
gradleTemplate.properties — enable AndroidX / Jetifier
org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
unityStreamingAssets=**STREAMING_ASSETS**
android.useAndroidX=true
android.enableJetifier=true
**ADDITIONAL_PROPERTIES**
settingsTemplate.gradle — register the STOVE / Huawei / OneStore Maven repositories
pluginManagement {
repositories {
**ARTIFACTORYREPOSITORY**
gradlePluginPortal()
google()
mavenCentral()
}
}
include ':launcher', ':unityLibrary'
**INCLUDES**
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
**ARTIFACTORYREPOSITORY**
google()
mavenCentral()
flatDir { dirs "${project(':unityLibrary').projectDir}/libs" }
maven { url "https://externalnexus.iam0.com/repository/mvp"; allowInsecureProtocol = true } // STOVE
maven { url "https://jitpack.io"; allowInsecureProtocol = true }
maven { url "https://developer.huawei.com/repo/"; allowInsecureProtocol = true } // Huawei
maven { url "https://repo.onestore.net/repository/onestore-sdk-public"; allowInsecureProtocol = true } // OneStore
}
}
mainTemplate.gradle — STOVE dependencies + dataBinding + multiDexEnabled
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.stove:base:2.9.0'
implementation 'com.stove:log:2.9.0'
implementation 'com.stove:auth:2.9.0'
implementation 'com.stove:auth-apple:2.9.0'
implementation 'com.stove:auth-facebook:2.9.0'
implementation 'com.stove:auth-google:2.9.0'
implementation 'com.stove:auth-naver:2.9.0'
implementation 'com.stove:auth-line:2.9.0'
implementation 'com.stove:auth-steam:2.9.0'
implementation 'com.stove:auth-ui:2.9.0'
implementation 'com.stove:push:2.9.0'
implementation 'com.stove:push-firebase:2.9.0'
implementation 'com.stove:view:2.9.0'
implementation 'com.stove:iap:2.9.0'
implementation 'com.stove:iap-google:2.9.0'
implementation 'com.stove:gamingservices:2.9.0'
**DEPS**
}
android {
defaultConfig { multiDexEnabled true }
buildFeatures { dataBinding true }
}
launcherTemplate.gradle — avoid Amazon Build conflicts + force SDK 2.8.0
configurations.all {
// Exclude duplicate dependencies in Amazon Build
exclude(group: 'com.google.protobuf', module: 'protobuf-lite')
// Android 7.x support is required when using SDK 2.8.0+
resolutionStrategy {
force 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
}
android {
defaultConfig { multiDexEnabled true }
buildFeatures { dataBinding true }
}
4) Extra setup when subclassing UnityPlayerActivity
If you subclass UnityPlayerActivity to use a custom Activity, add the code below and set hardwareAccelerated in the manifest so that STOVE Push / View UI Overlay work correctly.
class CustomActivity : UnityPlayerActivity() {
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
Push.handleIntent(applicationContext, intent) // Add Push behavior
}
override fun onNewIntent(newIntent: Intent?) {
super.onNewIntent(newIntent)
Push.handleIntent(applicationContext, newIntent)
}
// View 2.8.2 or higher — add UI Overlay behavior
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 7585) ViewUI.handleIntent(requestCode, resultCode, data)
}
}
AndroidManifest hardware acceleration setting (required for View 2.8.2+)
<activity
android:name="com.stove.unity.StoveUnityPlayerActivity"
android:hardwareAccelerated="true"
android:exported="true">
<!-- ... -->
</activity>
5) iOS — Xcode post-processing (PostProcessBuild recommended)
Unity generates an Xcode project at build time. To avoid touching it manually every build, we recommend placing a PostProcessBuild script in Assets/Editor/. The items to automate are as follows (see the iOS section above for concrete values).
- Write the Podfile +
pod install - Add
Info.plistkeys (StoveEnvironment/LSApplicationQueriesSchemes=[mstove]/ URL Schemes / permission messages) - Merge entitlements (Capabilities keys)
- Add Library / Runpath Search Paths (Xcode 16.x / 26 branch)
- Insert the
SGSApplicationDelegate openURLdelegation code intoAppDelegate.mm
Library / Runpath Search Paths — actual Xcode-version-branch code:
pbxProject.AddBuildProperty(targetGuid, "LIBRARY_SEARCH_PATHS", "$(SDKROOT)/usr/lib/swift");
pbxProject.AddBuildProperty(targetGuid, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)");
pbxProject.AddBuildProperty(targetGuid, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)");
pbxProject.AddBuildProperty(targetGuid, "LD_RUNPATH_SEARCH_PATHS", "/usr/lib/swift");
pbxProject.AddBuildProperty(targetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
// Apply the same to the UnityFramework target
pbxProject.AddBuildProperty(frameworkTargetGuid, "LIBRARY_SEARCH_PATHS", "$(SDKROOT)/usr/lib/swift");
pbxProject.AddBuildProperty(frameworkTargetGuid, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)");
pbxProject.AddBuildProperty(frameworkTargetGuid, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)");
pbxProject.SetBuildProperty(frameworkTargetGuid, "LD_RUNPATH_SEARCH_PATHS", "/usr/lib/swift");
pbxProject.AddBuildProperty(frameworkTargetGuid, "LD_RUNPATH_SEARCH_PATHS", "$(inherited)");
pbxProject.AddBuildProperty(frameworkTargetGuid, "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks");
pbxProject.AddBuildProperty(frameworkTargetGuid, "LD_RUNPATH_SEARCH_PATHS", "@loader_path/Frameworks");
pbxProject.AddBuildProperty(frameworkTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "NO");
Manual handling is also possible
If you don't set up an automation script, you can open Xcode after each build and apply the values above manually with no functional issue. However, if you build often, automation is recommended.
6) iOS — Changes when applying SGSIAP2 (Unity-specific)
Unlike iOS Native, Unity adds a step to check an SDK-internal file (IAPNativeInterface.mm).
- Change the import at the top of the
Assets/Stove/Plugins/iOS/IAPNativeInterface.mmfileobjectivec#import <SGSIAP2/SGSIAP2.h> // before: #import <SGSIAP/SGSIAP.h> - Change the Podfile —
pod 'SGSIAP2', '2.9.0' - Verify the
[SGSIAP prepareTransactionListener]call at the very bottom of thestove_iap_setListenerfunction- In Unity Plugin 2.8.2 or higher, the code is included internally. If it is missing, payment attempts fail silently, so we recommend checking directly.
objectivecvoid stove_iap_setListener(const char *identifier) { NSString *nsIdentifier = StoveSDKMakeNSString(identifier); // ... existing code ... [SGSIAP prepareTransactionListener]; // ⚠️ Payment fails if missing }
7) Notification Service Extension (when using rich push)
To use images and actions in iOS push, you must add an NSE target and include the SGSPushExtension Pod as a dependency.
- Add the NSE target to the Podfile (see iOS → Podfile above)
- Create the target via Xcode → File → New → Target → "Notification Service Extension"
The NSE target's Build Settings — actual Xcode-version-branch code:
pbxProject.AddBuildProperty(notificationServiceTarget, "LIBRARY_SEARCH_PATHS", "$(SDKROOT)/usr/lib/swift");
pbxProject.AddBuildProperty(notificationServiceTarget, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)");
pbxProject.AddBuildProperty(notificationServiceTarget, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)");
pbxProject.SetBuildProperty(notificationServiceTarget, "LD_RUNPATH_SEARCH_PATHS", "/usr/lib/swift");
pbxProject.AddBuildProperty(notificationServiceTarget, "LD_RUNPATH_SEARCH_PATHS", "$(inherited)");
pbxProject.AddBuildProperty(notificationServiceTarget, "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks");
pbxProject.AddBuildProperty(notificationServiceTarget, "LD_RUNPATH_SEARCH_PATHS", "@executable_path/../../Frameworks");
pbxProject.AddBuildProperty(notificationServiceTarget, "LD_RUNPATH_SEARCH_PATHS", "@loader_path/Frameworks");
Unreal
The basics are: placing the Plugins folder + Project.build.cs dependencies + injecting Android Gradle dependencies via UPL (GamePlugin.xml) + disabling Online Subsystem GooglePlay. If you need iOS Capabilities (keychain, app group) or LSSupportsOpeningDocumentsInPlace (for Naver login), a custom engine build environment is additionally required. (Unreal 5.44 or higher)
1) Place and enable the plugin
- Copy the downloaded STOVE module into the project's
Pluginsfolder - Enable it in the
.uprojector via the Edit → Plugins menu
2) Project.build.cs — module dependencies
using System.IO;
public class Game : ModuleRules
{
public Game(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[] {
"SGS_Base", "SGS_Log",
"SGS_Auth", "SGS_AuthUI",
"SGS_Push", "SGS_View",
"SGS_IAP", // or "SGS_IAP_StoreKit2"
"SGS_GamingServices"
});
}
}
3) Android setup
Pin the SDK Manager versions
- Install SDK Platform 34
- Install SDK Tools 33.0.3 (remove or uncheck higher versions)
Gradle 7.5 setting — Engine/Build/Android/Java/gradle/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip
Disable Online Subsystem GooglePlay (required) — disable Unreal's built-in Online Subsystem GooglePlay plugin to prevent conflicts with the STOVE plugin's GooglePlay library.
Extra Manifest — Edit → Project Settings → Android → Advanced APK Packaging
<meta-data android:name="com.stove.environment" android:value="live" /> <!-- live / sandbox -->
<meta-data android:name="com.stove.auth.ui.sanction_type" android:value="1" /> <!-- optional -->
UPL GamePlugin.xml — the only channel for injecting Gradle dependencies in Unreal
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:android="http://schemas.android.com/apk/res/android">
<init>
<log text="Android init"/>
</init>
<buildGradleAdditions>
<insert>
dependencies {
implementation 'com.stove:base:2.9.0'
implementation 'com.stove:log:2.9.0'
implementation 'com.stove:auth:2.9.0'
implementation 'com.stove:auth-apple:2.9.0'
implementation 'com.stove:auth-facebook:2.9.0'
implementation 'com.stove:auth-google:2.9.0'
implementation 'com.stove:auth-naver:2.9.0'
implementation 'com.stove:auth-line:2.9.0'
implementation 'com.stove:auth-steam:2.9.0'
implementation 'com.stove:auth-ui:2.9.0'
implementation 'com.stove:push:2.9.0'
implementation 'com.stove:push-firebase:2.9.0'
implementation 'com.stove:view:2.9.0'
implementation 'com.stove:iap:2.9.0'
implementation 'com.stove:iap-google:2.9.0'
implementation 'com.stove:gamingservices:2.9.0'
}
</insert>
</buildGradleAdditions>
</root>
Link the UPL in Project.build.cs
public class Game : ModuleRules
{
public Game(ReadOnlyTargetRules Target) : base(Target)
{
// ...
if (Target.Platform == UnrealTargetPlatform.Android)
{
PrivateDependencyModuleNames.AddRange(new string[] { "Launch" });
string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add(
"AndroidPlugin",
Path.Combine(PluginPath, "GamePlugin.xml"));
}
}
}
If you omit this UPL, the STOVE SDK won't be included in the APK
In Unreal, you cannot edit build.gradle directly; dependencies can only be injected via UPL.
4) iOS setup — basics
Apply this to the Xcode project produced after the Unreal build. Since Xcode settings may reset on every build, automation via IPP or Build.cs post-processing is recommended. Items to handle:
- Get the iOS SDK Framework from the Git repository and place it in the Plugins directory
Info.plist—StoveEnvironment/LSApplicationQueriesSchemes=[mstove]/ URL Schemes / permission messages (see the iOS section above for concrete values)- Embedded Framework handling — see the table below for the
.framework/.bundlemapping each plugin uses - Set Embed & Sign in Build Phases → Embed Frameworks
5) Unreal plugin ↔ iOS SDK Framework mapping
This maps which framework / bundle each Unreal plugin uses. Refer to it when working on Embedded Frameworks.
| Plugin | SDK Framework | Resources |
|---|---|---|
| SGS_Base | SGSBase.framework, SGSGamingServices.framework | SGSBaseResources.bundle |
| SGS_Log | SGSLog.framework | SGSLogResources.bundle |
| SGS_Auth | SGSAuth.framework, SGSMemberAuth.framework | SGSAuthResources.bundle, SGSMemberAuthResources.bundle |
| SGS_AuthUI | SGSAuthUI.framework | SGSAuthUIResources.bundle |
| SGS_Auth_Facebook | SGSAuthFacebook.framework, FBAEMKit.framework, FBSDKCoreKit.framework, FBSDKCoreKit_Basics.framework, FBSDKLoginKit.framework | SGSAuthFacebookResources.bundle |
| SGS_Auth_Google | SGSAuthGoogle.framework, GoogleSignIn.framework, AppAuth.framework, GTMAppAuth.framework, GTMSessionFetcher.framework | SGSAuthGoogleResources.bundle |
| SGS_Auth_Apple | SGSAuthApple.framework | SGSAuthAppleResources.bundle |
| SGS_Auth_Naver | SGSAuthNaver.framework, NaverThirdPartyLogin.framework | SGSAuthNaverResources.bundle |
| SGS_Auth_Line | SGSAuthLine.framework, LineSDK.framework | SGSAuthLineResources.bundle |
| SGS_Auth_Twitter | SGSAuthTwitter.framework | SGSAuthTwitterResources.bundle |
| SGS_Push | SGSPush.framework, SGSPushExtension.framework | — |
| SGS_View | SGSView.framework | SGSViewResources.bundle |
| SGS_IAP / SGS_IAP_StoreKit2 | SGSIAP.framework / SGSIAP2.framework | — |
6) iOS — Changes when applying SGSIAP2 (Unreal-specific)
Unlike iOS Native/Unity, Unreal replaces the entire plugin. The API call code (SGSIAPProduct, SGSIAPOptional, etc.) keeps the same @objc names, so no game code changes are needed.
- Download the
SGS_IAP_StoreKit2(iOS)item from the SDK download page - Replace the project's
Plugins/SGS_IAPdirectory with the downloaded plugin - Rebuild the Unreal project
Internal handling such as the prepareTransactionListener call is included in the new plugin, so no extra work is needed in the game.
7) iOS — Capabilities setup (custom engine build required)
The default Unreal 5.44 engine supports only Push Notifications / Sign in with Apple / In-App Purchase as Capabilities. To add the Keychain Sharing / App Group required by the STOVE SDK, you need a custom engine built from the full Unreal Engine source on GitHub.
Only applicable in a custom engine build environment
ㅁ Link your Epic Games account with your GitHub account and get the full source from Unreal Engine GitHub
ㅁ See the Unreal Engine GitHub Download Guide for the build procedure
Add the STOVE keychain settings to the WriteEntitlements() function in the custom engine's Engine/Source/Programs/UnrealBuildTool/Platform/IOS/IOSExports.cs.
// Add inside the IOSExports.cs > WriteEntitlements() function
Text.AppendLine("\t<key>keychain-access-groups</key>");
Text.AppendLine("\t<array><string>$(AppIdentifierPrefix)com.stove.globaldata</string></array>");
Games that don't require keychain/app group can use the default engine
For simple integration cases that don't use token persistence or NSE (push extension), you can build with the default engine. Check applicability with the publishing technical contact.
8) iOS — Using LSSupportsOpeningDocumentsInPlace (when using Naver login, custom engine build required)
Adding Naver login requires handling both the deprecated OpenURL method and the new method simultaneously, which requires engine source modification. This work is also only possible in a custom engine build environment.
Background: the Unreal engine uses iOS's deprecated OpenURL function, but the Naver SDK uses the new function form. To support both forms, you must add an application:openURL:options: method branch to IOSAppDelegate.
Files to modify:
Please add the code from add - start to add - end in the example code below
Engine/Source/Runtime/ApplicationCore/Public/IOS/IOSAppDelegate.h
DECLARE_MULTICAST_DELEGATE_FourParams(FOnOpenURL, UIApplication*, NSURL*, NSString*, id);
static FOnOpenURL OnOpenURL;
// add - start
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnOpenURLwithOptions, UIApplication*, NSURL*, NSDictionary* );
static FOnOpenURLwithOptions OnOpenURLwithOptions;
// add - end
// -------------------------------------------//
// parameters passed from openURL
@property (nonatomic, retain) NSMutableArray* savedOpenUrlParameters;
// add - start
@property (nonatomic, retain) NSMutableArray* savedOpenUrlWithOptionsParameters;
// add - end
Engine/Source/Runtime/ApplicationCore/Private/IOS/IOSAppDelegate.cpp
FIOSCoreDelegates::FOnOpenURL FIOSCoreDelegates::OnOpenURL;
// add - start
FIOSCoreDelegates::FOnOpenURLwithOptions FIOSCoreDelegates::OnOpenURLwithOptions;
// add - end
FIOSCoreDelegates::FOnWillResignActive FIOSCoreDelegates::OnWillResignActive;
FIOSCoreDelegates::FOnDidBecomeActive FIOSCoreDelegates::OnDidBecomeActive;
TArray<FIOSCoreDelegates::FFilterDelegateAndHandle> FIOSCoreDelegates::PushNotificationFilters;
// ----------------------------------------- //
@synthesize AccessibilityCacheTimer;
#endif
@synthesize savedOpenUrlParameters;
// add - start
@synthesize savedOpenUrlWithOptionsParameters;
// add - end
@synthesize BackgroundSessionEventCompleteDelegate;
// ----------------------------------------- //
GShowSplashScreen = false;
}, TStatId(), NULL, ENamedThreads::ActualRenderingThread);
}
// add - start
for (NSDictionary* openUrlParameter in self.savedOpenUrlWithOptionsParameters)
{
UIApplication* application = [openUrlParameter valueForKey : @"application"];
NSURL* url = [openUrlParameter valueForKey : @"url"];
NSDictionary<NSString*, id> * options = [openUrlParameter valueForKey : @"options"];
FIOSCoreDelegates::OnOpenURLwithOptions.Broadcast(application, url, options);
}
self.savedOpenUrlWithOptionsParameters = nil; // clear after saved openurl delegate running
// add - end
for (NSDictionary* openUrlParameter in self.savedOpenUrlParameters)
{
UIApplication* application = [openUrlParameter valueForKey : @"application"];
// ----------------------------------------- //
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
// save launch options
self.launchOptions = launchOptions;
#if PLATFORM_TVOS
self.bDeviceInPortraitMode = false;
#else
// use the status bar orientation to properly determine landscape vs portrait
self.bDeviceInPortraitMode = UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]);
printf("========= This app is in %s mode\n", self.bDeviceInPortraitMode ? "PORTRAIT" : "LANDSCAPE");
#endif
// check OS version to make sure we have the API
OSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (!FPlatformMisc::IsDebuggerPresent() || GAlwaysReportCrash)
{
// InstallSignalHandlers();
}
self.savedOpenUrlParameters = [[NSMutableArray alloc] init];
// add - start
self.savedOpenUrlWithOptionsParameters = [[NSMutableArray alloc] init];
// add - end
self.PeakMemoryTimer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(RecordPeakMemory) userInfo:nil repeats:YES];
#if !BUILD_EMBEDDED_APP
// ----------------------------------------- //
return YES;
}
// add - start
//### use option
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
#if !NO_LOGGING
NSLog(@"%s", "IOSAppDelegate openURL options\n");
#endif
NSString* EncdodedURLString = [url absoluteString];
NSString* URLString = [EncdodedURLString stringByRemovingPercentEncoding];
FString CommandLineParameters(URLString);
// Strip the "URL" part of the URL before treating this like args. It comes in looking like so:
// "MyGame://arg1 arg2 arg3 ..."
// So, we're going to make it look like:
// "arg1 arg2 arg3 ..."
int32 URLTerminator = CommandLineParameters.Find( TEXT("://"), ESearchCase::CaseSensitive);
if ( URLTerminator > -1 )
{
CommandLineParameters.RightChopInline(URLTerminator + 3, false);
}
FIOSCommandLineHelper::InitCommandArgs(CommandLineParameters);
self.bCommandLineReady = true;
[self.CommandLineParseTimer invalidate];
self.CommandLineParseTimer = nil;
// Save openurl infomation before engine initialize.
// When engine is done ready, running like previous. ( if OnOpenUrl is bound on game source. )
if (bEngineInit)
{
FIOSCoreDelegates::OnOpenURLwithOptions.Broadcast(app, url, options);
}
else
{
#if !NO_LOGGING
NSLog(@"%s", "Before Engine Init receive IOSAppDelegate openURL\n");
#endif
NSDictionary* openUrlParameter = [NSDictionary dictionaryWithObjectsAndKeys :
app , @"application",
url, @"url",
options, @"options",
nil];
[savedOpenUrlWithOptionsParameters addObject : openUrlParameter];
}
return YES;
}
// add - end
FCriticalSection RenderSuspend;
- (void)applicationWillResignActive:(UIApplication *)application
{
If you need the concrete patch code
Since the modification points differ by engine version, please request the detailed patch snippet from the STOVE publishing technical contact.
Android
Set up Gradle dependencies + AndroidManifest.xml metadata + (when using SDK 2.8.0 or higher) the option that forces Android 7.x support.
1) Gradle dependencies (app/build.gradle)
Register the STOVE Maven repository and add the required modules as dependencies.
buildscript {
ext.kotlin_version = '1.8.0'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
dataBinding { enabled = true }
}
repositories {
google()
maven {
// SDK 2.6.1 or higher — current repository
url "https://externalnexus.iam0.com/repository/mvp"
allowInsecureProtocol = true // Required for Android Gradle Plugin 7.0+
}
mavenCentral()
}
dependencies {
// Core
implementation 'com.stove:base:2.9.0'
implementation 'com.stove:log:2.9.0'
// Authentication
implementation 'com.stove:auth:2.9.0'
implementation 'com.stove:auth-apple:2.9.0'
implementation 'com.stove:auth-facebook:2.9.0'
implementation 'com.stove:auth-google:2.9.0'
implementation 'com.stove:auth-naver:2.9.0'
implementation 'com.stove:auth-line:2.9.0'
implementation 'com.stove:auth-steam:2.9.0'
implementation 'com.stove:auth-ui:2.9.0'
// Others
implementation 'com.stove:push:2.9.0'
implementation 'com.stove:push-firebase:2.9.0'
implementation 'com.stove:view:2.9.0'
implementation 'com.stove:iap:2.9.0'
implementation 'com.stove:iap-google:2.9.0'
implementation 'com.stove:gamingservices:2.9.0'
}
If you are using a version below SDK 2.6.1
The repository location differs: http://e-nexus.iam0.net/content/repositories/mvp/
2) AndroidManifest.xml — STOVE environment setting (required)
Without the com.stove.environment metadata, AuthConfigurationError (30001) occurs during SDK initialization.
<application>
<!-- Environment: live / sandbox (test) -->
<meta-data
android:name="com.stove.environment"
android:value="live" />
</application>
3) (Optional) AuthUI options
Add the metadata below if needed. If unset, it operates with the default value in parentheses.
<application>
<!-- Behavior when the sanction screen closes: if unset, exit the app (default); if set to 1, handle via callback -->
<meta-data android:name="com.stove.auth.ui.sanction_type" android:value="1" />
<!-- Terms screen color theme: orange (default) / black / LostarkM (AuthUI 2.6.2+) -->
<meta-data android:name="com.stove.auth.ui.theme" android:value="orange" />
<!-- Light/dark mode: 0=system (default) / 1=light / 2=dark -->
<meta-data android:name="com.stove.auth.ui.appearance_mode" android:value="1" />
<!-- Terms screen size: full (default) / small -->
<meta-data android:name="com.stove.auth.ui.display_size" android:value="small" />
<!-- Push heads-up notification: false (default) / true (AuthUI 2.9.0+) -->
<meta-data android:name="com.stove.push.heads_up_notification_enable" android:value="true" />
</application>
4) SDK 2.8.0 or higher — Android 7.x support (required)
You must pin play-services-ads-identifier to 18.0.1 to avoid runtime crashes on Android 7.x devices.
configurations.all {
resolutionStrategy {
force 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
}
5) Check debug logs
During game development and debugging, you can view SDK operation logs in logcat with the stove-sdk tag.
adb shell setprop log.tag.stove-sdk VERBOSE
iOS
You must add the STOVE SDK via CocoaPods and configure Info.plist / entitlements / Xcode Build Settings / AppDelegate for it to work correctly.
1) Prerequisite — register the Specs repository (once)
The STOVE SDK Pod is hosted in an internal repo. After signing up for GitLab, add the repository to your local CocoaPods.
# 1) Sign up on the web at http://stove-developers-gitlab.sginfra.net (no separate approval process)
# 2) Add the repo in the terminal (enter username/password once)
pod repo add Specs https://stove-developers-gitlab.sginfra.net/stove-sdk/Specs.git
Can't access GitLab?
Please contact the publishing technical contact.
2) Podfile
Replace {ProjectTargetName} in the example below with your Xcode project's main target name.
source 'http://stove-developers-gitlab.sginfra.net/stove-sdk/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'
target '{ProjectTargetName}' do
pod 'SGSBase', '2.9.0'
pod 'SGSLog', '2.9.0'
pod 'SGSAuth', '2.9.0'
pod 'SGSAuthApple', '2.9.0'
pod 'SGSAuthFacebook', '2.9.0'
pod 'SGSAuthGoogle', '2.9.0'
pod 'SGSAuthNaver', '2.9.0'
pod 'SGSAuthLine', '2.9.0'
pod 'SGSAuthSteam', '2.9.0'
pod 'SGSAuthUI', '2.9.0'
pod 'SGSPush', '2.9.0'
pod 'SGSView', '2.9.0'
pod 'SGSGamingServices', '2.9.0'
# In-app purchase — choose only one below (cannot be used together)
pod 'SGSIAP', '2.9.0' # StoreKit 1 based
# pod 'SGSIAP2', '2.9.0' # StoreKit 2 based
end
# Push extension (Notification Service Extension) — separate target
target 'NotificationServiceExtension' do
pod 'SGSPushExtension', '2.9.0'
end
Build with the .xcworkspace generated after install/update.
pod install
# or
pod update
3) (Optional) Manual Framework download
In environments where CocoaPods cannot be used, select items by tag name on the SDK Download and Installation page, download them directly, and add them to your Xcode project.
4) SGSIAP vs SGSIAP2 (in-app purchase module)
The two modules cannot be used together. Enable only one in the Podfile.
| Item | SGSIAP (StoreKit 1) | SGSIAP2 (StoreKit 2) |
|---|---|---|
| Firebase Analytics auto-collection | Supported | Not supported — listener-based manual integration required |
| Manual sending tools such as Singular | No change | No change |
3 required changes when migrating SGSIAP → SGSIAP2:
// ① Change the import — all files that import SGSIAP
#import <SGSIAP2/SGSIAP2.h> // before: #import <SGSIAP/SGSIAP.h>
// ② Podfile — pod 'SGSIAP2', '2.9.0' (replace from SGSIAP)
// ③ Add the prepareTransactionListener call — if missing, payment attempts immediately fail via errorListener
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSNotification.SGSPurchasesUpdatedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updatedPurchasesNotification:)
name:NSNotification.SGSPurchasesUpdatedNotification object:nil];
[SGSIAP prepareTransactionListener]; // ⚠️ Additionally required in SGSIAP2
When to call
Call it right after registering the payment notification observer. If not called, payment attempts fail silently.
5) Info.plist
<key>StoveEnvironment</key>
<string>live</string> <!-- live / sandbox -->
<!-- Required for Base 2.2.0+ -->
<key>NSUserTrackingUsageDescription</key>
<string>Required for log collection</string>
<!-- AuthUI 2.3.0+ optional: 1=handle via callback when the sanction screen closes (default: exit app) -->
<key>StoveSanctionType</key>
<integer>1</integer>
<!-- Permission messages when using community/customer support (adjust the wording to fit your game) -->
<key>NSCameraUsageDescription</key>
<string>Used to take photos/videos for community posts and inquiries</string>
<key>NSMicrophoneUsageDescription</key>
<string>Used to record videos that include audio</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to attach existing photos/videos</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Used to save photos/videos to the device</string>
<!-- STOVE app-to-app authentication — authentication fails if unset -->
<key>LSApplicationQueriesSchemes</key>
<array>
<string>mstove</string>
</array>
<!-- URL Schemes — used for returning from external apps (Google/Apple/Naver/Line, etc.) -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
6) Xcode Capabilities (.entitlements)
You can edit the .entitlements file directly, or toggle it in the UI via Xcode → Signing & Capabilities → + Capability for the same result.
<!-- When using APNS push -->
<key>aps-environment</key>
<string>production</string>
<!-- Required by StoveSDK — token storage fails if unset -->
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.stove.globaldata</string>
</array>
<!-- When using Apple login -->
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<!-- When using the push extension (Notification Service Extension) -->
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.stove.sdk</string>
</array>
7) Build Settings — Search Paths
Configure it by branching on the Xcode version. If unset, Swift runtime link or dylib not found errors occur.
Library Search Paths — Xcode → Build Settings → Search Paths
$(SDKROOT)/usr/lib/swift
$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)
$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
Additional path for Xcode 26.0.x
There is a bug where $(TOOLCHAIN_DIR) resolves incorrectly to the Metal cryptex path (fixed in 26.2). On 26.0.x, add the path below.$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/$(PLATFORM_NAME)
Runpath Search Paths — Xcode → Build Settings → Linking (common to Xcode 16/26; add strictly in the order below)
/usr/lib/swift
$(inherited)
@executable_path/Frameworks
@loader_path/Frameworks
8) AppDelegate — Provider login delegation (required)
To let the Google/Apple/Facebook/Naver/Line OAuth callbacks reach the SDK, you must delegate openURL. If unset, external login itself fails.
#import <SGSAuth/SGSAuth.h>
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
return [SGSApplicationDelegate application:app openURL:url options:options];
}
PC SDK
PC builds use a separate package from the Mobile SDK. Follow the procedure that matches your game's engine among the 3 environments below.
PCSDK3 officially supports the Windows 64-bit environment.
ㅁ If you need 32-bit or Mono (Unity) support, please contact STOVE technical support.
ㅁ Module dependencies: all modules require BaseSDK first. If you use IAPSDK/ViewSDK, WebView2Loader.dll must be included as well.
- Native C/C++ build setup (Visual Studio)
- Create a
StovePCSDK3directory in the solution directory and copy theInclude/Lib/Dllfolders from the downloaded package. - Specify the paths in the project properties as follows.
- Configuration Properties > C/C++ > General > Additional Include Directories:
$(SolutionDir)StovePCSDK3\Include - Configuration Properties > Linker > General > Additional Library Directories:
$(SolutionDir)StovePCSDK3\Lib - Configuration Properties > Linker > Input > Additional Dependencies:
*.libfor each module used (e.g.,BaseSDK.lib)
- Configuration Properties > C/C++ > General > Additional Include Directories:
- Copy the
*.dllof the modules you use into the game build output folder. - Include the header in your source code with
#include "BaseSDK.h".
- Create a
- Unity build setup
- Create
ManagedandNativedirectories underAssets/Plugins/STOVEPCSDK3. - From the downloaded package's
x86_64folder, copy the Managed plugins (*_NET.dll) and Native plugins (*.dll) into the directories above, respectively.- Native and Managed plugins form a pair, so include them together. (e.g., using only Base →
BaseSDK.dll+BaseSDK_NET.dll) - When using IAP/View, copy
WebView2Loader.dllas well.
- Native and Managed plugins form a pair, so include them together. (e.g., using only Base →
- In each dll's Inspector → Platform settings, select
x86_64(orx64) and click Apply. - Player Settings → Configuration → Api Compatibility Level: .NET 4.x
- At build time, set Architecture to
x86_64to match the system. (The Unity editor supports only x64) - Add the per-module namespace in code, such as
using static Stove.PCSDK.Base;.
!infoA unitypackage-based delivery is planned for the future.
ㅁ Currently only the manual method of placing dlls directly is supported, but from the next version we plan to provide a simpler.unitypackageimport method.
ㅁ We will announce the timing in the SDK release notes. - Create
- Unreal build setup
- Place the
Include/Lib/Dllfolders from the downloaded package into theThirdParty/StovePCSDKdirectory at the project root. - Also copy the module dlls into
Binaries/Win64. (IncludeWebView2Loader.dllwhen using IAP/View) - Add PublicIncludePaths / PublicAdditionalLibraries / RuntimeDependencies to the module's
*.Build.csfile as shown below.
csstring ThirdPartyPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty")); string StovePCSDKPath = Path.Combine(ThirdPartyPath, "StovePCSDK"); PublicIncludePaths.Add(Path.Combine(StovePCSDKPath, "Include")); string[] SDKNameList = { "BaseSDK", "IAPSDK", "ViewSDK" }; foreach(string SDKName in SDKNameList) { PublicAdditionalLibraries.Add(Path.Combine(StovePCSDKPath, "Lib", "x64", SDKName + ".lib")); RuntimeDependencies.Add( Path.Combine("$(BinaryOutputDir)", SDKName + ".dll"), Path.Combine(StovePCSDKPath, "Dll", "x64", SDKName + ".dll")); }- Include the header in your source code with
#include "BaseSDK.h".
- Place the
For the PCSDK3 module initialization and cleanup flow, follow the SDK Integration guide.
ㅁ Initialize the Base SDK first, then other modules; on cleanup, proceed in reverse order.
ㅁ Logs accumulate per module at C:\Users\{username}\AppData\Local\STOVEPCSDK3{Env}\logs\{GameID}.
SDK Config Settings
SDK Config is a system for registering and managing the configuration values required for SDK operation. It is provided in SDK v2.x and is registered and managed through Partners.
SDK Config characteristics
- Manages SDK default settings, UI display options, and platform URL settings.
- You can change service settings without changing the client or server.
- Settings can be made per country and per market (by package name), allowing flexible regional operation.
SDK init fails if SDK Config is not registered
ㅁ SDK Config must be registered per package and per client version. For unregistered versions, SDK init fails and the game cannot be accessed.
ㅁ Please perform the Config setup together when updating versions as well.
Where to register
Register and manage it in [Partners > GM > SDK Config Settings]. Separate registration is required per environment.
| Environment | Access path |
|---|---|
| Sandbox | partners.gate8.com > GM > SDK Config Settings |
| Live | partners.onstove.com > GM > SDK Config Settings |
Key registration items
| Item | Required? | Description |
|---|---|---|
| Package / client version | Required | Config registered per package name + client version |
| App ID / Client ID | Required | The key value by which the STOVE platform identifies the game |
| Default policy settings | Required | Access-country GDS settings, terms policy, identity-verification policy, etc. |
| Per-feature module settings | Optional | Options for each feature used, such as popup, push, in-app purchase, character, and device registration |
| UI / display options | Optional | Login UI Provider display order, terms-agreement UI options, etc. |
iOS Unity UISceneDelegate Temporary Workaround
From certain editor versions, Unity was updated to support the UIScene lifecycle (SceneDelegate) by default for iOS builds. As a result, when generating and building the Xcode project, the UIApplicationSceneManifest setting is automatically inserted into Info.plist.
The STOVE SDK (iOS) operates based on AppDelegate lifecycle callbacks. If UIApplicationSceneManifest exists in Info.plist, iOS calls SceneDelegate first and some AppDelegate callbacks are not called, so some SDK features such as social login and Push do not work correctly.
Applies to
This workaround is only needed if you are using the versions below or higher.
| Unity version line | Affected version |
|---|---|
| Unity 6.5 | 6000.5.0a3 or higher |
| Unity 6.4 | 6000.4.0b8 or higher |
| Unity 6.3 LTS | 6000.3.8f1 or higher |
| Unity 6.0 LTS | 6000.0.68f1 or higher |
| Unity 2022 xLTS | 2022.3.72f1 or higher |
Impact scope
If the UIApplicationSceneManifest setting remains in Info.plist, problems occur in the features below.
| Area | Related AppDelegate callback | Symptom |
|---|---|---|
| Social login (Auth) | application(_:open:options:) | The SDK cannot receive the redirect URL returning to the app after 3rd-party login (Google, Facebook, Naver, LINE, etc.), so login is not completed. |
Why can't SceneDelegate replace it?
ㅁ SceneDelegate (UIWindowSceneDelegate) does not have the callback above.
ㅁ When iOS is configured to use SceneDelegate, the app-wide AppDelegate URL-handling and Push callbacks are not called.
How to check
Check whether the setting below is applied to your project.
- Open the
Info.plistfile in Xcode - Check whether the following keys exist —
Application Scene Manifest(raw key:UIApplicationSceneManifest), and its sub-itemScene Configuration(raw key:UISceneConfigurations) - To check in source-code form, open Info.plist via right-click → Open As → Source Code and look for an entry similar to the one below
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict/>
</dict>
How to fix
Delete the UIApplicationSceneManifest key (and its sub-items such as UISceneConfigurations) from Info.plist. After deletion, iOS uses the AppDelegate lifecycle again and the SDK works correctly.
It may be re-inserted automatically at build time
ㅁ In Unity projects, this setting may be re-inserted automatically every build (Xcode project regeneration).
ㅁ We recommend re-checking Info.plist after each build, or automatically removing the key with a build post-processing script (PostProcessBuild).
SceneDelegate support planned
- Under Apple's platform policy, SceneDelegate (UIScene lifecycle) support is optional through iOS 26 but is planned to become mandatory from iOS 27.
- The STOVE SDK plans to support the SceneDelegate environment before the official iOS 27 release. We will provide further guidance once support is complete. Until then, please apply the workaround above.
Reference
- Unity Discussions — Apple: Update your Editor to receive UIScene lifecycle support
- Apple Developer — TN3187: Migrating to the UIKit scene-based life cycle
iOS Firebase Analytics Purchase Event Integration
This is how to manually integrate purchase events into Firebase Analytics in games using SGSIAP2. It targets the iOS 15 or higher + StoreKit 2 environment.
Overview
- In the iOS StoreKit 2 environment, Firebase Analytics' automatic purchase collection (
event_origin = auto) no longer works. - Therefore, you must call
Analytics.logEvent("in_app_purchase", ...)directly inside the SGSIAP2 purchase listener (SGSPurchasesUpdatedNotification) callback. - The set of transmitted parameters is compatible with the BigQuery columns that StoreKit 1 previously loaded automatically.
iOS only — wrap Android with a platform guard
ㅁ On Android, automatic purchase event collection is currently supported. If a Firebase Android SDK supporting manual collection is later released and applied, it may be double-counted with the auto-collected data.
ㅁ In cross-platform engines (Unity, Unreal), wrap it with an iOS platform guard as in the example code below.
Note — Firebase guidance
Starting from Google Analytics for Firebase iOS SDK version 12.5.0, in_app_purchase events will no longer be reserved. Manually logged in_app_purchase events (via SDK or Measurement Protocol) will be counted in addition to those automatically collected by the SDK.
Android will follow in the coming months.
Minimum Firebase SDK versions
These are the versions that support manual sending of the reserved event in_app_purchase in Firebase Analytics.
| Platform | Minimum version |
|---|---|
| iOS Native (CocoaPods) | 12.5.0 or higher |
| Unity | 13.6.0 or higher |
| C++ (Cocos2d-x, etc.) | 13.3.0 or higher |
Firebase official docs (must read)
ㅁ Please also review the Firebase iOS in-app purchase measurement doc. Firebase iOS In-App Purchase Measurement
Transmitted parameters — required
These are the parameters to fill when calling logEvent("in_app_purchase", ...) in the purchase listener callback. Send them with the keys, types, and units exactly as in the table below. They are the same form as the columns StoreKit 1 previously auto-collected.
| Firebase key | Send type | Example send value | product object field | BigQuery stored value |
|---|---|---|---|---|
| product_id | string | "item_001" | product.productIdentifier | Same |
| product_name | string | "1000-yen product" | product.localizedTitle | Same |
| currency | string | "USD" | product.priceCurrencyCode | Same |
| price | double | 0.99 | product.priceAmountMicros / 1_000_000.0 | 990000 (Firebase backend multiplies by 1,000,000) |
| value | double | 0.99 | product.priceAmountMicros / 1_000_000.0 | 990000 (Firebase backend multiplies by 1,000,000) |
| quantity | long | 1 | Fixed (SGSIAP2 is single-item payment) | 1 |
| validated | long | 1 | Fixed (the listener is only called on successful validation) | 1 |
Unit caution (important)
ㅁ For the reserved event in_app_purchase, the Firebase backend automatically multiplies value and price by 1,000,000 and loads them into BigQuery (micros integer). So you must send them as a real currency-unit Double (e.g., $0.99 → 0.99) to match the 990000 value of the previous auto-send format.
ㅁ If you send the priceAmountMicros integer (990000) as-is, ×1,000,000 is applied once more and it is over-loaded as 990000000000. It "appears to go in" without a firebase_error, but the revenue amount is distorted by a factor of a million, so always send it in Double units.
No need to send — auto-assigned by Firebase
- System parameters such as session and screen info are auto-assigned by the Firebase SDK, so do not include them in the send code.
- Always keep the event name as
in_app_purchase. - We recommend not adding custom parameters beyond the required ones (
content_id,order_id,customer_user_id, etc.) to thein_app_purchaseevent. If you need your own analytics data, send it separately under a different event name (e.g.,stove_purchase_detail).
SGSIAP2 listener payload reference (Product)
Call logEvent only when the listener callback's result is a success state. Use only the product field for the Firebase send.
| Field | Type | Use | Notes |
|---|---|---|---|
| productIdentifier | String | Firebase product_id |
— |
| localizedTitle | String | Firebase product_name |
— |
| priceAmountMicros | Double | Firebase price and value |
⚠️ Unit caution (÷1,000,000 needed) |
| priceCurrencyCode | String | Firebase currency |
— |
Integration code per engine
You only add the Firebase send block inside the purchase-success branch of an already-registered, operating SGSIAP2 purchase listener. You don't need to newly write the listener registration itself or the success/failure branch logic. The added flow is the same across all 3 engines — enter the purchase-success branch → extract values from the product field → build Firebase parameters → call Analytics.logEvent("in_app_purchase", params).
Scope of work
ㅁ In the code below, copy only the block between // --------------- START --------------- and // --------------- END --------------- into your existing listener success branch.
ㅁ The outer listener/condition branch is only shown to indicate where your existing code sits; there is no need to write or modify it.
Swift projects can also subscribe with the same NotificationCenter API. Add the block below inside the purchase-success branch of your existing SGSPurchasesUpdatedNotification observer callback.
#import <FirebaseAnalytics/FirebaseAnalytics.h>
#import <SGSIAP2/SGSIAP2.h>
- (void)onSGSPurchasesUpdated:(NSNotification *)notification
{
SGSResult *result = [notification.userInfo objectForKey:@"result"];
if ([result isSuccessful]) {
// Game's own purchase-success handling (item grant, UI update, etc.)
// ...
// --------------- START: Send Firebase purchase event ---------------
SGSIAPProduct *product = [notification.userInfo objectForKey:@"product"];
// Unit: since Firebase multiplies the reserved event's value/price by 1,000,000,
// send it as a real currency-unit Double
double priceAmount = product.priceAmountMicros / 1000000.0;
NSDictionary *params = @{
@"product_id": product.productIdentifier ?: @"",
@"product_name": product.localizedTitle ?: @"",
@"currency": product.priceCurrencyCode ?: @"",
@"price": @(priceAmount),
@"value": @(priceAmount),
@"quantity": @1,
@"validated": @1
};
[FIRAnalytics logEventWithName:@"in_app_purchase" parameters:params];
// --------------- END ---------------
}
}
📖 Firebase iOS event logging official doc: Log events
Supported engines summary
| Engine | Listener signature | Notes |
|---|---|---|
| iOS Native (Obj-C / Swift) | Observe SGSPurchasesUpdatedNotification via NotificationCenter | Call the Firebase iOS SDK directly |
| Unity | IAP.SetListener(Action |
Mind the Firebase Unity SDK ↔ iOS CocoaPods version mapping |
| Unreal (C++) | stove::IAP::SetListener(TFunction |
FString → UTF-8 conversion needed |
| Cocos2d-x / other C++ | Build an iOS native bridge directly | — |
Application checklist
- Update the Firebase SDK version
- iOS Native: CocoaPods
12.5.0or higher - Unity:
13.6.0or higher (internal iOS Pods12.6.0+ auto-installed) - C++ (Cocos2d-x, etc.): Firebase C++
13.3.0or higher (internal iOS Pods12.6.0+)
- iOS Native: CocoaPods
- Add the per-engine integration code example to your existing listener success branch
Verify purchase data integration
After integration, you can verify in Firebase DebugView that the in_app_purchase event is aggregated in real time with the intended parameters.
- Enable DebugView in a test build per the official guide
- Make a test purchase (Apple Sandbox / TestFlight)
- In the Firebase console Analytics → DebugView, verify the
in_app_purchaseevent fires and the required parameters appear
DebugView note
ㅁ DebugView lets you verify manually-sent events (event_origin = app) in real time.
ㆍ Firebase DebugView Official Guide
Reference
- Firebase iOS In-App Purchase Measurement — the document defining parameter specs, unit conversion, and aggregation behavior
- Per-engine event logging official docs — iOS · Unity · C++
- Firebase SDK Release Notes — iOS · Unity · C++
Module Composition
The STOVE SDK is provided modularized by feature. Add only the modules you need, matching the features your game uses.
Module categories
| Category | Module | Role |
|---|---|---|
| Base (required) | Base | SDK initialization, environment setup, common handling |
| Log | Log collection, SDK version info lookup | |
| Authentication | Auth | Login, sign-up, token management |
| AuthUI / AuthGoogle / AuthApple / AuthFacebook / AuthNaver / AuthLine / AuthSteam |
Integrated login UI and per-Provider authentication modules. Select only the Providers you use | |
| Notification / UI | Push | Receiving and handling push notifications |
| View | Webview-based UI such as popups, notices, and community | |
| Payment | IAP / IAPGoogle / IAPHuawei / IAPOneStore / IAP_StoreKit2(iOS) |
In-app purchase. Select only the market modules you use |
How to check module version info
ㅁ You can check the SDK module versions applied to the client in JSON form by calling Log.getSDKVersions().
ㅁ Use it for QA build verification, debugging, showing an in-game settings screen, etc. For details, see Feature Guides > Game Info.
External module info by version
- For external modules such as 3rd-party authentication Providers, push (Firebase), and payment (StoreKit2), the compatible external library version differs by SDK version.
- When adding an external module, check the SDK release notes for the external library version compatible with your STOVE SDK version.
Multi-platform Considerations
In a multi-platform game serving PC and mobile simultaneously, you must apply both platform SDKs. These are the additional points to check.
Applying the SDKs
- The PC and mobile SDKs are downloaded and applied separately
- Mobile build: STOVE Mobile SDK (Android / iOS)
- PC build: STOVE PC SDK (PCSDK3)
- Consistency of common identifiers
- The Game ID and App ID are used identically across the entire multi-platform game.
- Package names and bundle IDs differ per platform, but the STOVE identification keys must stay consistent.
- Environment synchronization
- The environments (Live/Sandbox) of the PC/mobile builds must match.
- A mismatched configuration during QA, such as PC = Sandbox and mobile = Live, leads to user-identification and payment-validation errors.
User identification
- MemberNo: the STOVE platform member identifier. The same member on PC/mobile uses the same MemberNo.
- GUID: the game character identifier. When sharing character info between PC/mobile in a multi-platform game, refer to the character integration guide
- Member type difference: mobile supports both registered members and guests, while PC supports only registered members (guest login is not available on PC)
Build branching recommendations
- Branch by build environment: separate PC/mobile SDK calls in client code with compile-time branches (
#if UNITY_ANDROID, etc.). - Abstract common business logic: for common flows such as authentication and payment, we recommend abstracting them behind an interface and separating them into per-platform implementations.