跳到主要内容

XDSDK v7 iOS 快速接入指南

· 阅读需 9 分钟

环境要求

  • 国内最低 iOS 11.0,海外最低 iOS 15.0。
  • XCode 26 或更高版本。

配置

XDSDK iOS 原生接入支持 SPM 和 framework 压缩包两种方式,推荐优先使用 SPM 接入。

通过 SPM 集成

  1. 在 Xcode 中打开项目,选择 File > Add Package Dependencies...
  2. 在搜索框中填入 XDSDK SPM 仓库地址:
    • 可以访问 GitHub 时使用:https://github.com/xindong/XDSDK-SPM
    • 无法稳定访问 GitHub 时使用国内托管地址:https://gitcode.com/XDSDK/XDSDK-SPM
  3. 选择需要接入的版本,具体版本请以更新日志中的当前 XDSDK 版本为准。
  4. Add to Target 中选择游戏 App Target,并按需勾选需要的 Package Product。
  5. 准备 XDConfig.json 参数文件,具体方式见下方参数文件
  6. 在 App Target 中添加 SPM 提供的 Run Script Build Phases,用于复制 SDK 资源并根据 XDConfig.json 自动配置 Info.plist 参数。

SPM 仓库内置了脚本用于自动完成部分 Xcode 配置,请直接从 SPM checkout 目录调用脚本,不需要复制脚本到游戏工程。

复制资源

在 App Target > Build Phases 中添加 Run Script Phase,命名为 Copy XDSDK Resources,用于复制 SDK bundle 资源:

SCRIPT_PATH="${BUILD_DIR%/Build/*}/SourcePackages/checkouts/XDSDK-SPM/Scripts/copy_xdsdk_resources.sh"
if [[ -f "$SCRIPT_PATH" ]]; then
bash "$SCRIPT_PATH"
else
echo "warning: XDSDK SPM resource script not found at $SCRIPT_PATH"
fi

请将该 Phase 放在 Build Phases 末尾(位于 Embed Frameworks / [CP] Embed Pods Frameworks 之后),取消勾选 Based on dependency analysis,并在 Build Settings 中将 User Script SandboxingENABLE_USER_SCRIPT_SANDBOXING)设置为 NO

自动配置 Info.plist

添加 Run Script Phase,命名为 Configure XDSDK Info.plist,用于读取 XDConfig.json 并自动写入 CFBundleURLTypesLSApplicationQueriesSchemes 以及 Facebook 所需的顶层字段:

SCRIPT_PATH="${BUILD_DIR%/Build/*}/SourcePackages/checkouts/XDSDK-SPM/Scripts/configure_xdsdk_info_plist.py"
if [[ -f "$SCRIPT_PATH" ]]; then
/usr/bin/env python3 "$SCRIPT_PATH"
else
echo "warning: XDSDK SPM info-plist script not found at $SCRIPT_PATH"
fi

请将该 Phase 放在 Compile Sources 之前,取消勾选 Based on dependency analysis,并将 User Script Sandboxing 设置为 NO。脚本默认从 ${SRCROOT}/${PRODUCT_NAME}/XDConfig.json 读取配置;如果配置文件放在其他路径,请在 Run Script 环境变量中设置 XDSDK_CONFIG_PATH=/absolute/path/XDConfig.json

提示

使用 SPM 自动配置脚本后,如需调整脚本生成的配置,请修改 XDConfig.json,不要手动编辑对应的 Info.plist 字段。

备注

GitHub 与 GitCode 托管的是同一套 XDSDK SPM 依赖,选择其中一个可稳定访问的地址即可。

通过 Framework 集成

  1. 请联系平台同事获取最新的 SDK 压缩包,解压后选择需要的 framework 和 bundle 导入到您的项目中。
  2. 压缩包分为 ThirdSDKXDSDK 两部分,所有的 framework 均为动态库,导入后请设置为 Embed & Sign

必选项:

  • XDAccountSDK.framework(登录)
  • XDPaymentSDK.framework(支付)
  • XDCommonSDK.framework(基础库)
  • XDTapSDK4WrapperSDK.framework(TapSDK 封装库)
  • TapTapMomentResource.bundle(TapTap 资源包)
  • TapTapLoginResource.bundle(TapTap 资源包)
  • TapTapComplianceResource.bundle(TapTap 资源包)
  • TapTapAchievementResource.bundle(TapTap 资源包)

可选项:

  • XDCNWrapper.framework(国内三方 SDK,按需添加)
  • XDGlobalWrapper.framework(海外三方 SDK,按需添加)

参数文件

将给到的参数配置文件名改为 XDConfig.json,导入到 XCode 工程中。

备注

如果使用 Google 登录或 Firebase 埋点,请在 Firebase 后台下载 GoogleService-Info.plist 并添加到项目中。

添加系统依赖库

请检查项目中是否已自动添加以下依赖项:

LocalAuthentication.framework
AuthenticationServices.framework
SystemConfiguration.framework
Accelerate.framework
SafariServices.framework
Webkit.framework
CoreTelephony.framework
Security.framework
libc++.tdb
AVFoundation.framework
AdServices.framework
提示
  • AdServices.framework 需要在 Build Phases → Link Binary With Libraries 中设置为 Optional。
  • AuthenticationServices.framework iOS 12 以上才支持,建议设置为 Optional。

配置编译选项

Build Setting 中的 Other Link Flag 中添加 -ObjC

配置 URL Types 与 Schemes

如果通过 SPM 接入且已添加 Configure XDSDK Info.plist 脚本,CFBundleURLTypesLSApplicationQueriesSchemes 等字段会由脚本根据 XDConfig.json 自动写入,无需手动维护。

通过 Framework 接入或未使用脚本时,需要手动配置 URL Types(详细内容请咨询平台同事),并在应用的 info.plist 中配置以下 LSApplicationQueriesSchemes

<key>LSApplicationQueriesSchemes</key>
<array>
<string>sinaweibo</string>
<string>weibosdk</string>
<string>weibosdk2.5</string>
<string>weibosdk3.3</string>
<string>mqqopensdkapiV2</string>
<string>mqq</string>
<string>mqqapi</string>
<string>tim</string>
<string>mqqopensdknopasteboard</string>
<string>weixin</string>
<string>weixinULAPI</string>
<string>weixinURLParamsAPI</string>
<string>tapsdk</string>
<string>tapiosdk</string>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
<string>lineauth2</string>
<string>twitterauth</string>
<string>xhsdiscover</string>
<string>douyinopensdk</string>
<string>douyinliteopensdk</string>
<string>douyinsharesdk</string>
<string>snssdk1128</string>
<string>taptap</string>
<string>tiktokopensdk</string>
<string>tiktoksharesdk</string>
<string>snssdk1180</string>
<string>snssdk1233</string>
<string>instagram</string>
<string>kwai</string>
<string>kwaiAuth2</string>
<string>kwaiopenapi</string>
<string>KwaiBundleToken</string>
<string>kwai.clip.multi</string>
<string>KwaiSDKMediaV2</string>
<string>ksnebula</string>
</array>

配置权限列表

SDK 涉及到的权限请求如下:

权限说明配置方式备注
相机权限在 info.plist 中配置 NSCameraUsageDescription 及描述文案。如:请允许 xxx 获取并使用您的相机。客服页面可能需要拍摄相关照片或视频
麦克风权限在 info.plist 中配置 NSMicrophoneUsageDescription 及描述文案。如:请允许 xxx 获取并使用您的麦克风。客服页面可能需要拍摄相关视频
相册权限在 info.plist 中配置 NSPhotoLibraryAddUsageDescription 及描述文案。如:请允许 xxx 获取并使用您的相册。客服页面可能需要访问照片

配置 IDFA

如果您的应用需要打开 IDFA,则需要:

  1. XDConfig.json 中将 idfa_enabled 设置为 true
  2. 在应用中导入下列系统库:
    AdSupport.framework
    AppTrackingTransparency.framework -> 需要在 Build Phases - Link Binary With Libraries 中设置为 Optional
  3. info.plist 中配置 NSUserTrackingUsageDescription 及对应的文案。

做完上述配置后应用会在您调用初始化时自动尝试请求获取 IDFA 权限,此时会弹出系统的隐私权限请求弹窗。

配置 App 所需能力

Capabilities 中按需打开 In-App PurchasePush NotificationsSign In With Apple 等功能。

配置 AppDelegate

在项目中实现了 UIApplicationDelegate 协议的类中引入头文件,并将系统回调转发给 SDK:

#import <XDCommonSDK/XDCommonSDK.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...其他初始化代码

[XDGSDK application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[XDGSDK application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
[XDGSDK application:app openURL:url options:options];
return YES;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
[XDGSDK application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
return YES;
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[XDGSDK application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

@end
提示

请确保在 didFinishLaunchingWithOptions 中尽早调用 [XDGSDK application:application didFinishLaunchingWithOptions:launchOptions],其余回调方法也需要正确转发,否则可能影响登录、支付、推送等功能。

初始化

初始化SDK

  • 请将初始化代码放在尽可能靠前的位置,在初始化成功前请不要绘制登录相关的界面。
  • 如果初始化失败一般为配置问题,请根据错误信息检查配置是否正确或者咨询平台。
  • 初始化成功前大部分接口都不可使用。
#import <XDCommonSDK/XDCommonSDK.h>

XDGInitParam *initParam = [XDGInitParam new];
// 语言和渠道根据实际情况设置
initParam.lang = XDGLanguageLocaleEnglish;
initParam.channel = @"AP";
// 可选:游戏自定义包体阶段参数,默认为空
initParam.gamePhase = @"release";
// db 参数可透传给 TapDB 的 device_login/user_login 事件
NSMutableDictionary *dbProperties = [NSMutableDictionary dictionary];
[dbProperties setValue:@"demo_extra_value" forKey:@"demo_extra_key"];
initParam.dbProperties = dbProperties;
[XDGSDK initSDK:initParam
handler:^(BOOL success, NSString *msg) {
if (success) {
NSLog(@"初始化成功");
} else {
NSLog(@"初始化失败:%@", msg);
}
}];

// 判断是否初始化完成
BOOL isInitialized = [XDGSDK isInitialized];

修改多语言

在初始化后可根据需要修改 SDK 语言。

#import <XDCommonSDK/XDCommonSDK.h>

/** 设置 SDK 显示语言
* @param locale 语言,在 XDGLanguageLocale 枚举中查看
*/
[XDGSDK setLanguage:XDGLanguageLocaleSimplifiedChinese];

登录

  • 在初始化成功后可以进入登录页面但暂时先不要绘制登录按钮,先设置好用户状态回调并调用自动登录,如果自动登录失败再绘制登录按钮。
  • 登录按钮点击后调用手动登录接口,需要传入对应的登录类型。登录失败后需要继续展示登录按钮让用户重新登录。
  • 自动登录在每次打开游戏时只能触发一次,失败后只能调用手动登录接口。
  • 收到用户退出登录的回调时需要回到登录页面并展示登录按钮。此时不要再调用自动登录接口。

状态回调

  • 需要在初始化前设置好
typedef NS_ENUM(NSInteger, XDGUserStateChangeCode) {
XDGUserStateChangeCodeLogout = 0, // 用户登出
XDGUserStateChangeCodeBindSuccess = 1, // 用户绑定成功,msg = 登录类型字符串,例如:@"TAPTAP"
XDGUserStateChangeCodeUnBindSuccess = 2, // 用户解绑成功,msg = 登录类型字符串
XDGUserStateChangeCodeProtocolAgreedAfterLogout = 3, // 用户在登出后点击确认同意协议
XDGUserStateChangeCodeSupportNoUnread = 4, // 客服中心没有未读消息
XDGUserStateChangeCodeSupportHasUnread = 5, // 客服中心有未读消息
};

[XDGAccount addUserStatusChangeCallback:^(XDGUserStateChangeCode userStateChangeCode, NSString *message) {
if (userStateChangeCode == XDGUserStateChangeCodeBindSuccess) {
// 绑定新平台成功
} else if (userStateChangeCode == XDGUserStateChangeCodeUnBindSuccess) {
// 解绑平台成功
} else if (userStateChangeCode == XDGUserStateChangeCodeLogout) {
// 用户退出登录
} else if (userStateChangeCode == XDGUserStateChangeCodeProtocolAgreedAfterLogout) {
// 用户退出登录后点击同意协议
} else if (userStateChangeCode == XDGUserStateChangeCodeSupportNoUnread) {
// 客服中心没有未读消息
} else if (userStateChangeCode == XDGUserStateChangeCodeSupportHasUnread) {
// 客服中心有未读消息
}
}];

发起登录

LoginEntryTypeDefault (自动登录)
LoginEntryTypeTapTap
LoginEntryTypeApple
LoginEntryTypeGoogle
LoginEntryTypeFacebook
LoginEntryTypeLine
LoginEntryTypeTwitter
LoginEntryTypeSteam
LoginEntryTypeGuest
LoginEntryTypePhone
LoginEntryTypeEmail

LoginEntryType type = LoginEntryTypeDefault;
[XDGAccount loginByType:type loginHandler:^(XDGUser * _Nullable result, NSError * _Nullable error) {
if (error) {
// 登录失败
// error.code (错误码,用来区分类型)
// error.localizedDescription (可以用来展示给用户的错误原因文案)
} else {
// 登陆成功
NSString *xdUserID = result.userId; // result.userId 为用户在 XD 账户系统的 XD User ID(用户唯一标识)
NSString *name = result.name;
NSString *nickName = result.nickName;
NSString *avatar = result.avatar;
}
}];

用户中心

[XDGAccount openUserCenter];

退出登录

[XDGAccount logout];

账号注销

[XDGAccount openAccountDeletion];

打开客服

XDGRoleInfo *role = [XDGRoleInfo new];
role.roleId = roleId; // 必填
role.roleName = roleName; // 必填
role.serverId = serverId; // 必填
NSString *pathStr = @"客服内的相对路径,一般留空即可";
NSDictionary *paramsDic = @{@"自定义参数 key":@"自定义参数 value"};
[XDGAccount openCustomerService:role path:pathStr params:paramsDic];

个人信息页

仅限国内可使用

XDGRoleInfo *roleInfo = [XDGRoleInfo new];
roleInfo.roleId = roleId; // 必填
roleInfo.roleName = roleName; // 必填
roleInfo.roleLevel = roleLevel; // 必填
roleInfo.serverId = serverId; // 必填
[XDGAccount openUserDashboard:roleInfo];

内购

查询商品价格

  • 在查询商品价格前请在后台配置好对应的商品信息。
  • 使用 App Store 的商品 ID 进行查询。
NSArray *procudtIds = @[@"com.xd.sdkdemo1.stone30", @"com.xd.sdkdemo1.stone50"];
[XDGPayment queryWithProductIds:procudtIds completionHandler:^(NSArray<XDGProductInfo *> * _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"查询失败 %@", error);
} else {
for (XDGProductInfo *product in result) {
// 商品 ID
NSString *productId = product.productIdentifier;
// 展示价格(拼接好的完整货币符号和价格文本)
NSString *displayPrice = product.displayPrice;
}
}
}];

发起内购

XDGPaymentParams *params = [XDGPaymentParams new];
params.gameOrderId = @"可选,游戏侧订单号,不填会自动生成随机订单号";
params.productId = @"必须,在苹果后台配置的商品 ID";
params.roleId = @"必须,角色 ID";
params.serverId = @"必须,服务器 ID";
params.extra = @"可选,透传参数";
params.quantity = 1; // 购买数量,限制为 1-10

[XDGPayment payWithParams:params completionHandler:^(XDGOrderInfo * _Nullable orderInfo, NSError * _Nullable error) {
if (error) {
// 支付失败
} else {
// 支付成功
}
}];

查询 Apple 未消费订单

  • 仅 Apple 平台可用。
  • 查询到的订单可能是用户之前购买成功但未成功消费的订单,也可能是 App Store 中兑换的礼包码订单。
[XDGPayment queryPendingPurchases:^(NSArray<XDGPendingPurchase *> * _Nonnull result) {
for (XDGPendingPurchase *purchase in result) {
NSString *productId = purchase.productId; // 商品ID
NSString *purchaseToken = purchase.pendingPurchaseToken; // 订单标识符
}
}];

消费 Apple 未消费订单

XDGPaymentParams *params = [XDGPaymentParams new];
params.gameOrderId = @"可选,游戏侧订单号,不填会自动生成随机订单号";
params.productId = @"必须,在苹果后台配置的商品 ID";
params.roleId = @"必须,角色 ID";
params.serverId = @"必须,服务器 ID";
params.extra = @"可选,透传参数";
params.quantity = 1;
params.pendingPurchaseToken = @"未完成订单标识符,从查询未完成订单接口获取";
[XDGPayment handlePendingPurchase:params completionHandler:^(XDGOrderInfo * _Nullable orderInfo, NSError * _Nullable error) {
if (error) {
// 兑换或补单失败
} else {
// 兑换或补单成功
}
}];

工具

事件上报

#import <XDCommonSDK/XDCommonSDK.h>

/** 跟踪自定义事件
* @param eventName 事件名称
*/
NSString *eventName = @"custom_event_name";
[XDGSDK trackEvent:eventName];

/** 跟踪自定义事件
* @param eventName 事件名称
* @param properties 自定义属性
*/
NSString *eventName2 = @"custom_event_name";
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
[XDGSDK trackEvent:eventName2 properties:properties];

// 跟踪角色信息
XDGRoleInfo *role = [XDGRoleInfo new];
role.roleId = @"your_role_id";
role.roleName = @"your_role_name";
role.roleLevel = 11;
role.serverId = @"your_server_id";
[XDGSDK trackRole:role];

商店评价

#import <XDCommonSDK/XDCommonSDK.h>

[XDGSDK storeReview];

打开网页

#import <XDCommonSDK/XDCommonSDK.h>

[XDGSDK openWebPageWithURL:@"https://活动页面地址" handler:^(XDGWebAction actionType, NSDictionary * _Nullable data) {
if (actionType == XDGWebActionCloseWeb) {
// 网页关闭
} else if (actionType == XDGWebActionMessage) {
// 网页透传消息
NSLog(@"网页透传消息 %@", data);
}
}];

公告

展示公告

展示公告 UI,由 SDK 处理公告的获取和展示。可以在公告后台进行样式自定义。

#import <XDCommonSDK/XDGAnnouncementManager.h>

XDGAnnouncementConfig *config = [XDGAnnouncementConfig new];
config.serverCode = @"1"; // 公告后台配置服务器后生成的代码
config.channel = @"ios"; // 渠道标识
[XDGAnnouncementManager openPageWithConfig:config handler:^(XDGWebAction actionType, NSDictionary * _Nullable data) {
if (actionType == XDGWebActionCloseWeb) {
// 页面关闭时回调
} else if (actionType == XDGWebActionMessage) {
// 页面消息回调
}
}];

检查未读公告

检查是否有未读公告,请不要频繁调用该接口,可能影响性能。

#import <XDCommonSDK/XDGAnnouncementManager.h>

XDGAnnouncementConfig *config = [XDGAnnouncementConfig new];
config.serverCode = @"1"; // 公告后台配置服务器后生成的代码
config.channel = @"ios"; // 渠道标识
[XDGAnnouncementManager requestUnreadWithConfig:config handler:^(_Bool hasRedDot) {
if (hasRedDot) {
// 有未读公告
} else {
// 无未读公告
}
}];

TapSDK

TapSDK 相关能力已由 XDSDK v7 统一封装。游戏侧不需要自行初始化 TapSDK,接入和接口说明请参考 TapSDK iOS 接口