跳到主要内容

XDSDK v7 Android 快速接入指南

· 阅读需 5 分钟

环境要求

  • 最低支持 Android API Level 21(Android 5.0)。
  • 使用 AndroidX

配置

获取 SDK

  1. 请联系平台同事获取最新的 SDK 压缩包,解压后根据需要选择对应的 aar 导入到项目中。
  2. 压缩包分为 XDSDKThirdPartyLibraryADs 三部分,按照添加依赖描述部分进行选择导入。

添加依赖

在项目 build.gradle 中添加 SDK 依赖:

XDSDK 目录

  • XDGCommon_latest.aar(基础库,必须)
  • XDGAccount_latest.aar(登录)
  • XDThirdLoginCN_latest.aar(国内第三方登录支持库)
  • XDGThirdLogin_latest.aar(海外第三方登录支持库)
  • XDGPayment_latest.aar(支付)
  • XDGPaymentUPPay_latest.aar(国内云闪付支付支持库)
  • XDGTapTapWrapperInternal_latest.aar(内部封装 TapSDK 支持库)
  • XDGTapTapWrapper_latest.aar(TapSDK 额外支持库)
  • XDGAnnouncement_latest.aar(公告)

ThirdPartyLibrary 目录

  • ThemisLite-release1.0.7.8.aar(基础库支持,必须)
  • oaid_sdk_xxx.aar(信通院 SDK)

在项目级 build.gradle(.kts) 中 添加远程依赖:

// 基础库依赖
implementation("io.reactivex.rxjava2:rxandroid:2.1.1")
implementation("androidx.appcompat:appcompat:1.3.1")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:adapter-rxjava2:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.7.2")
implementation("com.squareup.okio:okio:2.6.0")
implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("com.google.code.gson:gson:2.8.6")
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.0.0")

//XDSDK 依赖的 TapSDK 库
implementation("com.taptap.sdk:tap-core:4.9.0")
implementation("com.taptap.sdk:tap-login:4.9.0")
implementation("com.taptap.sdk:tap-compliance:4.9.0") // 国内防沉迷
// 支持的额外的 TapSDK 库
implementation("com.taptap.sdk:tap-moment:4.9.0")
implementation("com.taptap.sdk:tap-review:4.9.0")
implementation("com.taptap.sdk:tap-license:4.9.0")
implementation("com.taptap.sdk:tap-update:4.9.0")
// Google Advertising ID
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")

// 支付宝支付
implementation("com.alipay.sdk:alipaysdk-android:15.8.32@aar")
// 微信支付(同微信分享)
implementation("com.tencent.mm.opensdk:wechat-sdk-android:6.8.0")
// 海外支付支持库
implementation("androidx.browser:browser:1.4.0")
备注

具体使用哪些模块以及版本号请和平台同事确认。

参数文件

将给到的参数配置文件名改为 XDConfig.json,放到 app/src/main/assets/ 目录下。

备注

如果使用 Google 登录或 Firebase 埋点,请在 Firebase 后台下载 google-services.json 并添加到 app/ 目录下。

AndroidManifest.xml 配置

海外网页支付

提示

URL Scheme 组成规则:xd + xd_client_id,其中 xd_client_id 为全小写。 eg. : 你的 XD Client ID 为:hn5RcJei2JxCYlS0,在 AndroidManifest.xml 文件中添加的格式为 <data android:scheme="xdhn5rcjei2jxcyls0" />

<activity
android:name="com.xd.intl.payment.ui.SchemeCCTActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>

<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>

<data
android:host="xdcctwebpay"
android:scheme="xd{your_xd_client_id}}"/>
</intent-filter>
</activity>

初始化

初始化 SDK

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

import com.xd.sdk.common.XDGCommon;
import com.xd.sdk.common.base.Lang;
import com.xd.sdk.common.callback.XDGInitCallback;
import com.xd.sdk.common.data.model.InitParams;
import com.xd.sdk.common.data.model.PackageType;

import org.json.JSONObject;

// ...

private void init() {
InitParams initParams = InitParams.newBuilder()
.setPackageType(PackageType.GooglePlay) // 默认: PackageType.Normal
.setLanguage(Lang.EN) // 初始化语言
.setChannelName("GooglePlay") // 初始化渠道,默认为空,SDK 内部会按照读取顺序获取渠道顺序,这里是保留字段,在非广告渠道的自定义。读取广告包配置(仅国内) -> this -> XDConfig.json 配置
.setDBProperties(new JSONObject().put("custom_key", "custom_value")) // db 参数可透传给 TapDB 的 device_login/user_login 事件
.build();

XDGCommon.initSDK(MainActivity.this, initParams, new XDGInitCallback() {
@Override
public void initCallback(boolean success, String message) {
if (success) {
// Success
} else {
// Failure
Log.e("MainActivity", "XDSDK Init failed: " + message);
}
}
});
}

修改多语言

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

// MainActivity.java

import com.xd.sdk.common.XDGCommon;
import com.xd.sdk.common.base.Lang;

// ...

private void setLanguage() {
XDGCommon.setLanguage(Lang.ZH_CN);
}

通用

事件上报

// MainActivity.java

import com.xd.sdk.common.XDGCommon;

import java.util.HashMap;
import java.util.Map;

// ...

private void trackEvent() {
XDGCommon.trackEvent("自定义事件名称");

Map<String, Object> params = new HashMap<>();
params.put("key", "value");
XDGCommon.trackEvent("自定义带参数的事件名称", params);
}

商店评价

商店评价仅支持 Google Play 平台。

// MainActivity.java

import com.xd.sdk.common.XDGCommon;

// ...

private void storeReview() {
XDGCommon.storeReview(MainActivity.this);
}

打开网页

// PaymentActivity.java

import com.xd.sdk.common.XDGCommon;
import com.xd.sdk.common.callback.WebActionCallback;
import com.xd.sdk.common.entities.WebActionType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

// ...

private void openWebPage() {
String activityUrl = "https://www.xindong.com";
XDGCommon.openWebPage(PaymentActivity.this, activityUrl, new WebActionCallback() {
@Override
public void onAction(int type, @Nullable Map<@NotNull String, ?> data) {
if (type == WebActionType.CLOSE) {
// 网页关闭
} else if (type == WebActionType.MESSAGE) {
// 网页透传信息
if (data != null) {
Object value = data.get("key");
}
}
}
});
}

登录

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

状态回调

  • 需要在初始化前设置好
// MainActivity.java

import com.xd.sdk.account.XDGAccount;
import com.xd.sdk.common.callback.XDGUserStatusChangeCallback;

import org.jetbrains.annotations.Nullable;

// ...

private void addUserStatusChangeCallback() {
XDGAccount.addUserStatusChangeCallback(new XDGUserStatusChangeCallback() {
@Override
public void userStatusChange(int code, @Nullable String message) {
if (code == XDGUserStatusChangeCallback.UserStatus.LOGOUT) {
// 退出登录,回到登录页面,展示登录按钮
} else if (code == XDGUserStatusChangeCallback.UserStatus.BIND) {
// 绑定成功,没有更多登录方式可不处理
} else if (code == XDGUserStatusChangeCallback.UserStatus.UNBIND) {
// 解绑成功,没有更多登录方式可不处理
} else if (code == XDGUserStatusChangeCallback.UserStatus.PROTOCOL_AGREED_AFTER_LOGOUT) {
// 退出登录后同意协议,可不处理
} else if (code == XDGUserStatusChangeCallback.UserStatus.CUSTOMER_NO_UNREAD_MESSAGE) {
// 客服有未读消息,未开通服务可以不处理
} else if (code == XDGUserStatusChangeCallback.UserStatus.CUSTOMER_HAS_UNREAD_MESSAGE) {
// 客服没有未读消息,未开通服务可以不处理
} else {
// 未知 Code,不需要处理
}
}
});
}

发起登录

// LoginActivity.java

import android.util.Log;

import com.xd.sdk.account.XDGAccount;
import com.xd.sdk.common.base.XDGError;
import com.xd.sdk.common.bean.XDGUser;
import com.xd.sdk.common.callback.Callback;
import com.xd.sdk.common.entities.LoginEntryType;

import java.util.Map;

// ...

/**
* 登录
*
* LoginEntryType 枚举:
* LoginEntryType.DEFAULT - 自动登录
* LoginEntryType.TAP_TAP - TapTap 登录
* LoginEntryType.APPLE - Apple 登录
* LoginEntryType.GOOGLE - Google 登录
* LoginEntryType.FACEBOOK - Facebook 登录
* LoginEntryType.LINE - LINE 登录
* LoginEntryType.TWITTER - Twitter 登录
* LoginEntryType.STEAM - Steam 登录
* LoginEntryType.GUEST - 游客登录
* LoginEntryType.PHONE - 手机号登录
* LoginEntryType.EMAIL - 邮箱登录
*/
private void loginByType() {
XDGAccount.loginByType(LoginActivity.this, LoginEntryType.TAP_TAP, new Callback<XDGUser>() {
@Override
public void onCallback(XDGUser xdgUser, XDGError xdgError) {
if (xdgUser != null) {
// 登录成功
String userId = xdgUser.getId(); // 用户在 XD 账户系统的 XD User ID(用户唯一标识)
String avatarUrl = xdgUser.getAvatar();
String nickname = xdgUser.getNickName();
return;
}

// 登录失败
if (xdgError != null) {
int code = xdgError.getCode();
String message = xdgError.getMessage();
Log.e("LoginActivity", "XDSDK loginFailed, code=" + code + ", message: " + message);
Map<String, Object> errorDataMap = xdgError.getErrorDataMap();
if (errorDataMap != null) {
// ...
}
}
}
});
}

用户中心

// LoginActivity.java

import com.xd.sdk.account.XDGAccount;

// ...

private void openUserCenter() {
XDGAccount.openUserCenter(LoginActivity.this);
}

退出登录

// LoginActivity.java

import com.xd.sdk.account.XDGAccount;

// ...

private void logout() {
XDGAccount.logout(LoginActivity.this);
}

账号注销

// LoginActivity.java

import com.xd.sdk.account.XDGAccount;

// ...

private void openAccountDeletion() {
XDGAccount.openAccountDeletion(LoginActivity.this);
}

打开客服

// MainActivity.java

import com.xd.sdk.account.XDGAccount;
import com.xd.sdk.common.entities.RoleInfo;

import java.util.HashMap;
import java.util.Map;

// ...

private void openCustomerService() {
RoleInfo roleInfo = RoleInfo.newBuilder()
.setRoleId("game_role_id") // 必填
.setRoleName("game_role_name") // 必填
.setRoleLevel(100)// 必填
.setServerId("game_server_id") // 必填
.setExtra("extra_info")
.build();

String path = ""; // 客服内的相对路径,一般留空即可

Map<String, Object> extrasMap = new HashMap<>();
extrasMap.put("key", "value");

XDGAccount.openCustomerService(MainActivity.this, roleInfo, path, extrasMap);
}

个人信息页

仅限国内可使用

// LoginActivity.java

import com.xd.sdk.account.XDGAccount;
import com.xd.sdk.common.entities.RoleInfo;

// ...

private void openUserDashboard() {
RoleInfo roleInfo = RoleInfo.newBuilder()
.setRoleId("game_role_id") // 必填
.setRoleName("game_role_name") // 必填
.setRoleLevel(100)// 必填
.setServerId("game_server_id") // 必填
.setExtra("extra_info")
.build();
XDGAccount.openUserDashboard(LoginActivity.this, roleInfo);
}

内购

查询商品价格

  • 在查询商品价格前请在后台配置好对应的商品信息。
  • XDConfig.json 配置的 regionTypeGlobal 且初始化参数指定的 packageTypePackageType.GooglePlay 时查询的是 Google 的商品。
  • 其他情况查询的是在平台配置的商品。
// PaymentActivity.java

import com.xd.sdk.common.base.XDGError;
import com.xd.sdk.payment.XDGPayment;
import com.xd.sdk.payment.callback.PaymentResultCallback;
import com.xd.sdk.payment.entities.XDGProductInfo;


import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

// ...

private void queryProducts() {
// 当 XDConfig.json 配置的 regionType 为 Global 且初始化参数指定的 packageType 为 PackageType.GooglePlay 时查询的是 Google 的商品;
// 其他情况查询的是在平台配置的商品
List<String> productIdList = new ArrayList<>();
productIdList.add("product_id_1");
XDGPayment.queryWithProductIds(productIdList, new PaymentResultCallback<List<XDGProductInfo>>() {
@Override
public void onSuccess(@NotNull List<XDGProductInfo> xdgProductInfos) {
if (xdgProductInfos.isEmpty()) {
// 查询商品为空
} else {
// 查询成功
for (XDGProductInfo info : xdgProductInfos) {
String productId = info.getProductId();
String displayPrice = info.getDisplayPrice();
String title = info.getTitle();
String description = info.getDescription();
}
}
}

@Override
public void onError(@NotNull XDGError xdgError) {

}
});
}

发起内购

// PaymentActivity.java

import android.util.Log;

import com.xd.sdk.common.base.XDGError;
import com.xd.sdk.payment.XDGPayment;
import com.xd.sdk.payment.api.XDGPaymentParams;
import com.xd.sdk.payment.callback.PaymentResultCallback;
import com.xd.sdk.payment.entities.XDGOrderInfo;

import org.jetbrains.annotations.NotNull;

// ...

private void payWithParams() {
// 当 XDConfig.json 配置的 regionType 为 CN 发起的是国内支付宝&微信支付;
// regionType 为 Global 时:
// - 初始化参数指定的 packageType 为 PackageType.GooglePlay 时发起的是 Google 结算库购买
// - 其他,发起网页支付
XDGPaymentParams params = XDGPaymentParams.newBuilder()
.setGameOrderId("game_order_id") // 订单 ID
.setProductId("product_id") // 商品 ID
.setRoleId("game_role_id") // 角色 ID
.setServerId("game_server_id") // 服务器 ID
.setExt("extra_info") // 附加信息
.build();
XDGPayment.payWithParams(PaymentActivity.this, params, new PaymentResultCallback<XDGOrderInfo>() {
@Override
public void onSuccess(@NotNull XDGOrderInfo xdgOrderInfo) {
// 支付成功
Log.i("PaymentActivity", "支付订单数据: " + xdgOrderInfo);
}

@Override
public void onError(@NotNull XDGError xdgError) {
// 支付失败
int code = xdgError.getCode();
String message = xdgError.getMessage();
}
});
}

公告

展示公告

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

// AnnouncementActivity.java

import com.xd.sdk.announcement.XDGAnnouncement;
import com.xd.sdk.announcement.domain.model.AnnouncementConfig;
import com.xd.sdk.common.callback.WebActionCallback;
import com.xd.sdk.common.entities.WebActionType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

// ...

private void openPage() {
AnnouncementConfig config = AnnouncementConfig.newBuilder()
.setServerCode("server_code") // 公告后台配置服务器后生成的代码
.setChannel("tap") // 渠道标识
.build();
XDGAnnouncement.openPage(AnnouncementActivity.this, config, new WebActionCallback() {
@Override
public void onAction(int type, @Nullable Map<@NotNull String, ?> data) {
if (type == WebActionType.CLOSE) {
// 页面关闭
} else if (type == WebActionType.MESSAGE) {
// 页面消息
if (data != null) {
Object value = data.get("key");
}
}
}
});
}


检查未读公告

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

// AnnouncementActivity.java

import com.xd.sdk.announcement.XDGAnnouncement;
import com.xd.sdk.announcement.domain.model.AnnouncementConfig;
import com.xd.sdk.common.base.XDGError;
import com.xd.sdk.common.callback.Callback;

// ...

private void requestUnread() {
AnnouncementConfig config = AnnouncementConfig.newBuilder()
.setServerCode("server_code") // 公告后台配置服务器后生成的代码
.setChannel("tap") // 渠道标识
.build();
XDGAnnouncement.requestUnread(ADsActivity.this, config, new Callback<Boolean>() {
@Override
public void onCallback(Boolean aBoolean, XDGError xdgError) {
if (aBoolean) {
// 有未读公告
} else {
// 无未读公告
}
}
});
}


TapSDK 相关内容

请参考 TapSDK 接入文档的使用方式,将方法调用类改为 XDSDK 封装类,以云存档为例:

// TapSDKActivity.java

import androidx.annotation.NonNull;

import com.taptap.sdk.cloudsave.ArchiveData;
import com.taptap.sdk.cloudsave.ArchiveMetadata;
import com.taptap.sdk.cloudsave.internal.TapCloudSaveRequestCallback;

//...

private void createArchive() {
ArchiveMetadata metadata = new ArchiveMetadata.Builder()
.setName("")
.setSummary("")
.setExtra("")
.setPlaytime(0)
.build();
// 存档文件路径(单个存档文件大小不超过10MB)
String archiveFilePath = "path/to/archive/file";
// 存档封面路径(可选,封面大小不超过512KB)
String archiveCoverPath = "path/to/cover/image";

// 请求回调
TapCloudSaveRequestCallback callback = new TapCloudSaveRequestCallback() {

@Override
public void onRequestError(int errorCode, @NonNull String errorMessage) {
// 处理请求错误
}

@Override
public void onArchiveCreated(@NonNull ArchiveData archive) {
// 处理存档创建成功
}
};
XDTapCloudSave.createArchive(metadata, archiveFilePath, archiveCoverPath, callback);
}

XDSDK 封装的 TapSDK 类包括:

XDSDK v7 iOS 快速接入指南

· 阅读需 4 分钟

环境要求

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

配置

导入 SDK

  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

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

初始化

初始化SDK

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

XDGInitParam *initParam = [XDGInitParam new];
// 语言和渠道根据实际情况设置
initParam.lang = XDGLanguageLocaleEnglish;
initParam.channel = @"AP";
// 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.roleLevel = roleLevel; // 必填
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

以下模块均已由 XDSDK 统一封装,游戏无需单独集成对应的 TapSDK,接入请参考 TapTap 文档: 成就 云存档 动态

接入时不要使用 TapSDK 的类和方法,请使用 XDSDK 封装的类和方法:

#import <XDTapSDK4WrapperSDK/XDTapSDK4WrapperSDK.h>

//成就接口 XDGTapTapAchievementWrapper.h
//云存档接口 XDGTapTapCloudSaveWrapper.h
//动态接口 XDGTapTapMomentWrapper.h

XDSDK v7 Unity 快速接入指南

· 阅读需 4 分钟

配置

添加依赖

参考下面内容,在 manifest.json 中添加 SDK 依赖。代码示例为所有模块,具体使用哪些请和平台同事确认。

{
"dependencies": {
"com.xd.sdk.foundation": "7.2.0",
"com.xd.sdk.common": "7.2.0",
"com.xd.sdk.account": "7.2.0",
"com.xd.sdk.payment": "7.2.0",
"com.xd.sdk.mainland": "7.2.0",
"com.xd.sdk.announcement": "7.2.0",
"com.xd.sdk.tap": "4.9.0-xd.1",
"com.xd.sdk.tap.plus": "4.9.0-xd.1"
},
"scopedRegistries": [
{
"name": "NPMJS",
"url": "https://registry.npmmirror.com",
"scopes": [
"com.xd.sdk"
]
}
]
}

导入插件

  1. 将给到的 Vuplex 4.5 的 UnityPackage 导入项目。
  2. 将 asmdef 文件拷贝到 Vuplex/WebView/Core/Scripts/Vuplex.WebView.asmdef

参数文件

将给到的参数配置文件名改为XDConfig.json,放到 Assets/ 目录下。

初始化

打印日志

using XD.SDK.Common;
XDGLogger.LogDelegate = (level, info) =>
{
// 自行打印到控制台或文件
};

初始化SDK

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

// 渠道和语言根据实际情况修改
// PackageType 规则
// 国内 TapTap PC 平台请使用 PackageTypePCTapTap,
// 海外 Google Play Android 平台请使用 PackageTypeAndroidGooglePlay
// 其他平台请使用 PackageTypeDefault

// db 参数可透传给 TapDB 的 device_login/user_login 事件
var dbProperties = new Dictionary<string, object>
{
{ "test_init_device_login_key", "test_init_device_login_value" }
};
XDGInitParam initParam = XDGInitParam.CreateToXDSDK("your_channel", LangType.ZH_CN, XDGPackageType.PackageTypePCTapTap, dbProperties);
XDGCommon.InitSDK(initParam,
(success, msg) =>
{
if (success)
{
// 初始化成功
}
else
{
// 初始化失败
}
});

// 判断是否初始化完成
bool isInitialized = XDGCommon.IsInitialized();

修改多语言

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

using XD.SDK.Common;
XDGCommon.SetLanguage(LangType.EN);

登录

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

状态回调

  • 需要在初始化前设置好
using XD.SDK.Account;   

// 设置用户状态回调
XDGAccount.AddUserStatusChangeCallback((code, message) =>
{
switch (code)
{
case XDGUserStatusCodeType.BIND:
// 绑定成功,没有更多登录方式可不处理
break;
case XDGUserStatusCodeType.UNBIND:
// 解绑成功,没有更多登录方式可不处理
break;
case XDGUserStatusCodeType.LOGOUT:
// 退出登录,回到登录页面,展示登录按钮
break;
case XDGUserStatusCodeType.ProtocolAgreedAfterLogout:
// 退出登录后同意协议,可不处理
break;
case XDGUserStatusCodeType.SupportHasUnRead:
// 客服有未读消息,未开通服务可以不处理
break;
case XDGUserStatusCodeType.SupportNoUnRead:
// 客服没有未读消息,未开通服务可以不处理
break;
default:
// 未知 Code,不需要处理
break;
}
});

发起登录

using XD.SDK.Account;

// 自动登录,在初始化成功后可以调用该方法,每次打开游戏只触发一次。失败之后只能调用其他登录方式。
XDGAccount.LoginByType(LoginType.Default,
user =>
{
// 自动登录成功,进入游戏
String userId = user.UserId;
},
error =>
{
// 自动登录失败,展示 TapTap 登录按钮
});

// 手动登录
XDGAccount.LoginByType(LoginType.TapTap,
user =>
{
// TapTap登录成功,进入游戏
String userId = user.UserId;
},
error =>
{
// TapTap 登录失败,展示 TapTap 登录按钮
});

// 登录后获取用户信息
XDGUser currentUser = XDGAccount.GetCurrentUser();

用户中心

using XD.SDK.Account;

XDGAccount.OpenUserCenter(null);

退出登录

using XD.SDK.Account;

XDGAccount.Logout();

账号注销

using XD.SDK.Account;

XDGAccount.OpenAccountDeletion();

打开客服

using XD.SDK.Account;

// 角色信息
XDGRoleInfo role = new XDGRoleInfo()
{
RoleId = "role_id",
RoleLevel = 10,
RoleName = "role_name",
ServerId = "server_id"
};
// 透传参数
var paramsMap = new Dictionary<string, object>
{
{ "key1", "value1" },
{ "key2", true },
{ "key3", 1234567890 }
};
XDGAccount.OpenCustomerService(role, "", paramsMap);

个人信息页

仅限国内可使用

using XD.SDK.Account;

XDGRoleInfo role = new XDGRoleInfo()
{
RoleId = "role_id",
RoleLevel = 10,
RoleName = "role_name",
ServerId = "server_id"
};
XDGAccount.OpenUserDashboard(role);

内购

查询商品价格

  • 在查询商品价格前请在后台配置好对应的商品信息。
  • Apple、Google Play 平台查询价格需要使用对应平台的商品 ID。
  • 其他平台查询价格使用 XD 平台的商品 ID。
using XD.SDK.Payment;

string[] productIdList = { "com.xd.demo.sku1", "com.xd.demo.sku2" };
XDGPayment.QueryWithProductIds(productIdList,
list =>
{
foreach (var product in list)
{
// 商品 ID
var productId = product.ProductId;
// 商品价格,带货币符号,可直接使用
var productPrice = product.DisplayPrice;
}
},
error =>
{
// 查询失败
});

发起内购

using XD.SDK.Payment;

var paymentParams = new XDGPaymentParams(
"game_order_id", // 游戏订单号
"product_id", // 商品 ID
"role_id", // 当前角色 ID
"server_id", // 当前服务器 ID
"extra", // 透传参数
1);// 商品数量,仅 Apple 购买可用
XDGPayment.PayWithParams(paymentParams,
orderInfo =>
{
// 购买完成,发货请等待服务端回调
String orderId = orderInfo.GameOrderId;
String productId = orderInfo.ProductId;
String roleId = orderInfo.RoleId;
String serverId = orderInfo.ServerId;
String extra = orderInfo.Extra;
},
error =>
{
// 购买失败
});

查询 Apple 未消费订单

  • 仅 Apple 平台可用,其他平台调用该接口会直接返回空列表。
  • 查询到的订单可能是用户之前购买成功但未成功消费的订单,也可能是 App Store 中兑换的礼包码订单。
using XD.SDK.Payment;

XDGPayment.QueryPendingPurchases(
list =>
{
// 查询成功
foreach (var purchase in list)
{
// 商品 ID
String productId = purchase.ProductId;
// 订单 token
String purchaseToken = purchase.PurchaseToken;
}
},
error =>
{
// 查询失败
});

消费 Apple 未消费订单

using XD.SDK.Payment;

var paymentParams = new XDGPaymentParams(
"game_order_id", // 游戏订单号
"product_id", // 商品 ID
"role_id", // 当前角色 ID
"server_id", // 当前服务器 ID
"extra", // 透传参数
1);// 商品数量,仅 Apple 购买可用

// 传入查询到的未消费订单 token
paymentParams.PendingPurchaseToken = "purchase_token";

XDGPayment.PayWithParams(paymentParams,
orderInfo =>
{
// 购买完成,发货请等待服务端回调
String orderId = orderInfo.GameOrderId;
String productId = orderInfo.ProductId;
String roleId = orderInfo.RoleId;
String serverId = orderInfo.ServerId;
String extra = orderInfo.Extra;
},
error =>
{
// 购买失败
});

工具

事件上报

using XD.SDK.Common;

// 事件上报
XDGCommon.TrackEvent("event_name", new Dictionary<string, object>()
{
{ "key1", "value1" },
{ "key2", "value2" }
});

// 角色信息上报
XDGRoleInfo role = new XDGRoleInfo()
{
RoleId = "role_id",
RoleLevel = 10,
RoleName = "role_name",
ServerId = "server_id"
};
XDGCommon.TrackRole(role);

商店评价

商店评价仅支持 Apple 和 Google Play 平台。

using XD.SDK.Common;

XDGCommon.StoreReview();

打开网页

using XD.SDK.Common;

XDGCommon.OpenWebPage("url", (actionType, objects) =>
{
// objects 是透传数据,在各个事件中均可能携带
if (actionType == WebActionEnum.CLOSE)
{
// 关闭网页
} else if (actionType == WebActionEnum.MESSAGE)
{
// 透传数据,具体数据内容根据和网页的约定而定
}
});

公告

展示公告

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

using XD.SDK.Announcement;

XDGAnnouncementConfig config = new XDGAnnouncementConfig();
config.Channel = "渠道配置"; // 对应公告后台的 Google iOS PC 等
config.ServerCode = "服务器 code"; // 对应公告后台配置服务器时对应的 code

// 展示公告面板
XDGAnnouncementManager.OpenAnnouncementPage(config, (actionType, objects) =>
{
// objects 是透传数据,在各个事件中均可能携带
if (actionType == WebActionEnum.CLOSE)
{
// 关闭公告
} else if (actionType == WebActionEnum.MESSAGE)
{
// 透传数据
}
});

检查未读公告

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

using XD.SDK.Announcement;

XDGAnnouncementConfig config = new XDGAnnouncementConfig();
config.Channel = "渠道配置"; // 对应公告后台的 Google iOS PC 等
config.ServerCode = "服务器 code"; // 对应公告后台配置服务器时对应的 code

XDGAnnouncementManager.RequestAnnouncementUnread(config, hasUnread =>
{
if (hasUnread)
{
// 有未读公告
}
else
{
// 没有未读公告
}
});

TapSDK

  • TapSDK 内的功能模块均由 XDSDK 进行初始化和调用,游戏无需重复初始化 TapSDK。
  • 接口功能使用说明请参考 TapSDK 文档,但接口使用时请注意替换成 XDSDK 中的对应接口,一般在 XDGTapSDK 和 XDGTapPlusSDK 两个类中,函数名一般保持不变。

XDGTapSDK

using XD.SDK.Tap;

该模块下所有模块使用时需要替换成 XDGTapSDK.接口名 形式调用。

XDGTapPlusSDK

using XD.SDK.Tap.Plus;

该模块下所有模块使用时需要替换成 XDGTapPlusSDK.接口名 形式调用。

XDSDK 接入 TDS 实名认证防沉迷最佳实践

· 阅读需 7 分钟

准备工作

开发者只需要知道游戏在 TapDC 后台的 Client ID 参数用于防沉迷 SDK 的初始化。没错,准备工作就这一点。

游戏实名认证

请参考最佳实践

调用 SDK 提供的功能性接口

  • TapTap 快速认证

TapTap 快速认证服务顾名思义,是指让玩家直接授权其 TapTap 账号的实名信息完成实名认证,省去填写姓名、身份证号的繁琐步骤。

具体的代码示范如下:

// 参数:userIdentifier 玩家唯一标识,请填写用户的 XDID(即 XDGUser 中的 userId)
string userIdentifier = "玩家的唯一标识";
// 参数:isTapUser 对于是否是 Tap 用户,游戏可根据当前玩家选择的登录方式进行设置,即选择 Tap 登录方式的设置为 true, 其他类型设置为 false。
// 对于国服游戏一般只有 Tap 登录渠道的 isTapUser 参数设置 true 即可,具体情况请依旧游戏侧自己的需求来定,不是一成不变的。这个参数会影响实名认证弹窗的样式,具体样式区别接下来做详细展示说明。
bool isTapUser = true;
AntiAddictionUIKit.Startup(userIdentifier, isTapUser);
  • 正确调用 startup 接口移动端打包后可以看到如下的弹窗,以游戏铃兰之剑作为示例展示。(参数:isTapUser 设置为 true 的状态):

由上图可见,实名认证弹窗只提供一个「使用」按钮,玩家点击「使用」按钮后会触发 TapTap 快速认证的授权页面。

  • startup 接口参数:isTapUser 设置为 false 的状态:

由上图可见,实名认证弹窗会提供「使用」和「不实用」按钮,玩家点击「使用」按钮后会触发 TapTap 快速认证的授权页面;当玩家点击「不使用」按钮时,会触发需要玩家手动输入身份证信息的界面。如下图所示。

玩家输入姓名、身份证号后如果认证失败,会提示「认证未通过,请提交真实信息」,如果乱填写身份证号,则会提示「身份证号码非法」。这些也不需要开发者关心,认证失败时,「游戏实名认证」窗口是不会关闭的,除非玩家点击右上角的关闭按钮主动关闭。这些都是 SDK 内部封装好的,开发者重点需要关心的是文档中给出的回调类型,这个很重要。比如实名认证过程中,玩家点击了右上角的关闭按钮,则会触发 code 为 9002 的回调,该回调告知开发者玩家的动作,表示玩家并没有完成实名认证,开发者对此应该做相应的逻辑处理。

无版号游戏没有开通实名认证防沉迷服务是无法使用 TDS 的实名认证防沉迷功能的。没有开通服务的游戏接入实名认证防沉迷,当调用实名认证接口时会给出相对应的提示:「未查询到实名认证配置」

因此,至于 startup 接口参数 isTapUser 该如何赋值,具体参考游戏需求,如果游戏只有 TapTap 登录渠道,没有其他的登录渠道,则 isTapUser 可以设置为 true;如果游戏具有多个登录渠道,建议游戏根据登录类型来决定设置 isTapUser 的值。

防沉迷策略

仅允许未成年人在周五、周六、周日和法定节假日的 20:00 至 21:00 进行游戏。非允许游戏时间段内,SDK 封装的相应逻辑会被触发,弹出提示框提醒未成年无法继续游戏。此时的未成年玩家最多有两种选择:「退出游戏」或者「切换账号」。

如果初始化 SDK 时设置的一个参数 showSwitchAccount 为 false(表示不显示「切换账号」按钮),那此时的未成年玩家只能选择「退出游戏」了。

// 是否显示切换账号按钮
bool showSwitchAccount = false;

检查消费上限

根据年龄段的不同,未成年玩家的消费金额有不同的上限。 如果要启用消费限制功能,开发者只需要在未成年玩家消费前检查是否受限。如果游戏没有消费则可以忽略这部分说明。

游戏在收到玩家的付费请求后,调用以下接口检验当前玩家的付费行为是否被限制,游戏侧请 务必 在未成年玩家每次充值之前调用如下接口进行判断。

long amount = 100;    // 100 表示 100 分,即 1 元
AntiAddictionUIKit.CheckPayLimit(amount,
(result) => {
// status 为 1 时可以支付
int status = result.status;
if (status == 1) {
// 可以进行支付
} else {
// 说明玩家当前的这一笔消费不可以再继续了,如果继续就超过了限制,游戏侧则要拦截这笔消费。
}
},
(exception) => {
// 处理异常
}
);

消费金额的单位为分。

警告

当玩家支付成功后并且支付渠道给到支付回调后,XD Server 会 Server to Server 上报玩家当前支付金额给 TDS 防沉迷,游戏侧不需要再额外的去上报玩家消费金额。游戏侧需要做的就是客户端自行校验玩家消费是否达到上限即可。

至此,你基本上已经很好的完成了 TDS 实名认证防沉迷 SDK 的接入了,请给你自己一点掌声。

讲真,个人觉得 TDS 实名认证防沉迷 SDK 并不需要心动一方游戏服务端的过多参与,不知道屏幕前的你在完全了解后是否也有相同的感受。SDK 剩余的其他接口开发者请酌情按需调用即可。

获取玩家年龄段

实名认证后,可以统一调用如下接口获取当前玩家的年龄段:

int ageRange = AntiAddictionUIKit.AgeRange;
// ageRange 是一个整数,表示玩家所处年龄段的下限(最低年龄)。 特别地,-1 表示「未实名」。

具体年龄段返回数值及其对应年龄段如下表所示:

类型数值含义
-1未实名
00 到 7 岁
88 到 15 岁
1616 到 17 岁
18成年玩家

上报游戏时长

如果启用时长限制功能,需要上报游戏时长。已登录的玩家,开始游戏时调用此接口,之后 SDK 会自动轮询上报游戏时长。

AntiAddictionUIKit.EnterGame();

相应地,已登录的玩家,停止游戏时调用此接口,之后 SDK 停止轮询上报时长。

AntiAddictionUIKit.LeaveGame();

获取剩余时长

获取玩家当前剩余时长:

int remainingTimeInSeconds = AntiAddictionUIKit.RemainingTime;  // 单位:秒

int remainingTimeInMinutes = AntiAddictionUIKit.RemainingTimeInMinutes; // 单位:分钟

Checklist

游戏侧接入 TDS 实名认证防沉迷功能,开发者需要测试实名认证防沉迷流程是否正常,检查并知晓以下事项:

  • 游戏侧正确导入 TDS 实名认证防沉迷所需的包体。

  • SDK 的正确初始化,gameId 参数为 Tap Client ID,游戏侧根据需求决定是否显示「切换账号」按钮,若显示「切换账号」按钮请务必处理好这块的逻辑。

  • 充分了解实名认证防沉迷的各个回调方法所对应的含义,游戏侧对此做出相应的逻辑处理。

  • 充分了解实名认证 AntiAddictionUIKit.Startup(userIdentifier, isTapUser) 接口的两个参数含义。

  • SDK 的初始化 AntiAddictionUIKit.Init 和实名认证接口 AntiAddictionUIKit.Startup 保留毫秒级的间隔,以确保 SDK 完成初始化。

  • 游戏在收到未成年玩家付费请求后请 务必 先检查当前这笔消费是否已达上限,达到上限则拦截当前这笔消费。

  • 游戏前端请 务必 不要额外上报玩家消费的,XDSDK 服务端会自行上报。

关于不同登录方式同一邮箱自动绑定处理

· 阅读需 3 分钟

1、背景:

目前心动海外游戏在现有 TapTap、游客登录基础上,允许额外开通 Apple、Google 登录。注意:该功能仅针对用海外。

基于目前海外用户习惯,当用户使用不同方式登录(Apple、Google、TapTap)且为同一邮箱时,需要让其登录上同一账号,防止其账号裂开。详细背景

例如用户使用 TapTap (邮箱 A)登录并创建心动账号(XDID:1)后,再使用新的 Google (邮箱 A)账号登录时,会自动登录并绑定该 Google 账号至心动账号(XDID:1)。

2、处理事项

基于邮箱登录策略,防止用户账号裂开,以下场景项目组需要自行处理并告知用户:

场景一:用户未验证 TapTap 邮箱导致登录失败

前置条件:

  • 用户使用邮箱、密码注册 TapTap 账号时未通过邮件验证邮箱。

场景描述:

  • 当用户使用未验证邮箱的 TapTap 账号登录后,需要告知其邮箱未验证并弹窗引导其前往邮箱进行验证。

弹窗文案:

  • 标题:邮箱未验证
  • 内容:当前 {第三方平台名称} 账号所关联的邮箱( {从第三方平台获取的邮箱信息})未被验证,请先查看注册 {第三方平台名称} 账号时发送至 ( {从第三方平台获取的邮箱信息})的验证邮件,并根据邮件指引验证成功后再次尝试登录。

场景1

场景二:多个心动账号绑定同一邮箱

前置条件:

  • XDID:1 已绑定 TapTap 账号(邮箱 A)、Google 账号 (邮箱 B)
  • XDID:2 已绑定 Google 账号(邮箱 A)

用户流程:

  • 用户使用 Apple 账号 (邮箱 A)登录时,由于 SDK 并不知晓用户期望绑定哪一个 XDID 所以需要告知用户账号已存在并引导用户登录原有账号执行绑定、解绑操作。

弹窗文案:

  • 标题:账号已存在
  • 内容:当前 {第三方平台名称} 账号所关联的邮箱({从第三方平台获取的邮箱信息})已被用于另一个游戏账号,请使用该邮箱所关联的 {邮箱所关联心动账号下绑定该邮箱的其他登录方式} 登录游戏账号后进入「账号安全中心」进行账号绑定、解绑操作。

场景2

场景三:现有心动账号已绑定用户当前的登录方式

前置条件:

  • XDID:1 已绑定 TapTap 账号(邮箱 A)、Google 账号 (邮箱 B)

用户流程:

  • 用户使用 TapTap (邮箱 B)登录时,为了防止用户账号裂开情况,将告知用户账号已存在,并弹窗引导用户登录原有账号执行绑定、解绑操作。

弹窗文案

  • 标题:账号已存在
  • 内容:当前 {第三方平台名称}账号所关联的邮箱({从第三方平台获取的邮箱信息})对应的游戏账号已绑定其他 {第三方平台名称}账号 。请使用该邮箱所关联的 {邮箱所关联心动账号下绑定该邮箱的其他登录方式} 登录游戏账号后进入「账号安全中心」进行账号绑定、解绑操作。

场景3