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
Hey Bastian, thanks for this gist! I ran into some trouble when building in XCode however, was wondering if you'd be able to lend a hand:
Undefined symbols for architecture arm64: "_generateIdentityVerificationSignature", referenced from: _IOSService_LinkWithPlayFab_m50C06AB4A24D0671D8FFFA339CDF9E97E004B60B in Assembly-CSharp1.o _IOSService_generateIdentityVerificationSignature_m984F45BAEDBD21D460CB748008F996C974F752BE in Assembly-CSharp1.o _U3CU3Ec__DisplayClass3_0_U3CLinkWithPlayFabU3Eb__0_m41D6AB0E02E8D40953DC88EC2554F12591BEED1F in Assembly-CSharp1.o (maybe you meant: _IOSService_generateIdentityVerificationSignature_m984F45BAEDBD21D460CB748008F996C974F752BE) ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
The code in the project is exactly as shown here, aside from some minor changes in the .mm file (that shouldn't be causing this linker issue). Thanks in advance for any help you can provide!