구글 로그인
구글 계정으로 로그인하는 API입니다.
URL 확인
이 API는 service-account.playnanoo.com 도메인을 사용합니다.
API 정보
- URL:
https://service-account.playnanoo.com/api/v20240401/google/signin - Method:
PUT - 인증 필요: 아니오
요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| linked_id | string | 필수 | 구글 ID 토큰 |
| platform | string | 필수 | 플랫폼 (예: "aos", "ios") - 자동 포함 |
| device_id | string | 필수 | 기기 고유 ID - 자동 포함 |
| device_model | string | 필수 | 기기 모델명 - 자동 포함 |
| device_os | string | 필수 | 기기 OS - 자동 포함 |
| device_language | string | 필수 | 기기 언어 (예: "KO", "EN") - 자동 포함 |
자동 포함되는 기기 정보
FPlayNANOOHelper::CreateRequestBody()를 사용하면 platform, device_id, device_model, device_os, device_language가 자동으로 포함됩니다.
응답 데이터
Token 정보
AccessToken: 액세스 토큰RefreshToken: 리프레시 토큰
Player 정보
UserUniqueID: 사용자 고유 IDOpenID: 오픈 IDNickname: 닉네임LinkedID: 연동 ID (구글 ID)LinkedType: 연동 타입 (google)PurchaseCount: 구매 횟수PurchaseCurrencyCode: 구매 통화 코드PurchaseTotalPrice: 총 구매 금액Country: 국가Timezone: 타임존Offset: 시간 오프셋JoinPeriod: 가입 기간
Unreal C++ 구현
헤더 파일 (GoogleSignin.h)
// GoogleSignin.h
#pragma once
#include "CoreMinimal.h"
#include "Json.h"
#include "JsonUtilities.h"
// 응답 콜백 델리게이트
DECLARE_DELEGATE_OneParam(FOnGoogleSigninSuccess, const FString&);
DECLARE_DELEGATE_OneParam(FOnGoogleSigninError, const FString&);
class YOURPROJECT_API FGoogleSignin
{
public:
// 토큰 응답 구조체
struct FTokenData
{
FString AccessToken;
FString RefreshToken;
void FromJson(TSharedPtr<FJsonObject> JsonObject)
{
JsonObject->TryGetStringField(TEXT("AccessToken"), AccessToken);
JsonObject->TryGetStringField(TEXT("RefreshToken"), RefreshToken);
}
};
// 플레이어 응답 구조체
struct FPlayerData
{
FString UserUniqueID;
FString OpenID;
FString Nickname;
FString LinkedID;
FString LinkedType;
int32 PurchaseCount;
FString PurchaseCurrencyCode;
double PurchaseTotalPrice;
FString PurchaseVoidedCount;
FString PurchaseVoidedCurrencyCode;
FString PurchaseVoidedTotalPrice;
FString Country;
FString Timezone;
int32 Offset;
int32 JoinPeriod;
void FromJson(TSharedPtr<FJsonObject> JsonObject)
{
JsonObject->TryGetStringField(TEXT("UserUniqueID"), UserUniqueID);
JsonObject->TryGetStringField(TEXT("OpenID"), OpenID);
JsonObject->TryGetStringField(TEXT("Nickname"), Nickname);
JsonObject->TryGetStringField(TEXT("LinkedID"), LinkedID);
JsonObject->TryGetStringField(TEXT("LinkedType"), LinkedType);
JsonObject->TryGetNumberField(TEXT("PurchaseCount"), PurchaseCount);
JsonObject->TryGetStringField(TEXT("PurchaseCurrencyCode"), PurchaseCurrencyCode);
JsonObject->TryGetNumberField(TEXT("PurchaseTotalPrice"), PurchaseTotalPrice);
JsonObject->TryGetStringField(TEXT("PurchaseVoidedCount"), PurchaseVoidedCount);
JsonObject->TryGetStringField(TEXT("PurchaseVoidedCurrencyCode"), PurchaseVoidedCurrencyCode);
JsonObject->TryGetStringField(TEXT("PurchaseVoidedTotalPrice"), PurchaseVoidedTotalPrice);
JsonObject->TryGetStringField(TEXT("Country"), Country);
JsonObject->TryGetStringField(TEXT("Timezone"), Timezone);
JsonObject->TryGetNumberField(TEXT("Offset"), Offset);
JsonObject->TryGetNumberField(TEXT("JoinPeriod"), JoinPeriod);
}
};
// 응답 구조체
struct FRes
{
FString ErrorCode;
FString Message;
FTokenData Token;
FPlayerData Player;
bool FromJson(const FString& JsonString)
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonString);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
JsonObject->TryGetStringField(TEXT("ErrorCode"), ErrorCode);
JsonObject->TryGetStringField(TEXT("Message"), Message);
const TSharedPtr<FJsonObject>* TokenObject;
if (JsonObject->TryGetObjectField(TEXT("Token"), TokenObject))
{
Token.FromJson(*TokenObject);
}
const TSharedPtr<FJsonObject>* PlayerObject;
if (JsonObject->TryGetObjectField(TEXT("Player"), PlayerObject))
{
Player.FromJson(*PlayerObject);
}
return true;
}
return false;
}
};
/**
* 구글 로그인 요청 전송
*/
static void Send(
const FString& GoogleIdToken,
FOnGoogleSigninSuccess OnSuccess,
FOnGoogleSigninError OnError
);
};
구현 파일 (GoogleSignin.cpp)
// GoogleSignin.cpp
#include "GoogleSignin.h"
#include "PlayNANOOHelper.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
void FGoogleSignin::Send(
const FString& GoogleIdToken,
FOnGoogleSigninSuccess OnSuccess,
FOnGoogleSigninError OnError)
{
// 요청 데이터 생성 (기기 정보는 자동으로 포함됨)
TSharedPtr<FJsonObject> Body = FPlayNANOOHelper::CreateRequestBody();
Body->SetStringField(TEXT("linked_id"), GoogleIdToken);
// JSON 변환
FString JsonBody;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonBody);
FJsonSerializer::Serialize(Body.ToSharedRef(), Writer);
// HTTP 요청 생성
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetURL(TEXT("https://service-account.playnanoo.com/api/v20240401/google/signin"));
Request->SetVerb(TEXT("PUT"));
Request->SetContentAsString(JsonBody);
// 공통 헤더 설정 (로그인 API이므로 인증 토큰 불필요)
FPlayNANOOHelper::SetCommonHeaders(Request, false);
// 응답 처리
Request->OnProcessRequestComplete().BindLambda(
[OnSuccess, OnError](FHttpRequestPtr Req, FHttpResponsePtr Res, bool bSuccess)
{
if (bSuccess && Res.IsValid())
{
FString Response = Res->GetContentAsString();
FRes Result;
if (Result.FromJson(Response))
{
if (Result.ErrorCode.IsEmpty())
{
// 성공
OnSuccess.ExecuteIfBound(Response);
}
else
{
// 에러 응답
OnError.ExecuteIfBound(Response);
}
}
else
{
// JSON 파싱 실패
OnError.ExecuteIfBound(TEXT("Failed to parse response"));
}
}
else
{
// HTTP 요청 실패
OnError.ExecuteIfBound(TEXT("HTTP request failed"));
}
}
);
// 요청 전송
Request->ProcessRequest();
}
사용 예제
void UYourClass::GoogleLogin()
{
// Google 로그인 SDK를 통해 ID 토큰을 받은 후
FString GoogleIdToken = TEXT("구글_ID_토큰");
// 구글 로그인 요청 (기기 정보는 FPlayNANOOHelper가 자동으로 처리)
FGoogleSignin::Send(
GoogleIdToken,
FOnGoogleSigninSuccess::CreateLambda([](const FString& Response)
{
FGoogleSignin::FRes Result;
if (Result.FromJson(Response))
{
// 토큰 저장
FPlayNANOOHttpClient::AccessToken = Result.Token.AccessToken;
// 토큰 정보 출력
UE_LOG(LogTemp, Log, TEXT("AccessToken: %s"), *Result.Token.AccessToken);
UE_LOG(LogTemp, Log, TEXT("RefreshToken: %s"), *Result.Token.RefreshToken);
// 플레이어 정보 출력
UE_LOG(LogTemp, Log, TEXT("UserUniqueID: %s"), *Result.Player.UserUniqueID);
UE_LOG(LogTemp, Log, TEXT("OpenID: %s"), *Result.Player.OpenID);
UE_LOG(LogTemp, Log, TEXT("Nickname: %s"), *Result.Player.Nickname);
UE_LOG(LogTemp, Log, TEXT("LinkedID: %s"), *Result.Player.LinkedID);
UE_LOG(LogTemp, Log, TEXT("LinkedType: %s"), *Result.Player.LinkedType);
UE_LOG(LogTemp, Log, TEXT("Country: %s"), *Result.Player.Country);
// 구매 관련 정보 출력
UE_LOG(LogTemp, Log, TEXT("PurchaseCount: %d"), Result.Player.PurchaseCount);
UE_LOG(LogTemp, Log, TEXT("PurchaseTotalPrice: %.2f"), Result.Player.PurchaseTotalPrice);
UE_LOG(LogTemp, Log, TEXT("PurchaseCurrencyCode: %s"), *Result.Player.PurchaseCurrencyCode);
UE_LOG(LogTemp, Log, TEXT("Timezone: %s"), *Result.Player.Timezone);
UE_LOG(LogTemp, Log, TEXT("Offset: %d"), Result.Player.Offset);
UE_LOG(LogTemp, Log, TEXT("JoinPeriod: %d"), Result.Player.JoinPeriod);
}
}),
FOnGoogleSigninError::CreateLambda([](const FString& Error)
{
UE_LOG(LogTemp, Error, TEXT("구글 로그인 실패: %s"), *Error);
})
);
}
Google 로그인 플러그인
Unreal Engine에서 Google 로그인을 사용하려면 Google Sign-In 플러그인을 설치하거나 네이티브 SDK를 연동해야 합니다.
- Android: Google Play Games Services
- iOS: Google Sign-In SDK
ID 토큰 발급
구글 OAuth 로그인을 통해 ID 토큰을 받아야 합니다. 이 토큰을 linked_id 파라미터로 전달합니다.