반응형

안녕하세요

unity cloud 연결을 위해 Apple Gamekit Plugin을 사용해보았지만

여러 이슈들로 인해 현재 이용이 어려워서 우회하는 방법을 이전 포스팅에 소개해드렸는데요

https://horae.tistory.com/1124

 

Unity Cloud Autenticator Game Center 연동시 발생하는 에러 해결

안녕하세요 오늘은 unity cloud authenticator Gamecenter 연동 과정중에 잘 안되는 부분을 해결하고자 하였고 어느정도 우회 방법을 찾았습니다. 우선 Unity에서는 Apple.gamekit을 이용한 연동 방식을 가이드

horae.tistory.com

오늘은 세부 설정 방법에 대하여 소개해드리려고 해요 

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 연동 확인

반응형
반응형

안녕하세요

오늘은 unity cloud authenticator

Gamecenter 연동 과정중에 잘 안되는 부분을 해결하고자 하였고 어느정도 우회 방법을 찾았습니다.

우선 Unity에서는 Apple.gamekit을 이용한 연동 방식을 가이드 하고 있습니다.

https://docs.unity.com/ugs/en-us/manual/authentication/manual/platform-signin-apple-game-center

 

하지만 해당 방법으로 진행하려고 하면 dllnotfound 가 나오던가 아니면, entrypoint를 못찾는 이슈에 도달하게 됩니다.

관련하여 여러 커뮤니티를 찾아보았고 Unity 기술자는 해당 문제에 대해 Apple에 고쳐달라고 얘기하였다고 합니다. 

해당 링크중에 다른 방법으로 unitycloud 연동방식을 해결한 사람이 있었습니다.

 https://gist.github.com/BastianBlokland/bbc02a407b05beaf3f55ead3dd10f808

Publickey url, signature, salt and timestamp 값만 있으면 

unity cloud에서 제공하는 코드로 연동이 가능합니다!!

바로 아래 코드에 인자 값으로 들어가게 되는거지요

async Task SignInWithAppleGameCenterAsync(string signature, string teamPlayerId, string   publicKeyURL, string salt, ulong timestamp)
{
    try
    {
        await AuthenticationService.Instance.SignInWithAppleGameCenterAsync(signature, teamPlayerId, publicKeyURL, salt, timestamp);
        Debug.Log("SignIn is successful.");
    }
    catch (AuthenticationException ex)
    {
        // Compare error code to AuthenticationErrorCodes
        // Notify the player with the proper error message
        Debug.LogException(ex);
    }
    catch (RequestFailedException ex)
    {
        // Compare error code to CommonErrorCodes
        // Notify the player with the proper error message
        Debug.LogException(ex);
    }
}

 

그래서 저는 아래와 같이 코드를 추가해보았답니다. 

자세한 내용은 아래 포스팅을 참고해주세요

https://horae.tistory.com/1125

 

Unity Cloud Gamecenter 연결 관련 해결

안녕하세요 unity cloud 연결을 위해 Apple Gamekit Plugin을 사용해보았지만 여러 이슈들로 인해 현재 이용이 어려워서 우회하는 방법을 이전 포스팅에 소개해드렸는데요 https://horae.tistory.com/1124 Unity Clo

horae.tistory.com

 

참고

https://forum.unity.com/threads/apple-unity-plugins-crashing-on-authentication.1450414/#post-9424940

https://forum.unity.com/threads/apple-unity-plugins-crashing-on-authentication.1450414/#post-9424940

https://docs.unity.com/ugs/en-us/manual/authentication/manual/platform-signin-apple-game-center

https://docs.google.com/document/d/18IfxMcaYCoCHgFrMmM4gfGCHcKKnYx9iCr6DFBU-nLg/edit#heading=h.nh5j6ob4nbj3

I have the same problem,
fetchItems()
OnSuccess()
Thread 1: EXC_BAD_ACCESS (code=257, address=0x2) error, it just crashes when cuts connection from the device to XCode
if not cut connection, it will keep stay in this error line in Xcode
using Unity 2021.3.9f, build on iOS,
manually modified manifest.json to use unity authentication 2.4.0
using Apple Game Center plugin for unity

반응형
반응형

[unity/android] android에서 Debug.Log() 로그 출력하기

 

#방법은 2가지가 있다.

1.cmd 환경에서 아래 명령어를 입력한다.

adb logcat -s Unity

#다음과 같이 logcat을 볼 수 있다.

 

2.유니티 툴에서 [windows]->[Package Manager] 에서 [android Logcat] 설치

 

[Windows]->[Analsis] ->[android Logcat] 창 실행

#모바일에서 환경에서 디버깅이 가능하다.

 

#unity #유니티 #debug #log #debugging #디버깅 #로그 #안드로이드 #android 

 

 

출처: https://gofogo.tistory.com/70

 

 

반응형
반응형

 

iOS 앱을 개발하고 광고까지 넣어서 출시한 경험이 있다면 잘 알겠지만, 본인 기기에서 광고를 클릭하면 부정 클릭으로 인식되어 광고가 막힌다. 하지만 AdMob에 본인 기기를 테스트 기기로 등록하면 앱 내 광고가 테스트 모드로 바뀌기 때문에 부정 클릭을 걱정할 필요가 없다.

배너 광고만 넣은 경우는 조심하면 될 것 같긴 한데, 전면 광고는 무조건 보이기 때문에 광고가 잘 나오는지 확인하려면 테스트 모드로 확인하는 수밖에 없을 것이다.

1. IDFA 값 알아오기
AdMob에 테스트 기기를 등록하려면 IDFA가 필요하다. Android는 설정에서 쉽게 알 수 있지만 iOS는 코드를 작성해서 알아와야 한다.

AppDelegate에 AdSupport와 AppTrackingTransparency를 import 하고 앱 추적 권한 요청 코드를 작성한다. 허용하면 IDFA 값을 print 하여 알아온다.

// AppDelegate.swift
import UIKit
import AdSupport
import AppTrackingTransparency
import GoogleMobileAds

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // 앱 추적 권한 요청
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            if #available(iOS 14, *) {
                ATTrackingManager.requestTrackingAuthorization { status in
                    switch status {
                    case .authorized:           // 허용됨
                        print("Authorized")
                        print("IDFA = \(ASIdentifierManager.shared().advertisingIdentifier)")
                    case .denied:               // 거부됨
                        print("Denied")
                    case .notDetermined:        // 결정되지 않음
                        print("Not Determined")
                    case .restricted:           // 제한됨
                        print("Restricted")
                    @unknown default:           // 알려지지 않음
                        print("Unknow")
                    }
                }
            }
        }

        // AdMob
        GADMobileAds.sharedInstance().start(completionHandler: nil)
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(
        _ application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
    ) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }
}

 

2. AdMob에서 테스트 기기 추가하기
AdMob에 로그인한 후 대시보드에서 설정 ➜ 기기 테스트 ➜ 테스트 기기 추가를 선택한다.

 

 

 

출처: https://velog.io/@minji0801/AdMob-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B8%B0%EA%B8%B0-%EB%93%B1%EB%A1%9D%ED%95%98%EA%B8%B0

 

반응형

+ Recent posts