반응형
안녕하세요
unity cloud 연결을 위해 Apple Gamekit Plugin을 사용해보았지만
여러 이슈들로 인해 현재 이용이 어려워서 우회하는 방법을 이전 포스팅에 소개해드렸는데요
https://horae.tistory.com/1124
오늘은 세부 설정 방법에 대하여 소개해드리려고 해요
1. Asset/Plugin/iOS 폴더 밑에 .m 파일 생성 한다.
구체적으로 c#스크립트를 먼저 생성 후 확장자 이름을 .m으로 변경해줘야 한다. (finder에서 변경)
변경 이후 기존 c# .meta 파일은 삭제
.m 파일에 아래 코드 삽입
#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
typedef void (*IdentityVerificationSignatureCallback)(const char * publicKeyUrl, const char * signature, int signatureLength, const char * salt, int saltLength, const uint64_t timestamp, const char * error);
extern void generateIdentityVerificationSignature(IdentityVerificationSignatureCallback callback) {
GKLocalPlayer * localPlayer = [GKLocalPlayer localPlayer];
NSLog(@"LocalPlayer: %@", localPlayer.playerID);
[localPlayer fetchItemsForIdentityVerificationSignature:^(NSURL * _Nullable publicKeyURL, NSData * _Nullable signature, NSData * _Nullable salt, uint64_t timestamp, NSError * _Nullable error) {
NSLog(@"Received 'generateIdentityVerificationSignature' callback, error: %@", error.description);
// Create a pool for releasing the resources we create
@autoreleasepool {
// PublicKeyUrl
const char * publicKeyUrlCharPointer = NULL;
if (publicKeyURL != NULL)
{
const NSString * publicKeyUrlString = [[NSString alloc] initWithString:[publicKeyURL absoluteString]];
publicKeyUrlCharPointer = [publicKeyUrlString UTF8String];
}
// Signature
const char * signatureBytes = (char*)[signature bytes];
int signatureLength = (int)[signature length];
// Salt
const char * saltBytes = (char*)[salt bytes];
int saltLength = (int)[salt length];
// Error
const NSString * errorString = error.description;
const char * errorStringPointer = [errorString UTF8String];
// Callback
callback(publicKeyUrlCharPointer, signatureBytes, signatureLength, saltBytes, saltLength, timestamp, errorStringPointer);
}
}];
}
2. 위에서 만든 코드를 실제 호출하는 코드 이며, .cs파일에 넣는다.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void IdentityVerificationSignatureCallback(
string publicKeyUrl,
IntPtr signaturePointer, int signatureLength,
IntPtr saltPointer, int saltLength,
ulong timestamp,
string error);
[DllImport("__Internal")]
public static extern void generateIdentityVerificationSignature(
[MarshalAs(UnmanagedType.FunctionPtr)]IdentityVerificationSignatureCallback callback);
// Note: This callback has to be static because Unity's il2Cpp doesn't support marshalling instance methods.
[MonoPInvokeCallback(typeof(IdentityVerificationSignatureCallback))]
public static void OnIdentityVerificationSignatureGenerated(
string publicKeyUrl,
IntPtr signaturePointer, int signatureLength,
IntPtr saltPointer, int saltLength,
ulong timestamp,
string error)
{
// Create a managed array for the signature
var signature = new byte[signatureLength];
Marshal.Copy(signaturePointer, signature, 0, signatureLength);
// Create a managed array for the salt
var salt = new byte[saltLength];
Marshal.Copy(saltPointer, salt, 0, saltLength);
UnityEngine.Debug.Log($"publicKeyUrl: {publicKeyUrl}");
UnityEngine.Debug.Log($"signature: {signature.Length}");
UnityEngine.Debug.Log($"salt: {salt.Length}");
UnityEngine.Debug.Log($"timestamp: {timestamp}");
UnityEngine.Debug.Log($"error: {error}");
}
3. 해당 코드를 호출 및 사용 하도록 코드 구성
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void IdentityVerificationSignatureCallback(
string publicKeyUrl,
IntPtr signaturePointer, int signatureLength,
IntPtr saltPointer, int saltLength,
ulong timestamp,
string error);
[DllImport("__Internal")]
public static extern void generateIdentityVerificationSignature(
[MarshalAs(UnmanagedType.FunctionPtr)] IdentityVerificationSignatureCallback callback);
// Note: This callback has to be static because Unity's il2Cpp doesn't support marshalling instance methods.
[MonoPInvokeCallback(typeof(IdentityVerificationSignatureCallback))]
public static void OnIdentityVerificationSignatureGenerated(
string publicKeyUrl,
IntPtr signaturePointer, int signatureLength,
IntPtr saltPointer, int saltLength,
ulong timestamp,
string error)
{
// Create a managed array for the signature
var signature = new byte[signatureLength];
Marshal.Copy(signaturePointer, signature, 0, signatureLength);
// Create a managed array for the salt
var salt = new byte[saltLength];
Marshal.Copy(saltPointer, salt, 0, saltLength);
string time = timestamp.ToString();
UnityEngine.Debug.Log($"horae:: publicKeyUrl: {publicKeyUrl}");
UnityEngine.Debug.Log($"horae:: signature.length: {signature.Length}");
UnityEngine.Debug.Log($"horae:: salt.length: {salt.Length}");
UnityEngine.Debug.Log($"horae:: string timestamp: {time}");
UnityEngine.Debug.Log($"horae:: ulong timestamp: {timestamp}");
UnityEngine.Debug.Log($"horae:: error: {error}");
UnityEngine.Debug.Log($"horae:: signature: {BitConverter.ToString(signature).Replace("-", "")}");
UnityEngine.Debug.Log($"horae:: salt: {BitConverter.ToString(salt).Replace("-", "")}");
UnityEngine.Debug.Log($"horae:: signature base64: {Convert.ToBase64String(signature)}");
UnityEngine.Debug.Log($"horae:: salt base64: {Convert.ToBase64String(salt)}");
Task task = SignInWithAppleGameCenterAsync(Convert.ToBase64String(signature), Social.localUser.id, publicKeyUrl, Convert.ToBase64String(salt), timestamp);
}
public void StartIdentityVerification()
{
// 네이티브 코드에게 인증 서명을 생성하도록 요청합니다.
generateIdentityVerificationSignature(OnIdentityVerificationSignatureGenerated);
}
public static async Task SignInWithAppleGameCenterAsync(string signature, string teamPlayerId, string publicKeyURL, string salt, ulong timestamp)
{
Debug.Log("horae:: SignInWithAppleGameCenterAsync");
Debug.Log("horae:: SignInWithAppleGameCenterAsync signature: " + signature);
Debug.Log("horae:: SignInWithAppleGameCenterAsync teamPlayerId: " + teamPlayerId);
Debug.Log("horae:: SignInWithAppleGameCenterAsync publicKeyURL: " + publicKeyURL);
Debug.Log("horae:: SignInWithAppleGameCenterAsync salt: " + salt);
Debug.Log("horae:: SignInWithAppleGameCenterAsync timestamp: " + timestamp);
try
{
Debug.Log("horae:: try await SignInWithAppleGameCenterAsync");
await AuthenticationService.Instance.SignInWithAppleGameCenterAsync(signature, teamPlayerId, publicKeyURL, salt, timestamp);
UnityEngine.Debug.Log("horae:: SignIn is successful.");
}
catch (AuthenticationException ex)
{
// Compare error code to AuthenticationErrorCodes
// Notify the player with the proper error message
Debug.Log("horae:: AuthenticationException");
Debug.LogException(ex);
}
catch (RequestFailedException ex)
{
// Compare error code to CommonErrorCodes
// Notify the player with the proper error message
Debug.Log("horae:: RequestFailedException");
Debug.LogException(ex);
}
}
4. 이제 StartIdentityVerification() 함수를 호출해주면 Gamecenter 로 로그인한 유저를
Unity Cloud로 연결해준다.
AppleGamecenterHandler.Instance.GameCenterInit();
AppleGamecenterHandler.Instance.StartIdentityVerification();
GamecenterInit()은 아래와 같이 구성되어 있다
public void GameCenterInit()
{
DontDestroyOnLoad(gameObject);
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
if (task.Exception != null)
{
Debug.LogError($"Failed to initialize Firebase with {task.Exception}");
return;
}
auth = FirebaseAuth.DefaultInstance;
OnFirebaseInitialized.Invoke();
});
GameCenterLogin();
}
/// <summary>
/// Apple GameCenter Login
/// </summary>
public void GameCenterLogin()
{
if (Social.localUser.authenticated == true)
{
Debug.Log("Success to true");
}
else
{
Social.localUser.Authenticate((bool success) =>
{
if (success)
{
Debug.Log("Success to authenticate");
}
else
{
Debug.Log("Faile to login");
}
});
}
}
5. Unity Cloud 연동 확인
반응형
'게임 관련 > 유니티' 카테고리의 다른 글
[유니티 xcode]Invalid Bundle. The bundle at 'CuteMaze.app/Frameworks/UnityFramework.framework' contains disallowed file 'Frameworks'. (0) | 2024.06.09 |
---|---|
FBLPromises Framework not found 에러 문제 해결 방법 (0) | 2024.05.14 |
Unity Cloud Autenticator Game Center 연동시 발생하는 에러 해결 (0) | 2024.02.15 |
[Unity] 유니티 환경에서 android Debug 진행하는 방법 (0) | 2024.01.30 |
ios admob 테스트 기기 등록 방법 (0) | 2024.01.17 |