跳转至

iOS(AppStore)手游SDK客户端对接文档

本文档是小雪球发行商将游戏发行到 AppStore 的客户端的对接文档,需要游戏开发商对接和使用。SDK中不仅包含玩家登录和内购支付等功能,还包括其他比如个人中心、角色信息上报等方法。该文为iOS客户端接入本SDK的使用教程,只涉及SDK的使用方法,默认读者已经熟悉IDE的基本使用方法(本文以XCode为例),以及具有相应的编程知识基础等。


1. 准备阶段

请先阅读《SDK接入相关文件及参数介绍》和《SDK接入数据交互流程图》,之后将SDK需要游戏服务端提供的接口地址以及游戏内购商品列表提供给小雪球后,方可开始游戏与SDK的对接与联调。

2. SDK导入与配置

2.1 依赖库导入

小雪球SDK直接导入

SDK下载界面中直接下载iOS(AppStore)的SDK包压缩文件。

压缩包
  | --- SDK/
  | ------SnowBallSDK.framework
  | ------SnowBallBundle.bundle
  ...

将其中的SNBGameSDK.frameworkSNBGameRES.bundle引入到游戏的XCode项目中。

注意

XCode的版本必须大于或者等于13.3.1

三方依赖库Swift Package Manager(SPM)导入

导入步骤

  1. 在Xcode中,点击File (文件) > Swift Packages (Swift 软件包) > Add Package Dependency (添加软件包依赖项)
  2. 在出现的对话框中,输入如下存储库网址,并选择最新稳定版本
    // Google登录库
    https://github.com/google/GoogleSignIn-iOS
    
    // Facebook登录库
    https://github.com/facebook/facebook-ios-sdk
    
    // Appsflyer广告监测
    https://github.com/AppsFlyerSDK/AppsFlyerFramework
    
    // Firebase
    https://github.com/firebase/firebase-ios-sdk
    
  3. 当导入Firebase相关的库时,选择AnalyticsMessagingCrashlytics

原生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接入

注意

  • 以下所有接口使用前,必须引入header文件
    #import <SnowBallSDK/SnowBallSDK.h>
    

3.1 重要方法重写

重写AppDelegateopenURLapplicationDidBecomeActive以及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方法中进行
SDK初始化代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //...

    /**
     初始化
     参数: 无
     返回: 无
     */
    [[SnowBallSDK sharedInstance] initSDK];

    //...
    return YES;
}

3.3 玩家登录

玩家登录代码
/**
 玩家登录
 参数: 无
 返回: 无
*/
[[SnowBallSDK sharedInstance] login];

3.4 玩家登出/切换账户

注意

  • 本接口必须在账户登录成功后才能调用
玩家登出代码
/**
 玩家登出
 参数: 无
 返回: 无
*/
[[SnowBallSDK sharedInstance] logout];

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 打开用户中心

注意

  • 游戏设置界面中,需要加入用户中心菜单,点击后调用该接口
打开用户中心代码
/**
 打开用户中心
 参数: 无
 返回: 无
*/
[[SnowBallSDK sharedInstance] openUserCenter];

3.8 打开其他H5窗口

注意

  • 该接口为选接
  • 游戏中如果需要调用以下接口,需要在游戏中实现该功能的菜单按钮
打开其他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提供的各种配置和参数值。

全局属性获取代码
// 获取SDK的应用实例key
NSString *instanceKey = [[SnowBallSDK sharedInstance] getInstanceKey];

// 获取当前游戏是否是提审版本(初始化成功后才能获取)
// YES: 正在提审
// NO: 非提审
BOOL reviewStatus = [[SnowBallSDK sharedInstance] getReviewStatus];

// 获取SDK账户唯一uid(登录成功后才能获取)
NSString *uid = [[SnowBallSDK sharedInstance] getUid];