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
Thanks for the heads up about the deprecation, will have to look into that.
Good to hear that you got it working. Atm i don't think you will be rejected, at work we are using this in two live projects and have had no problems shipping updates. But it's an interesting question what the replacement api for this is.