iOS(AppStore)手游SDK客户端对接文档
本文档是小雪球发行商将游戏发行到 AppStore 的客户端的对接文档,需要游戏开发商对接和使用。SDK中不仅包含玩家登录和内购支付等功能,还包括其他比如个人中心、角色信息上报等方法。该文为iOS客户端接入本SDK的使用教程,只涉及SDK的使用方法,默认读者已经熟悉IDE的基本使用方法(本文以XCode为例),以及具有相应的编程知识基础等。
1. 准备阶段
请先阅读《SDK接入相关文件及参数介绍》和《SDK接入数据交互流程图》,之后将SDK需要游戏服务端提供的接口地址以及游戏内购商品列表提供给小雪球后,方可开始游戏与SDK的对接与联调。
2. SDK导入与配置
2.1 依赖库导入
小雪球SDK直接导入
在SDK下载界面中直接下载iOS(AppStore)的SDK包压缩文件。
将其中的SNBGameSDK.framework
和SNBGameRES.bundle
引入到游戏的XCode项目中。
注意
XCode的版本必须大于或者等于13.3.1
三方依赖库Swift Package Manager(SPM)导入
导入步骤
- 在Xcode中,点击
File (文件) > Swift Packages (Swift 软件包) > Add Package Dependency (添加软件包依赖项)
- 在出现的对话框中,输入如下存储库网址,并选择最新稳定版本
- 当导入Firebase相关的库时,选择
Analytics
、Messaging
和Crashlytics
库
原生iOS框架导入
以下原生framework需要在xcode中引入
- AdSupport
- iAd
- AppTrackingTransparency
- AdServices (V6.1.3+)
- AVFoundation
- WebKit
- libsqlite3.dylib
- libresolv.tbd
- libc++.tbd
2.2 info.plist配置
在info.plist
配置文件中添加以下配置
<key>SNB_INSTANCE_KEY</key>
<string>{SNB_INSTANCE_KEY}</string>
<key>SNB_API_PREFIX</key>
<string>{SNB_API_PREFIX}</string>
<key>SNB_PAGE_PRIVACY_URL</key>
<string>{SNB_PAGE_PRIVACY_URL}</string>
<key>SNB_PAGE_USERAGREEMENT_URL</key>
<string>{SNB_PAGE_USERAGREEMENT_URL}</string>
<key>SNB_PAGE_HELP_URL</key>
<string>{SNB_PAGE_HELP_URL}</string>
<key>SNB_PAGE_FB_HOME_URL</key>
<string>{SNB_PAGE_FB_HOME_URL}</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fb{FACEBOOK_APP_ID}</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>{GOOGLE_REVERSED_CLIENT_ID}</string>
</array>
</dict>
</array>
<key>GOOGLE_CLIENT_ID</key>
<string>{GOOGLE_CLIENT_ID}</string>
<key>FacebookAppID</key>
<string>{FACEBOOK_APP_ID}</string>
<key>FacebookClientToken</key>
<string>{FACEBOOK_CLIENT_TOKEN}</string>
<key>FacebookDisplayName</key>
<string>{FACEBOOK_DISPLAY_NAME}</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
</array>
<key>APPSFLYER_DEV_KEY</key>
<string>{APPSFLYER_DEV_KEY}</string>
<key>APPLE_APP_ID</key>
<string>{APPLE_APP_ID}</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSUserTrackingUsageDescription</key>
<string>若您允許追蹤,本服務所收集到的客户資料將有助於提升應用程式的品質。並且也會用於改善各種活動的通知。為了提供更好的服務,希望可以允許追蹤。追蹤設定可於設備的設定當中隨時進行變更。</string>
注意
将小雪球提供的配置参数信息表中的值替换进上面{xxx}
中,具体参数对应的说明请参考参数配置
2.3 GoogleService-Info.plist文件
将Firebase的配置文件GoogleService-Info.plist
移至Xcode项目的根目录中。
2.4 其他配置信息
开启三方静态库
在TARGET -> Build Settings -> Linking -> Other Liker Flags
中添加-ObjC
关闭bitcode
将TARGET -> Build Settings -> Build Options -> Enable Bitcode
设置成No
2.5 资源配置
图标icon配置
配置游戏各像素icon图标,图片尺寸列表如下:
图片尺寸 |
---|
20×20|29×29|40×40|58×58|60×60|76×76|80×80|87×87|120×120|152×152|167×167|180×180|1024×1024 |
注意
图片的格式为不带透明图层的PNG文件
3. SDK接入
3.1 重要方法重写
重写AppDelegate
的openURL
、applicationDidBecomeActive
以及continueUserActivity
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
//...
// 如果iOS SDK版本小于9
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
//...
return [[SnowBallSDK sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}
// 如果iOS SDK版本大于或等于9
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
//...
return [[SnowBallSDK sharedInstance] application:application openURL:url options:options];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
//...
// iOS14及以上版本需要先请求权限
if (@available(iOS 14, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
}];
}
[[SnowBallSDK sharedInstance] applicationDidBecomeActive:application];
//...
}
// 如果iOS SDK版本大于或等于9
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{
//...
return [[SnowBallSDK sharedInstance] application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//...
[[SnowBallSDK sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
//...
return YES;
}
// Report Push Notification attribution data for re-engagements
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//...
[[SnowBallSDK sharedInstance] application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
//...
}
3.2 SDK初始化
注意
- SDK初始化后才能正确调用其他接口
- 建议在游戏主
AppDelegate.m
的开始处如didFinishLaunchingWithOptions
方法中进行
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//...
/**
初始化
参数: 无
返回: 无
*/
[[SnowBallSDK sharedInstance] initSDK];
//...
return YES;
}
3.3 玩家登录
3.4 玩家登出/切换账户
注意
- 本接口必须在账户登录成功后才能调用
3.5 游戏内购物品支付
注意
- 本接口中sign签名请参考游戏内购订单验证过程和发送接口中的游戏创建内购订单部分。为了保障支付的安全性,签名计算请在游戏服务端中进行,保证
instanceSecret
不被非法破解获取。 - 本接口必须在账户登录成功后才能调用
SnowBallIapRequest *iapReq = [[SnowBallIapRequest alloc] init];
[iapReq setInstanceKey:@"SDK应用实例key"];
[iapReq setUid:@"账户uid"];
[iapReq setToken:@"账户登录后的token"];
[iapReq setProductId:@"内购商品id"];
[iapReq setProductName:@"内购商品名称"];
[iapReq setRoleId:@"角色id"];
[iapReq setRoleName:@"角色名称"];
[iapReq setServerId:@"游戏服id"];
[iapReq setServerName:@"游戏服名称"];
[iapReq setAmount:@"商品金额,比如0.99"];
[iapReq setCurrency:@"货币类型,比如USD"];
[iapReq setGameOrderId:@"游戏生成的订单号"];
[iapReq setExtra:@"透传参数,订单成功后原样返回"]; //选填
[iapReq setNotifyUrl:@"游戏内购物品发送通知地址"]; //选填
[iapReq setSign:@"游戏生成的sign"];
/**
游戏内购物品支付
参数:
- iapReq: 类型SnowBallIapRequest
返回: 无
*/
[[SnowBallSDK sharedInstance] inAppPay:iapReq];
3.6 上报角色信息
以下3种情况下上报
- 创造角色
- 角色进入游戏
- 角色升级
SnowBallRoleInfo *roleInfo = [[SnowBallRoleInfo alloc] init];
[roleInfo setRoleId:@"角色id"];
[roleInfo setRoleName:@"角色名"];
[roleInfo setRoleLevel:@"角色等级"];
[roleInfo setVipLevel:@"角色VIP等级,可为空"];
[roleInfo setServerId:@"游戏服id"];
[roleInfo setServerName:@"游戏服名"];
// 上报枚举类型:
// - InfoType.CREATE: 创角色
// - InfoType.ENTER: 进入游戏
// - InfoType.UPGRADE: 升级
[roleInfo setType:InfoType.CREATE];
/**
上报角色信息
参数:
- roleInfo: 类型SnowBallRoleInfo
返回: 无
*/
[[SnowBallSDK sharedInstance] reportRoleInfo:roleInfo];
3.7 打开用户中心
注意
- 游戏设置界面中,需要加入用户中心菜单,点击后调用该接口
3.8 打开其他H5窗口
注意
- 该接口为选接
- 游戏中如果需要调用以下接口,需要在游戏中实现该功能的菜单按钮
// 打开隐私政策页面
[[SnowBallSDK sharedInstance] openExtraPage:PRIVACY_POLICY];
// 打开用户协议页面
[[SnowBallSDK sharedInstance] openExtraPage:USER_AGREEMENT];
// 打开帮助中心页面
[[SnowBallSDK sharedInstance] openExtraPage:HELP_CENTER];
// 打开Facebook社区页面
[[SnowBallSDK sharedInstance] openExtraPage:FACEBOOK_HOMEPAGE];
3.9 全局事件回调
注意
- 在游戏界面显示时,给SDK设置可以依附的
UIViewController
对象,并在该类文件增加SnowBallSDKGlobalDelegate
协议 - 请在此协议中实现游戏的初始化、登录、注销、支付的返回逻辑
- 登录成功后获得的相关信息,需要传到游戏服务端进行sign验证,具体说明请参考游戏登录信息验证
- 支付成功后获得的相关信息,需要传到游戏服务端进行sign验证,具体说明请参考游戏内购订单验证过程和发送接口中的客户端返回SDK订单信息验证方式部分
#import <Foundation/Foundation.h>
//...
@interface ViewController () <SnowBallSDKGlobalDelegate>
@end
//...
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置回调主体
[[SnowBallSDK sharedInstance] setDelegate:self];
}
// 初始化回调
- (void)SnowBallInitCallback:(SnowBallCallbackCode)code andMsg:(NSString *)msg {
if (SnowBallCodeSuc == code) {
//初始化成功
NSLog(@"初始化成功");
} else {
//初始化失败
NSLog(@"初始化失败,msg=%@", msg);
}
}
// 登录回调
- (void)SnowBallLoginCallback:(SnowBallCallbackCode)code andMsg:(NSString *)msg andUser:(NSString *)userInfo {
if (SnowBallCodeSuc == code) {
//登录成功,将以下信息传入游戏服务端进行sign验证
NSLog(@"登录成功");
NSData *userData = [userInfo dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
id userObject = [NSJSONSerialization JSONObjectWithData:userData options:NSJSONReadingMutableContainers error:&error];
NSString *uid = [userObject valueForKey:@"uid"]; //SDK账户uid
NSString *userType = [userObject valueForKey:@"userType"]; //用户类型
NSString *instanceKey = [userObject valueForKey:@"instanceKey"]; //SDK应用实例key
NSString *displayName = [userObject valueForKey:@"displayName"]; //用户显示名称
NSString *token = [userObject valueForKey:@"token"]; //用户登录token
int expire = [[userObject valueForKey:@"expire"] intValue]; //用户登录失效时间戳
NSString *avatarUrl = [userObject valueForKey:@"avatarUrl"]; //用户头像地址
int firstLogin = [[userObject valueForKey:@"firstLogin"] intValue]; //是否新用户;1-是,0-否
int preRegister = [[userObject valueForKey:@"preRegister"] intValue]; //是否预注册用户;0-非,1-官网预注册,2-市场预注册
NSString *sessionId = [userObject valueForKey:@"sessionId"]; //登录session
NSString *sign = [userObject valueForKey:@"sign"]; //签名
// TODO 传入到服务端验证
} else if (SnowBallCodeFail == code) {
//登录失败
NSLog(@"登录失败:%@", msg);
} else if (SnowBallCodeCancel == code) {
//登录取消
NSLog(@"登录取消:%@", msg);
} else if (SnowBallCodeTimeOut == code) {
//登录超时
NSLog(@"登录超时:%@", msg);
}
}
// 支付回调
- (void)SnowBallPayCallback:(SnowBallCallbackCode)code andMsg:(NSString *)msg andOrder:(NSString *)iapOrder {
if (SnowBallCodeSuc == code) {
//支付成功,将以下信息传入游戏服务端进行sign验证,验证成功,给玩家发货
NSLog(@"支付成功");
NSData *orderData = [iapOrder dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
id orderObject = [NSJSONSerialization JSONObjectWithData:orderData options:NSJSONReadingMutableContainers error:&error];
NSString *orderType = [orderObject valueForKey:@"orderType"]; //订单类型
NSString *orderId = [orderObject valueForKey:@"orderId"]; //SDK订单号
NSString *instanceKey = [orderObject valueForKey:@"instanceKey"]; //SDK应用实例key
int sandbox = [[orderObject valueForKey:@"uid"] intValue]; //是否沙盒支付;1-是,0-否
NSString *productId = [orderObject valueForKey:@"productId"]; //内购商品id
NSString *realPrice = [orderObject valueForKey:@"realPrice"]; //实付金额
NSString *realCurrency = [orderObject valueForKey:@"realCurrency"]; //实付使用货币
int ts = [[orderObject valueForKey:@"uid"] intValue]; //订单时间戳
NSString *gameOrderId = [orderObject valueForKey:@"gameOrderId"]; //游戏生成的订单号
NSString *sign = [orderObject valueForKey:@"sign"]; //签名
// TODO 传入到服务端验证
} else if (SnowBallCodeFail == code) {
//支付失败
NSLog(@"支付失败,msg=%@", msg);
} else if (SnowBallCodeCancel == code) {
//支付取消
NSLog(@"支付取消,msg=%@", msg);
}
}
// 登出回调
- (void)SnowBallLogoutCallback:(SnowBallCallbackCode)code andMsg:(NSString *)msg {
if (SnowBallCodeSuc == code) {
//注销成功
NSLog(@"注销成功");
} else if (SnowBallCodeKickOut == code) {
//SDK后台踢玩家下线
NSLog(@"SDK后台踢玩家下线,msg=%@", msg);
} else if (SnowBallCodeFail == code) {
//登出失败
NSLog(@"登出失败,msg=%@", msg);
}
}
@end
3.10 全局属性获取
在游戏对接过程中,需要使用到SDK提供的各种配置和参数值。