本文源链接:http://blog.csdn.net/qq393830887/article/details/54023218
关键
1. 从2016年开始,Game Center已经取消了沙箱机制
2. 要开启Game Center,需要在iTunes Connect的Game Center处,新建一个排行榜或者成就。这个我觉得就是苹果的bug,虽然也能理解,否则的话当连入Game Center的时候,会收到error,权限没开?建完之后就可以删除的了
3. 要是取消Game Center登陆3次,虽然会收到回调,但是由于view为空,无法继续弹出登陆界面,得让玩家自己去Game Center手动登陆才行(坑爹的潜规则)
代码
#import <GameKit/GameKit.h>
@implementation GameCenterSdkController
{
// 记录上次的账号,用于确认是否有登出操作
NSString* _lastPlayerId;
// 保证只初始化一次
BOOL _hasInit;
// 判断是否登陆过一次了
BOOL _hasLoginOnce;
}
//初始化
-(void)initsdk
{
NSLog(@"初始化 init");
//一般要在这里增加回调监听
if (self->_hasInit)
{
[self sendMessageToUnity:"init" code:1 data:@"想要再次验证Game Center,请切到后台再切回来,或者重启游戏。"];
return;
}
self->_hasInit = true;
[self registerForAuthenticationNotification];
[self setAuthenticateLocalPlayer];
}
//注销
- (void)logout
{
NSLog(@"注销 logout");
// 苹果没有主动登出一说
[self sendMessageToUnity:"logout" code:0 data:@""];
}
//登陆
- (void)login
{
NSLog(@"登陆 login");
[self getSignature];
}
//帐号管理
- (void)userCenter
{
NSLog(@"帐号管理 userCenter");
}
-(BOOL) isAuthenticated
{
return [[GKLocalPlayer localPlayer] isAuthenticated];
}
-(NSString*) getLocalPlayerId
{
if ([self isAuthenticated])
{
return [GKLocalPlayer localPlayer].playerID;
}
return nil;
}
// 这玩意只有第一次执行的时候会触发回调
-(void) setAuthenticateLocalPlayer
{
NSLog(@"setAuthenticateLocalPlayer");
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError *error)
{
[self authenticateCallback:viewcontroller Error:error];
})];
}
// 这玩意每次切换到桌面再切回来还会被调用一次,有点像支付
-(void) authenticateCallback:(UIViewController*)viewcontroller Error:(NSError*)error
{
NSLog(@"authenticateCallback");
if (viewcontroller != nil)
{
NSLog(@"打开Game Center验证界面。");
[self.rootViewController presentViewController:viewcontroller animated:YES completion:nil];
}
else
{
// 登出再登陆的,说明已经初始化过了
if (self->_hasLoginOnce)
{
return;
}
// 切到后台,登出,再切回来,依旧是空viewcontroller,空error,非常神奇
if ([self isAuthenticated])
{
self->_hasLoginOnce = true;
[self sendMessageToUnity:"init" code:0 data:@""];
}
else
{
if (error)
{
[self sendMessageToUnity:"init" code:1 data:[NSString stringWithFormat:@"code=%ld description=%@", (long)error.code, error.description]];
}
else
{
[self sendMessageToUnity:"init" code:1 data:@"Game Center登出了或者未知错误"];
}
}
}
}
-(void) getSignature
{
// 如果还没有登录,特殊处理
if (![self isAuthenticated])
{
[self sendMessageToUnity:"login" code:2 data:@"玩家还没有登录GameCenter,切到后台再切回来登陆,或者去Game Center登陆。"];
return;
}
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error)
{
if(error != nil)
{
[self sendMessageToUnity:"login" code:2 data:[NSString stringWithFormat:@"code=%ld description=%@", (long)error.code, error.description]];
return;
}
NSString* url = [publicKeyUrl absoluteString];
NSString* sig = [NSString stringWithFormat:@"%@", [signature base64EncodedStringWithOptions: 0]];
NSString* slt = [NSString stringWithFormat:@"%@", [salt base64EncodedStringWithOptions: 0]];
NSString* stamp = [NSString stringWithFormat:@"%llu", timestamp];
NSString* playerId = [GKLocalPlayer localPlayer].playerID;
NSString* bundleId = [NSBundle mainBundle].bundleIdentifier;
NSString* data = [NSString stringWithFormat:@"%@|%@|%@|%@|%@|%@", playerId, sig, slt, stamp, url, bundleId];
NSLog(@"%@", data);
[self sendMessageToUnity:"login" code:0 data:data];
}];
}
-(void) registerForAuthenticationNotification
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];
}
// 这玩意会比authenticationHandler早回调
-(void) authenticationChanged
{
NSLog(@"authenticationChanged");
// 登出了或者切换了账号
if (self->_lastPlayerId != nil)
{
[self logout];
}
self->_lastPlayerId = [self getLocalPlayerId];
}
@end
- 其实关键在于generateIdentityVerificationSignatureWithCompletionHandler获取的数据如何验证,有空我在弄一下吧
- setAuthenticateHandler有点像支付,第一次调用的时候会触发handler,然后每次后台切换回来也会触发
- 退出账号这里有问题,authenticateCallback无法正确判断,只能通过GKPlayerAuthenticationDidChangeNotificationName