Android Signup and Authentication
Apple OAuth login handling via external browser. Supports Apple login on Android.
How It Works
- Obtain Apple OAuth URL from PlayNANOO server
- Log in with Apple account in external browser
- Receive token via Deep Link
- Call account registration (SocialSignIn) or account conversion (SocialChange) API with the token
Unreal Implementation
// 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 login handling via external browser
*/
UCLASS()
class YOURPROJECT_API UiOSSignin : public UObject
{
GENERATED_BODY()
private:
// Apple URL response struct
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:
/**
* Start Apple login
*/
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;
// Register Deep Link listener
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"));
// Set common headers (no authentication token needed for login 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"));
}
// Remove Deep Link listener
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.RemoveAll(this);
}
}
void UiOSSignin::SendTokenToServer(const FString& Token)
{
// Proceed with SocialChange or SocialSignIn using token value
// 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();
}
Usage
1. Start Apple Login
void UYourClass::StartAppleLogin()
{
UiOSSignin* AppleSignin = NewObject<UiOSSignin>();
AppleSignin->Sign_in_with_Apple(
FOnAppleSigninSuccess::CreateLambda([](const FString& Token)
{
UE_LOG(LogTemp, Log, TEXT("Apple login successful! Token: %s"), *Token);
// Call PlayNANOO API with token
// SocialSignIn(Token, TEXT("APPLE ID"));
}),
FOnAppleSigninError::CreateLambda([](const FString& ErrorCode, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Apple login failed: [%s] %s"), *ErrorCode, *Message);
})
);
}
2. Link Account with Token
Call the PlayNANOO API with the token received in the SendTokenToServer method after authentication:
New Login (SocialSignIn)
void UYourClass::SocialSignIn(const FString& Token, const FString& AccountType)
{
// First login with Apple account
// AccountType: "APPLE ID"
}
Account Conversion (SocialChange)
void UYourClass::SocialChange(const FString& Token, const FString& AccountType)
{
// Convert from guest to Apple member
// AccountType: "APPLE ID"
}
Reference
- Account Type Value:
PN_ACCOUNT_APPLE_ID = "APPLE ID"- See Etc > Account Type Information for more details - Account Conversion: Refer to Guest > Account Conversion documentation