Android注册及认证
通过外部浏览器进行Apple OAuth登录处理。支持在Android上进行Apple登录。
工作方式
- 从PlayNANOO服务器获取Apple OAuth URL
- 在外部浏览器中登录Apple账号
- 通过Deep Link接收token
- 使用Token调用账号注册(SocialSignIn)或会员转换(SocialChange)API
Unreal实现
// iOSSignin.h
#pragma once
#include "CoreMinimal.h"
#include "Http.h"
#include "Json.h"
#include "JsonUtilities.h"
#include "iOSSignin.generated.h"
DECLARE_DELEGATE_OneParam(FOnAppleSigninSuccess, const FString&);
DECLARE_DELEGATE_TwoParams(FOnAppleSigninError, const FString&, const FString&);
/**
* Apple Sign In (Android/iOS)
* 외부 브라우저를 통한 Apple OAuth 로그인 처리
*/
UCLASS()
class YOURPROJECT_API UiOSSignin : public UObject
{
GENERATED_BODY()
private:
// Apple URL 응답 구조체
struct FAppleUrlResponse
{
FString ErrorCode;
FString Message;
FString Url;
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);
JsonObject->TryGetStringField(TEXT("Url"), Url);
return true;
}
return false;
}
};
FOnAppleSigninSuccess OnSuccessCallback;
FOnAppleSigninError OnErrorCallback;
public:
/**
* Apple 로그인 시작
*/
UFUNCTION(BlueprintCallable, Category = "PlayNANOO|Account")
void Sign_in_with_Apple(FOnAppleSigninSuccess OnSuccess, FOnAppleSigninError OnError);
private:
void GetAppleUrlAndOpen();
void OnDeepLink(const FString& URL);
void SendTokenToServer(const FString& Token);
FString ExtractParam(const FString& URL, const FString& Key);
};
// iOSSignin.cpp
#include "iOSSignin.h"
#include "PlayNANOOHelper.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "Kismet/GameplayStatics.h"
void UiOSSignin::Sign_in_with_Apple(FOnAppleSigninSuccess OnSuccess, FOnAppleSigninError OnError)
{
OnSuccessCallback = OnSuccess;
OnErrorCallback = OnError;
// Deep Link 리스너 등록
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.AddUObject(this, &UiOSSignin::OnDeepLink);
GetAppleUrlAndOpen();
}
void UiOSSignin::GetAppleUrlAndOpen()
{
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetVerb(TEXT("GET"));
Request->SetURL(TEXT("https://service-account.playnanoo.com/api/apple/url"));
// 공통 헤더 설정 (로그인 API이므로 인증 토큰 불필요)
FPlayNANOOHelper::SetCommonHeaders(Request, false);
Request->OnProcessRequestComplete().BindLambda(
[this](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bSuccess)
{
if (bSuccess && Response.IsValid())
{
FAppleUrlResponse Result;
if (Result.FromJson(Response->GetContentAsString()))
{
if (!Result.Url.IsEmpty())
{
FPlatformProcess::LaunchURL(*Result.Url, nullptr, nullptr);
}
else
{
OnErrorCallback.ExecuteIfBound(Result.ErrorCode, Result.Message);
}
}
}
else
{
OnErrorCallback.ExecuteIfBound(TEXT("HTTP_ERROR"), TEXT("Failed to get Apple URL"));
}
}
);
Request->ProcessRequest();
}
void UiOSSignin::OnDeepLink(const FString& URL)
{
if (URL.Contains(TEXT("type=apple")))
{
FString Status = ExtractParam(URL, TEXT("status"));
FString Token = ExtractParam(URL, TEXT("token"));
if (Status == TEXT("success") && !Token.IsEmpty())
{
SendTokenToServer(Token);
}
else
{
OnErrorCallback.ExecuteIfBound(TEXT("APPLE_AUTH_FAILED"), TEXT("Apple authentication failed"));
}
// Deep Link 리스너 해제
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.RemoveAll(this);
}
}
void UiOSSignin::SendTokenToServer(const FString& Token)
{
// token 값으로 SocialChange 또는 SocialSignIn 진행
// SocialChange(Token, TEXT("APPLE ID"));
// or
// SocialSignIn(Token, TEXT("APPLE ID"));
OnSuccessCallback.ExecuteIfBound(Token);
}
FString UiOSSignin::ExtractParam(const FString& URL, const FString& Key)
{
FString Search = Key + TEXT("=");
if (URL.Contains(Search))
{
int32 StartIndex = URL.Find(Search) + Search.Len();
int32 EndIndex = URL.Find(TEXT("&"), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartIndex);
if (EndIndex == INDEX_NONE)
{
EndIndex = URL.Len();
}
return URL.Mid(StartIndex, EndIndex - StartIndex);
}
return FString();
}
使用方法
1. 开始Apple登录
void UYourClass::StartAppleLogin()
{
UiOSSignin* AppleSignin = NewObject<UiOSSignin>();
AppleSignin->Sign_in_with_Apple(
FOnAppleSigninSuccess::CreateLambda([](const FString& Token)
{
UE_LOG(LogTemp, Log, TEXT("Apple 로그인 성공! Token: %s"), *Token);
// 토큰으로 PlayNANOO API 호출
// SocialSignIn(Token, TEXT("APPLE ID"));
}),
FOnAppleSigninError::CreateLambda([](const FString& ErrorCode, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Apple 로그인 실패: [%s] %s"), *ErrorCode, *Message);
})
);
}
2. 通过Token关联账号
认证完成后,使用SendTokenToServer方法中获取的token调用PlayNANOO API:
新登录(SocialSignIn)
void UYourClass::SocialSignIn(const FString& Token, const FString& AccountType)
{
// Apple 계정으로 처음 로그인
// AccountType: "APPLE ID"
}
会员转换(SocialChange)
void UYourClass::SocialChange(const FString& Token, const FString& AccountType)
{
// 비회원에서 Apple 회원으로 전환
// AccountType: "APPLE ID"
}
参考
- 账号类型 值:
PN_ACCOUNT_APPLE_ID = "APPLE ID"- 详细信息请参阅 其他 > 账号类型信息 参考 - 会员转换: 游客关联 > 会员转换 文档 参考