Even tho Unity has implemented a game-center api (Social api) it doesn't have a way to generate a verification signature, which you need to use game-center as a authentication method.
Luckily the objective-c
code required is pretty straight forward. (Apple documentation: generateIdentityVerificationSignature)
#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 generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL * publicKeyUrl, NSData * signature, NSData * salt, uint64_t timestamp, NSError * 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 = [signature bytes];
int signatureLength = (int)[signature length];
// Salt
const char * saltBytes = [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);
}
}];
}
Strings are marshalled automatically for us and for the byte[]'s we pass a pointer to the obj-c memory, that way we can copy the data into managed arrays.
// Add a using for: AOT
// Add a using for: System.Runtime.InteropServices
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void IdentityVerificationSignatureCallback(
string publicKeyUrl,
IntPtr signaturePointer, int signatureLength,
IntPtr saltPointer, int saltLength,
ulong timestamp,
string error);
[DllImport("__Internal")]
private 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))]
private 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}");
}
You can then call generateIdentityVerificationSignature
and give it OnIdentityVerificationSignatureGenerated
as a callback, you can then in the callback save the results to a static variable for example.
Note: this assumes that the user is already logged-in to game-center, luckily Unity has already implemented the api to login:
Social.localUser.Authenticate(success =>
{
});
For info on where to place the objective-c
code Unity has a manual page: PluginsForIOS
Okay so... hiding in the source is the new auth-handle called
fetchItemsForIdentityVerificationSignature
. It looks like the same signature as the deprecatedgenerateIdentityVerificationSignature
but withteamPlayerId
instead.