Game Center Configuration Guide for iTunes Connect

iOS游戏开发之Game Center实战

iOS开发长文--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总

请看以上文章的GameCenter部分

Game Center是由苹果发布的在线多人游戏社交网络,通过它游戏玩家可以邀请好友进行多人游戏,它也会记录玩家的成绩并在排行榜中展示,同时玩家每经过一定的阶段会获得不同的成就。这里就简单介绍一下如何在自己的应用中集成Game Center服务来让用户获得积分、成就以及查看游戏排行和已获得成就。

准备工作:

①首先要创建一个Explicit App ID,不能创建Wildcard App ID,然后默认就勾选了GameCenter这个功能
②然后创建描述文件
③然后在ITC中创建刚刚那个BundleID的应用,这个应用可以不用提交
④创建沙盒测试用户,这个应该是iOS9.0还是iOS10.0之前的,现在是不需要添加沙盒测试用户了。如果要看测试数据,还需要到手机设置==>GameCenter==>sandbox

Snip20180312_22.png

⑤在ITC应用的Features里面找到GameCenter,然后配置GameCenter

Snip20180312_16.png

以下是排行榜的配置:其中重要的是排行榜ID,项目中要配置

Snip20180312_19.png

Snip20180312_20.png

⑥接下来就是工程中的配置了,第一步先打开Capability这个功能

Snip20180312_24.png

⑦接下来就是添加代码了:在需要的位置导入:

#import <GameKit/GameKit.h>
//验证授权
-(void)authPlayer{GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];localPlayer.authenticateHandler = ^(UIViewController * __nullable viewController, NSError * __nullable error){if ([[GKLocalPlayer localPlayer] isAuthenticated]) {NSLog(@"%@",@"已经授权!");}else if(viewController){[self presentViewController:viewController animated:YES completion:nil];}else{if (!error) {NSLog(@"%@",@"授权OK");} else {NSLog(@"没有授权");NSLog(@"AuthPlayer error :%@",error);}}};
}
// 上传分数给 gameCenter
-(void)saveHighScore{if ([GKLocalPlayer localPlayer].isAuthenticated) {//得到分数的报告GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier:@"你的排行榜ID,ITC中找"];scoreReporter.value = 1000;NSArray<GKScore*> *scoreArray = @[scoreReporter];//上传分数[GKScore reportScores:scoreArray withCompletionHandler:nil];}
}
//下载 game center 某一排行榜中的分数及排名情况
- (void)downLoadGameCenter{if ([GKLocalPlayer localPlayer].isAuthenticated == NO) {NSLog(@"没有授权,无法获取更多信息");return;}GKLeaderboard *leaderboadRequest = [GKLeaderboard new];//设置好友的范围leaderboadRequest.playerScope = GKLeaderboardPlayerScopeGlobal;//指定那个区域的排行榜NSString *type = @"today";if ([type isEqualToString:type]) {leaderboadRequest.timeScope = GKLeaderboardTimeScopeToday;}else if([type isEqualToString:@"week"]){leaderboadRequest.timeScope = GKLeaderboardTimeScopeWeek;}else if([type isEqualToString:@"all"]){leaderboadRequest.timeScope = GKLeaderboardTimeScopeAllTime;}//哪一个排行榜NSString *ID = @"你的排行榜ID,ITC中找";leaderboadRequest.identifier = ID;//从那个排名到那个排名NSInteger location = 1;NSInteger length = 10;leaderboadRequest.range = NSMakeRange(location, length);//请求数据[leaderboadRequest loadScoresWithCompletionHandler:^(NSArray<GKScore *> * _Nullable scores, NSError * _Nullable error) {if (error) {NSLog(@"请求分数失败");NSLog(@"error = %@",error);}else{NSLog(@"请求分数成功");//定义一个可变字符串存放用户信息NSMutableString *userInfo = [NSMutableString string];NSString *rankBoardID = nil;for (GKScore *score in scores) {NSLog(@"");//得到排行榜的 idNSString *gamecenterID = score.leaderboardIdentifier;NSString *playerName = score.player.displayName;NSInteger scroeNumb = score.value;NSInteger rank = score.rank;NSLog(@"排行榜 = %@,玩家名字 = %@,玩家分数 = %zd,玩家排名 = %zd",gamecenterID,playerName,scroeNumb,rank);[userInfo appendString:[NSString stringWithFormat:@"玩家名字 = %@,玩家分数 = %zd,玩家排名 = %zd",playerName,scroeNumb,rank]];[userInfo appendString:@"\n"];rankBoardID = gamecenterID;}//弹框展示[self popShowViewWithTitileName:[NSString stringWithFormat:@"%@ 排行榜的信息",rankBoardID] andInfo:userInfo];}}];
}
- (void)getAllOnlineFriends {if ([GKLocalPlayer localPlayer].isAuthenticated == NO) {NSLog(@"没有授权,无法获取好友信息");return;}[[GKLocalPlayer localPlayer] loadFriendPlayersWithCompletionHandler:^(NSArray<GKPlayer *> * _Nullable friendPlayers, NSError * _Nullable error) {//定义一个可变字符串存放用户信息NSMutableString *userInfo = [NSMutableString string];for (GKPlayer *player in friendPlayers) {NSString *name = player.displayName;NSString *al = player.alias;//NSString *ID = player.guestIdentifier;NSString *ID = @"";[userInfo appendString:[NSString stringWithFormat:@"好友名字 = %@,nickName = %@%@",name,al,ID]];[userInfo appendString:@"\n"];}[self popShowViewWithTitileName:@"好友信息" andInfo:userInfo];}];
}
//遵循代理
@interface ViewController ()<GKGameCenterControllerDelegate>//显示排行榜 可以跳转到自定的 game 排行榜 和 跳转到那个时间段
- (void)gameCenter{if ([GKLocalPlayer localPlayer].isAuthenticated == NO) {NSLog(@"没有授权,无法获取展示中心");return;}UIViewController *vc = [self.view.window rootViewController];GKGameCenterViewController *GCVC = [GKGameCenterViewController new];//跳转指定的排行榜中[GCVC setLeaderboardIdentifier:@"你的排行榜ID"];//跳转到那个时间段NSString *type = @"all";if ([type isEqualToString:@"today"]) {[GCVC setLeaderboardTimeScope:GKLeaderboardTimeScopeToday];}else if([type isEqualToString:@"week"]){[GCVC setLeaderboardTimeScope:GKLeaderboardTimeScopeWeek];}else if ([type isEqualToString:@"all"]){[GCVC setLeaderboardTimeScope:GKLeaderboardTimeScopeAllTime];}GCVC.gameCenterDelegate = self;[vc presentViewController:GCVC animated:YES completion:nil];
}//实现代理:
#pragma mark -  GKGameCenterControllerDelegate
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController{[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
// 上传成就
- (void)uploadAchievment {if ([GKLocalPlayer localPlayer].isAuthenticated == NO) {NSLog(@"没有授权,上传不了成就");return;}GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:@"challenge1"];[achievement setPercentComplete:10];[GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError * _Nullable error) {if (error) {NSLog(@"%@",error);}else{NSLog(@"上传成就成功");}}];
}
//下载 game center 中的所有排行榜的榜单内容,但是只是显示了每一个排行榜的内容,可以拼接下做一个TableView来显示
- (void)downloadGameCenter {if ([GKLocalPlayer localPlayer].isAuthenticated == NO) {NSLog(@"没有授权,无法获取更多信息");return;}[GKLeaderboard loadLeaderboardsWithCompletionHandler:^(NSArray<GKLeaderboard *> * _Nullable leaderboards, NSError * _Nullable error) {//定义可变字符串NSMutableString *leadBoardInfo = [NSMutableString string];for (GKLeaderboard *lb in leaderboards) {NSString *ID = lb.identifier;NSString *leadBoardTittle = lb.title;[lb loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {NSMutableString *stringM = [NSMutableString string];if (!error) {for (NSObject *score in scores) {GKScore *newScore = (GKScore *)score;GKPlayer *player = newScore.player;NSString *playerID = player.playerID;NSString *alias = player.alias;NSString *displayName = player.displayName;NSString *guestId = player.guestIdentifier;NSInteger rank = newScore.rank;NSDate *date = newScore.date;NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"];NSString *currentDateString = [dateFormatter stringFromDate:date];NSString *leaderboardID = newScore.leaderboardIdentifier;NSInteger value = newScore.value;NSInteger formattedValue = newScore.formattedValue;NSLog(@"score = %@",score);[stringM appendFormat:@"\nLeaderboardID:%@, PlayerID:%@,  NickName:%@, DisplayName:%@, GuestID:%@, Rank:%zd, Value:%zd, Time:%@",leaderboardID,playerID,alias,displayName,guestId,rank,value,currentDateString];}}[self popShowViewWithTitileName:leadBoardTittle andInfo:stringM];}];[leadBoardInfo appendString:[NSString stringWithFormat:@"排行榜id = %@,排行榜标题 = %@",ID,leadBoardTittle]];[leadBoardInfo appendString:@"\n"];}//[self popShowViewWithTitileName:@"所有的排行榜" andInfo:leadBoardInfo];}];
}
//Private method 弹框
-(void)popShowViewWithTitileName:(NSString *)tittleName andInfo:(NSString*)info{UIAlertController *alert = [UIAlertController alertControllerWithTitle:tittleName message:info preferredStyle:UIAlertControllerStyleAlert];[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];[self presentViewController:alert animated:true completion:nil];
}

所需参数

①具备GameCenter功能的描述文件
②成就ID和排行榜ID

注意问题

①看下手机的版本,如果是路径:设置==>GameCenter==>Sandbox能找到的话那么我们就需要开启这个Sandbox,如果路径没有表示的是新系统的,就不需要了。
②我们在测试的功能的时候都需要先授权,但是授权一次就OK,然后才能测试出功能
③如果我们测试的时候用两台设备测试,但是我们查看排行榜的数据的时候只能看到自己设备的数据,那可能是由于数据还没有统计过来,需要一点时延,可能几个小时后数据就能同步了,放心妥妥的睡一觉,明天第二天再来测试就能显示两台设备跑的数据了...
④另外如果发布的时候是需要勾选GameCenter开关的,见下图:

Snip20180328_40.png

调试过程中报错解决:
①问题一
报错如下:

Error Domain=GKErrorDomain Code=15 "未能完成所请求的操作,因为 Game Center 未识别此应用程序。"

问题解决:
①工程中开启Capability这个功能项
②对比下BundleId和ITC后台的BundleID是否一致
③再检查看itunesconnect里是不是没有添加过排行榜或者成就设置,必须要至少添加一条
④设置里面开启GameCenter.

②问题二:
报错如下:

 [Error] _authenticateUsingAlert:Faied to authenticate player with existing credentials.
Error: Error Domain=GKErrorDomain Code=6 "未能完成所请求的操作,因为本地玩家尚未通过认证。"
UserInfo={NSLocalizedDescription=未能完成所请求的操作,因为本地玩家尚未通过认证。

原因:这是由于GameCenter进入后台关闭导致的...
解决办法:再次进入后台,再进入前台,配合验证bolck中的代码如果viewController有值那么就展示此viewController就会出现系统的输入GameCenter id 的界面,下面有“注意注意”中有截图,所需配合的代码如下:

if(viewController){//这个是GameCenter没有开启的时候[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:viewController animated:YES completion:nil];
}

问题参考:
Unity iOS Game Center帐号验证(包括python后端)
解决 Error Domain=GKErrorDomain Code=15 &quot;无法完成所请求的操作,

文章参考:
iOS Game Center 登陆验证实现
IOS: How to authenticate the GKLocalPlayer on my 'third party server'.
服务器端验证 Apple Game Center GKLocalPlayer 签名(PHP描述)

蓝瘦.gif

以上!!!











注意注意:


GameCenter的验证流程:

①GameCenter通过以下方法验证登录:

[GKLocalPlayer localPlayer].authenticateHandler = ^(UIViewController * __nullable viewController, NSError * __nullable error){
//code here...
}

这个方法内部通过判断error和viewController来判定是否弹出登录框,如果viewController的值为nil,那么表明GameCenter的开关并没有关,是通过验证的,如下图:

Snip20180330_42.png

如果viewController不为nil,那么表明GameCenter的开关是关闭的,如下图:

Snip20180330_43.png

如果error为nil,并且[[GKLocalPlayer localPlayer] isAuthenticated]值为YES的话,一般就是验证成功的.
具体的验证方法如下:

        GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];//NSLog(@"localPlayer %@",localPlayer);localPlayer.authenticateHandler = ^(UIViewController * __nullable viewController, NSError * __nullable error){if ([[GKLocalPlayer localPlayer] isAuthenticated]) {NSLog(@"%@",@"已经授权!");//这个是在本地服务器上验证登录信息的,具体参考本小节结束给出[[GKLocalPlayer localPlayer] generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) {if (error) {NSLog(@"ERROR: %@",error);}}];if (localPlayer.playerID && localPlayer.playerID.length) {[KODGCPlayerInfo defaultUserInfo].playerID = [GKLocalPlayer localPlayer].playerID;[KODGCPlayerInfo defaultUserInfo].isFirstAuthenticationFlag = NO;}}else if(viewController){//这个是GameCenter没有开启的时候[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:viewController animated:YES completion:nil];}else{if (!error) {NSLog(@"%@",@"授权OK");} else {NSLog(@"没有授权");NSLog(@"AuthPlayer error :%@",error);}}};

②因为GKLocalPlayer是单例,并且苹果在内部把这个验证的block只传一次,但是会多次调用这个block信息,那么在何时会调用这个信息呢,请看以下说明:
1>程序一启动,只要点击登录按钮传入这个验证block,就会开始进行验证,然后如果验证成功,那么就会在屏幕上方弹出一个信息条,显示某某GameCenter账号已经登录了...
2>只要在程序中你再次点击这个登录按钮再次传入这个验证block是不会再进行验证的,因为你这个账号一直在使用没有问题...
3>但是如果我们让此程序进入后台再回到前台,那么传入的验证block将再次被调用。即每进入一次后台再回到前台就会调用一次验证block.
4>如果我们在进入后台的时候将GameCenter开关给关掉了,那么再回到前台的时候调用验证block,打印错误信息,但是此时的ViewController为nil,错误信息如下:

[Error] _authenticateUsingAlert:Faied to authenticate player with existing credentials.
Error: Error Domain=GKErrorDomain Code=6 "未能完成所请求的操作,因为本地玩家尚未通过认证。"
UserInfo={NSLocalizedDescription=未能完成所请求的操作,因为本地玩家尚未通过认证。

如果此时你再次进入后台,什么都不做,再次回到前台,那么会弹出GameCenter输入账号系统的验证,如下图:

Snip20180330_45.png

5>如果我们进入后台,直接将GameCenter关掉,然后再开启GameCenter再验证另外一个Apple ID,再次回到前台,此时会在界面上出现第二个账号登录的横幅弹框。

Snip20180330_46.png

对接游戏的登录系统

我们只需要每次调用验证block的时候,如果验证是成功的,并且localPlayer的playerID是有值的,那么我就记录这个localPlayer,然后保持最新的,如果用户点击登录,那么直接用记录的那个localPlayer去登录就行了,因为如果用户的行为是自己主动去后台切换了那个GameCenter的ID,那么意味着用户要切换GameCenter的ID从而来切换游戏里面的登录角色等等,那么此时用户再次进入游戏的时候,就应该主动去找到切换登录的按钮,再次点击登录即可,那么此时登录的账户就是最新的localPlayer了。

iOS开发之GameCenter使用相关推荐

  1. iOS开发之AVKit框架使用

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一.引言 在iOS开发框架中,AVKit是一个非常上层,偏应用的框架,它是基于AVFounda ...

  2. (0045) iOS 开发之MBProgressHUD 源码学习

    (0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1.  学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...

  3. (0016)iOS 开发之Mac上Navicat Premium 创建远程连接和本地连接

    1.下载安装 (百度云盘里面有安装文件和注册机) 链接: https://pan.baidu.com/s/1kVG1k71 密码: mr5g 破解教程看这篇博客:http://blog.csdn.ne ...

  4. 李洪强iOS开发之RunLoop的原理和核心机制

    李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研 ...

  5. IOS开发之MD5加密和钥匙串的使用-oc

    IOS开发之MD5加密和钥匙串的使用-oc 源码在我的主页,md5加密是用户登录安全的一个保障.不可逆的,可以暴力破解的. // // ViewController.m // MD5演练 // // ...

  6. IOS开发之CALayer基本属性和使用

    IOS开发之CALayer基本属性和使用 // // ViewController.m // CALayer // // Created by 鲁军 on 2021/2/21. //#import & ...

  7. ios开发之plist 的文件的读写以及沙盒容器路径打印

    ios开发之plist 的文件的读写以及沙盒容器路径打印 核心代码在这里 // // ViewController.m // 21-plist存储和沙盒路径 // // Created by 鲁军 o ...

  8. IOS开发之JSON文件的读写

    IOS开发之JSON文件的读写 // // ViewController.m // 20-JSON的读写 // // Created by 鲁军 on 2021/2/13. //#import &qu ...

  9. IOS开发之JSON序列化从客户端发送到服务器端

    IOS开发之JSON序列化从客户端发送到服务端的准备工作 共有6种情况 需要序列化 请查看源代码. 服务器端接受我们采用的是java的Tomcat服务器.配合 struts 2 controller框 ...

  10. IOS开发之UI基础LOL英雄展示-15

    IOS开发之UI基础LOL英雄展示-15 // // ViewController.m // 15-英雄展示-单组数据 // // Created by 鲁军 on 2021/2/3. //#impo ...

最新文章

  1. 如何入门自动控制理论
  2. oracle数据库连接时报12514_Oracle 数据库 SQLPlus连接正常、PLSQL连接报错 ORA-12514、TNSPING正常...
  3. ubuntu 配置mycat
  4. xen虚拟机管理xm的用法
  5. 小甲鱼 OllyDbg 教程系列 (十二) : inline patch ( 内嵌补丁 ) 之 调用堆栈查找法
  6. java占位符填充_Java使用freemark生成word
  7. spring AOP 讲解
  8. tailf 命令安装
  9. 机器学习基础(八)——感知机(iterative optimization)
  10. win10 桌面设置为远程桌面
  11. c#时间 转换成java_Java与C#时间转换
  12. 为什么要从 Microsoft Store 下载 Visual Studio/VS Code?
  13. st8s003 c语言编译器,STM8S系列单片机stm8s003f3p6性能介绍
  14. 165个站长在线工具箱网站源码/野兔在线工具系统V2.2.7中文版
  15. java jpg转换tif_JAVA 实现jpg/tif/bmp 等图片之间格式得互相转换
  16. 计算机图形点阵表示实例,计算机图形学的应用实例(计算机图形作业)精选.doc
  17. 多路耦合器(有源分离器)在无线通讯中的应用
  18. java1.8新特性之stream流式算法
  19. 好用全面的电商评论文本情感分析实战教程
  20. 领域驱动设计——项目分层与项目落地

热门文章

  1. 功能测试数据测试之错误推测方法
  2. 群晖 重启 mysql_群晖nas修改MariaDB配置文件
  3. Python如何按下指定按键后执行特定的操作
  4. 网易微专业java高级笔记_网易微专业java高级开发工程师
  5. 16年“折腾史” | 盘点联想手机成与败
  6. ping服务器地址显示TTL传输中过期,ping公网固定IP出现: TTL 传输中过期,怎么处理?...
  7. 向量线性无关和正交及其关系
  8. 软考常用计算公式及理解
  9. 推荐3个干净、资源多的看剧网站给大家
  10. [网络性能测试学习笔记] 测试AX3 Pro WiFi6无线路由器的系统转发能力(硬件转发交换能力L23吞吐量,L47应用层能力-最大可支持设备用户数,并发连接数等)