Skip to content
Stove
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


2) STOVE environment setup (Zone)

Separately from StoveEnvironment in the iOS Info.plist, Unity sets the environment directly in the editor Inspector.

  • Click Unity → StoveEdit Settings
  • Set the Zone item 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

gradle
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

properties
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

gradle
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

gradle
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

gradle
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.

kotlin
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+)

xml
<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.plist keys (StoveEnvironment / LSApplicationQueriesSchemes=[mstove] / URL Schemes / permission messages)
  • Merge entitlements (Capabilities keys)
  • Add Library / Runpath Search Paths (Xcode 16.x / 26 branch)
  • Insert the SGSApplicationDelegate openURL delegation code into AppDelegate.mm

Library / Runpath Search Paths — actual Xcode-version-branch code:

csharp
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).

  1. Change the import at the top of the Assets/Stove/Plugins/iOS/IAPNativeInterface.mm file
    objectivec
    #import <SGSIAP2/SGSIAP2.h>   // before: #import <SGSIAP/SGSIAP.h>
    
  2. Change the Podfile — pod 'SGSIAP2', '2.9.0'
  3. Verify the [SGSIAP prepareTransactionListener] call at the very bottom of the stove_iap_setListener function
    • 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.
    objectivec
    void 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:

csharp
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 Plugins folder
  • Enable it in the .uproject or via the EditPlugins menu

2) Project.build.cs — module dependencies

csharp
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

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 — EditProject SettingsAndroidAdvanced APK Packaging

xml
<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
<?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

csharp
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.plistStoveEnvironment / LSApplicationQueriesSchemes=[mstove] / URL Schemes / permission messages (see the iOS section above for concrete values)
  • Embedded Framework handling — see the table below for the .framework / .bundle mapping 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.

  1. Download the SGS_IAP_StoreKit2(iOS) item from the SDK download page
  2. Replace the project's Plugins/SGS_IAP directory with the downloaded plugin
  3. 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.

csharp
// 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

objectivec
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

objectivec
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.

gradle
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.

xml
<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.

xml
<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.

gradle
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.

bash
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.

bash
# 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.

ruby
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.

bash
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:

objectivec
// ① 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

xml
<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.

xml
<!-- 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

text
$(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)

text
/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.

objectivec
#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 StovePCSDK3 directory in the solution directory and copy the Include / Lib / Dll folders 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: *.lib for each module used (e.g., BaseSDK.lib)
    • Copy the *.dll of the modules you use into the game build output folder.
    • Include the header in your source code with #include "BaseSDK.h".

  • Unity build setup
    • Create Managed and Native directories under Assets/Plugins/STOVEPCSDK3.
    • From the downloaded package's x86_64 folder, 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.dll as well.
    • In each dll's Inspector → Platform settings, select x86_64 (or x64) and click Apply.
    • Player Settings → Configuration → Api Compatibility Level: .NET 4.x
    • At build time, set Architecture to x86_64 to 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 .unitypackage import method.
    ㅁ We will announce the timing in the SDK release notes.


  • Unreal build setup
    • Place the Include / Lib / Dll folders from the downloaded package into the ThirdParty/StovePCSDK directory at the project root.
    • Also copy the module dlls into Binaries/Win64. (Include WebView2Loader.dll when using IAP/View)
    • Add PublicIncludePaths / PublicAdditionalLibraries / RuntimeDependencies to the module's *.Build.cs file as shown below.
    cs
    string 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".

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.plist file in Xcode
  • Check whether the following keys exist — Application Scene Manifest (raw key: UIApplicationSceneManifest), and its sub-item Scene Configuration (raw key: UISceneConfigurations)
  • To check in source-code form, open Info.plist via right-clickOpen AsSource Code and look for an entry similar to the one below
xml
<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

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 the in_app_purchase event. 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.

objc
#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

  1. Update the Firebase SDK version
    • iOS Native: CocoaPods 12.5.0 or higher
    • Unity: 13.6.0 or higher (internal iOS Pods 12.6.0+ auto-installed)
    • C++ (Cocos2d-x, etc.): Firebase C++ 13.3.0 or higher (internal iOS Pods 12.6.0+)
  2. 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 AnalyticsDebugView, verify the in_app_purchase event 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

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.



Need to contact us directly? stove.developers@smilegate.com