Skip to main content

Android Signup and Authentication

Apple OAuth login handling via external browser. Supports Apple login on Android.

How It Works
  1. Obtain Apple OAuth URL from PlayNANOO server
  2. Log in with Apple account in external browser
  3. Receive token via Deep Link
  4. 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);
})
);
}

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