Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion EOSIntegrationKit.uplugin
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
{
"Name": "EIKLoginMethods",
"Type": "Runtime",
"LoadingPhase": "Default",
"LoadingPhase": "PreLoadingScreen",
"PlatformAllowList": [
"Win64",
"Android",
Expand Down
10 changes: 10 additions & 0 deletions Source/EIKLoginMethods/EIKLoginMethods.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ public EIKLoginMethods(ReadOnlyTargetRules Target) : base(Target)
Console.WriteLine("PluginPath: " + PluginPath);
//AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(PluginPath, "GoogleOneTap_UPL.xml"));
}

PublicIncludePaths.AddRange(
new string[]
{
Path.Combine(ModuleDirectory, "Public"),
Path.Combine(ModuleDirectory, "Public/GooglePlayBilling")
}
);

PublicDependencyModuleNames.AddRange(
new string[]
{
Expand All @@ -33,6 +42,7 @@ public EIKLoginMethods(ReadOnlyTargetRules Target) : base(Target)
"OnlineSubsystemEIK",
"GoogleOneTapLibrary",
"GooglePlayGamesLibrary",
"GooglePlayBillingLibrary",
"Json",
"JsonUtilities"
}
Expand Down
1 change: 0 additions & 1 deletion Source/EIKLoginMethods/Private/EIKLoginMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

void FEIKLoginMethodsModule::StartupModule()
{

}

void FEIKLoginMethodsModule::ShutdownModule()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (C) 2025 Betide Studio. All Rights Reserved.
// Written by AvnishGameDev.

#include "GooglePlayBilling/AsyncNodes/GPB_AcknowledgePurchase.h"
#include "TimerManager.h"

#if GPB_SUPPORTED
#include "Android/Utils/AndroidJNIConvertor.h"
#endif

TWeakObjectPtr<UGPB_AcknowledgePurchase> UGPB_AcknowledgePurchase::StaticInstance;
FTimerHandle UGPB_AcknowledgePurchase::TimeoutTimerHandle;

UGPB_AcknowledgePurchase::UGPB_AcknowledgePurchase()
{
}

UGPB_AcknowledgePurchase* UGPB_AcknowledgePurchase::AcknowledgePurchase(const FString& PurchaseToken, UObject* WorldContextObject)
{
UGPB_AcknowledgePurchase* Node = NewObject<UGPB_AcknowledgePurchase>();
Node->PurchaseToken = PurchaseToken;
Node->World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
StaticInstance = Node;
return Node;
}

void UGPB_AcknowledgePurchase::Activate()
{
Super::Activate();

UGPB_AcknowledgePurchase::StaticInstance = this;

// Set up timeout
if (World.IsValid())
{
World->GetTimerManager().SetTimer(
TimeoutTimerHandle,
this,
&UGPB_AcknowledgePurchase::OnTimeout,
GPB_AsyncTimeoutSeconds, // Use global configurable timeout
false
);
}

#if GPB_SUPPORTED
INIT_JAVA_METHOD(AndroidThunkJava_GPBL_acknowledgePurchase, "(Ljava/lang/String;)V");
if (JNIEnv* JNIEnvPtr = FAndroidApplication::GetJavaEnv(true))
{
FJavaWrapper::CallVoidMethod(JNIEnvPtr, FJavaWrapper::GameActivityThis, AndroidThunkJava_GPBL_acknowledgePurchase,
AndroidJNIConvertor::GetJavaString(PurchaseToken));
}
#else
OnComplete.Broadcast(false, PurchaseToken, "ERROR: Google Play Billing Not Supported!");
SetReadyToDestroy();
#endif
}

void UGPB_AcknowledgePurchase::BeginDestroy()
{
// Clear timeout timer
if (World.IsValid())
{
World->GetTimerManager().ClearTimer(TimeoutTimerHandle);
}

UGPB_AcknowledgePurchase::StaticInstance = nullptr;
Super::BeginDestroy();
}

void UGPB_AcknowledgePurchase::OnTimeout()
{
if (StaticInstance.Get())
{
StaticInstance->OnComplete.Broadcast(false, StaticInstance->PurchaseToken, "Timeout! Check parameters and try again.");
StaticInstance->SetReadyToDestroy();
}
}

#if GPB_SUPPORTED
extern "C"
{
JNIEXPORT void JNICALL
Java_com_epicgames_unreal_GameActivity_nativeOnAcknowledgeResponse(
JNIEnv* Env,
jclass Clazz,
jboolean bSuccess,
jstring PurchaseToken,
jstring Error)
{
bool bSuccessCpp = (bool)bSuccess;
FString PurchaseTokenStr = AndroidJNIConvertor::FromJavaString(PurchaseToken);
FString ErrorStr = AndroidJNIConvertor::FromJavaString(Error);

AsyncTask(ENamedThreads::GameThread, [bSuccessCpp, PurchaseTokenStr, ErrorStr]()
{
if (UGPB_AcknowledgePurchase::StaticInstance.Get())
{
// Always clear timeout timer first
if (UGPB_AcknowledgePurchase::StaticInstance->World.IsValid())
{
UGPB_AcknowledgePurchase::StaticInstance->World->GetTimerManager().ClearTimer(UGPB_AcknowledgePurchase::TimeoutTimerHandle);
}
// Now broadcast and destroy
UGPB_AcknowledgePurchase::StaticInstance->OnComplete.Broadcast(bSuccessCpp, PurchaseTokenStr, ErrorStr);
UGPB_AcknowledgePurchase::StaticInstance->SetReadyToDestroy();
}
});
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (C) 2025 Betide Studio. All Rights Reserved.
// Written by AvnishGameDev.

#include "GooglePlayBilling/AsyncNodes/GPB_ConsumePurchase.h"
#include "TimerManager.h"

#if GPB_SUPPORTED
#include "Android/Utils/AndroidJNIConvertor.h"
#endif

TWeakObjectPtr<UGPB_ConsumePurchase> UGPB_ConsumePurchase::StaticInstance;
FTimerHandle UGPB_ConsumePurchase::TimeoutTimerHandle;

UGPB_ConsumePurchase::UGPB_ConsumePurchase()
{
}

UGPB_ConsumePurchase* UGPB_ConsumePurchase::ConsumePurchase(const FString& PurchaseToken, UObject* WorldContextObject)
{
UGPB_ConsumePurchase* Node = NewObject<UGPB_ConsumePurchase>();
Node->PurchaseToken = PurchaseToken;
Node->World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
StaticInstance = Node;
return Node;
}

void UGPB_ConsumePurchase::Activate()
{
Super::Activate();

UGPB_ConsumePurchase::StaticInstance = this;

// Set up timeout
if (World.IsValid())
{
World->GetTimerManager().SetTimer(
TimeoutTimerHandle,
this,
&UGPB_ConsumePurchase::OnTimeout,
GPB_AsyncTimeoutSeconds, // Use global configurable timeout
false
);
}

#if GPB_SUPPORTED
INIT_JAVA_METHOD(AndroidThunkJava_GPBL_consumePurchase, "(Ljava/lang/String;)V");
if (JNIEnv* JNIEnvPtr = FAndroidApplication::GetJavaEnv(true))
{
FJavaWrapper::CallVoidMethod(JNIEnvPtr, FJavaWrapper::GameActivityThis, AndroidThunkJava_GPBL_consumePurchase,
AndroidJNIConvertor::GetJavaString(PurchaseToken));
}
#else
OnComplete.Broadcast(false, PurchaseToken, "ERROR: Google Play Billing Not Supported!");
SetReadyToDestroy();
#endif
}

void UGPB_ConsumePurchase::BeginDestroy()
{
// Clear timeout timer
if (World.IsValid())
{
World->GetTimerManager().ClearTimer(TimeoutTimerHandle);
}

UGPB_ConsumePurchase::StaticInstance = nullptr;
Super::BeginDestroy();
}

void UGPB_ConsumePurchase::OnTimeout()
{
if (StaticInstance.Get())
{
StaticInstance->OnComplete.Broadcast(false, StaticInstance->PurchaseToken, "Timeout! Check parameters and try again.");
StaticInstance->SetReadyToDestroy();
}
}

#if GPB_SUPPORTED
extern "C"
{
JNIEXPORT void JNICALL
Java_com_epicgames_unreal_GameActivity_nativeOnConsumeResponse(
JNIEnv* Env,
jclass Clazz,
jboolean bSuccess,
jstring PurchaseToken,
jstring Error)
{
bool bSuccessCpp = (bool)bSuccess;
FString PurchaseTokenStr = AndroidJNIConvertor::FromJavaString(PurchaseToken);
FString ErrorStr = AndroidJNIConvertor::FromJavaString(Error);

AsyncTask(ENamedThreads::GameThread, [bSuccessCpp, PurchaseTokenStr, ErrorStr]()
{
if (UGPB_ConsumePurchase::StaticInstance.Get())
{
// Always clear timeout timer first
if (UGPB_ConsumePurchase::StaticInstance->World.IsValid())
{
UGPB_ConsumePurchase::StaticInstance->World->GetTimerManager().ClearTimer(UGPB_ConsumePurchase::TimeoutTimerHandle);
}
// Now broadcast and destroy
UGPB_ConsumePurchase::StaticInstance->OnComplete.Broadcast(bSuccessCpp, PurchaseTokenStr, ErrorStr);
UGPB_ConsumePurchase::StaticInstance->SetReadyToDestroy();
}
});
}
}
#endif
Loading