在应用程序侧集成SDK
- 为应用程序的登录系统、游戏内商店及其他页面设计界面。
- 根据您的应用程序逻辑使用SDK方法设置事件处理。要开始使用基本的SDK功能,请按照下方的分步教程进行操作。
本说明解释如何使用SDK方法实现以下内容:
- 用户注册
- 重新发送注册验证邮件请求
- 用户登录
- 用户密码重置
您可以使用用户名或邮箱地址来认证用户身份。以下示例中,我们使用用户的用户名来进行认证,使用邮箱地址来进行注册验证及重置密码。
示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的认证系统实现方案。
实现用户注册
本教程介绍以下逻辑的实现:
创建页面界面
为注册页面创建一个场景并在页面上添加以下元素:
- 用户名字段
- 用户邮箱地址字段
- 用户密码字段
- 注册按钮
下图为页面结构的示例。

创建页面控制器
- 创建一个继承自MonoBehaviour基类的脚本
RegistrationPage
。 - 声明网页界面元素的变量并在
Inspector 面板中设置它们的值。 - 添加逻辑来处理对注册按钮的点击:
- 在
Start
方法中,订阅点击事件。 - 添加一个在点击该按钮后调用的匿名方法。
- 在该方法中,声明
username
、email
和password
变量,并按页面中相应字段的值对其进行初始化。 - 调用
XsollaAuth.Instance.Register
SDK方法,并向其传入username
、email
和password
变量以及下列方法:
- 在
OnSuccess
— 注册成功时调用OnError
— 发生错误时调用
在脚本示例中,OnSuccess
和OnError
方法调用标准Debug.Log方法。错误代码和描述在error
参数中传递。
您还可以添加其他动作,例如打开一个包含重新发送注册邮件请求的页面或在注册成功时打开一个登录页面。
注册页面的脚本示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3using Xsolla.Auth;
4using Xsolla.Core;
5
6namespace Recipes
7{
8 public class RegistrationPage : MonoBehaviour
9 {
10 // Declaration of variables for UI elements on the page
11
12 [SerializeField] private InputField UsernameInput;
13
14 [SerializeField] private InputField EmailInputField;
15
16 [SerializeField] private InputField PasswordInputField;
17
18 [SerializeField] private Button RegisterButton;
19
20 private void Start()
21 {
22 // Handling the button click
23 RegisterButton.onClick.AddListener(() =>
24 {
25 var username = UsernameInput.text;
26 var email = EmailInputField.text;
27 var password = PasswordInputField.text;
28
29 XsollaAuth.Instance.Register(username, password, email, onSuccess: OnSuccess, onError: OnError);
30 });
31 }
32
33 private void OnSuccess()
34 {
35 UnityEngine.Debug.Log("Registration successful");
36 // Some actions
37 }
38
39 private void OnError(Error error)
40 {
41 UnityEngine.Debug.Log($"Registration failed. Description: {error.errorMessage}");
42 // Some actions
43 }
44 }
45}
设置注册验证邮件
成功注册后,用户将在指定邮箱中收到一封注册验证邮件。您可以在发布商帐户中自定义发送给用户的邮件。
如果您开发的是Android应用程序,请设置深度链接以在用户验证注册后将用户返回到应用程序。
实现重新发送注册验证邮件请求
本教程介绍以下逻辑的实现:
创建页面界面
为包含重新发送验证邮件请求的页面创建一个场景并在页面上添加以下元素:
- 用户名/邮箱字段
- 重新发送邮件按钮
下图为页面结构的示例。

创建页面控制器
- 创建一个继承自MonoBehaviour基类的脚本
ResendConfirmationEmail
。 - 声明网页界面元素的变量并在
Inspector 面板中设置它们的值。 - 添加逻辑来处理对重新发送邮件按钮的点击:
- 在
Start
方法中,订阅点击事件。 - 添加一个在点击该按钮后调用的匿名方法。
- 在该方法中,声明
username
变量,并按页面中相应字段的值对其进行初始化。 - 调用
XsollaAuth.Instance.ResendConfirmationLink
SDK方法,并向其传入username
变量以及OnSuccess
和OnError
方法。
- 在
重新发送邮件页面的脚本示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3using Xsolla.Auth;
4using Xsolla.Core;
5
6namespace Recipes
7{
8 public class ResendConfirmationEmail : MonoBehaviour
9 {
10 // Declaration of variables for UI elements on the page
11
12 [SerializeField] private InputField UsernameInput;
13
14 [SerializeField] private Button ResendEmailButton;
15
16 private void Start()
17 {
18 // Handling the button click
19 ResendEmailButton.onClick.AddListener(() =>
20 {
21 var username = UsernameInput.text;
22
23 XsollaAuth.Instance.ResendConfirmationLink(username, onSuccess: OnSuccess, onError: OnError);
24 });
25 }
26
27 private void OnSuccess()
28 {
29 UnityEngine.Debug.Log("Resend confirmation email successful");
30 // Some actions
31 }
32
33 private void OnError(Error error)
34 {
35 UnityEngine.Debug.Log($"Resend confirmation email failed. Description: {error.errorMessage}");
36 // Some actions
37 }
38 }
39}
如果请求成功,用户将在注册时指定的邮箱中收到一封注册验证邮件。
实现用户登录
本教程介绍以下逻辑的实现:
创建页面界面
为登录页面创建一个场景并在页面上添加以下元素:
- 用户名字段
- 密码字段
- 记住我复选框
- 登录按钮
下图为页面结构的示例。

创建页面控制器
- 创建一个继承自MonoBehaviour基类的脚本
AutorizationPage
。 - 声明网页界面元素的变量并在
Inspector 面板中设置它们的值。 - 添加逻辑来处理对登录按钮的点击:
- 在
Start
方法中,订阅点击事件。 - 添加一个在点击该按钮后调用的匿名方法。
- 在该方法中,声明
username
和password
变量,并按页面中相应字段的值对其进行初始化。创建rememberMe
变量,并使用一个复选框状态对其进行初始化以记住帐户。 - 调用
XsollaAuth.Instance.SignIn
SDK方法,并向其传入username
、password
和rememberMe
变量以及OnSuccess
和OnError
方法。
- 在
token
参数中传入授权令牌。授权令牌在向艾克索拉服务器发送的请求中需用到。登录页面的脚本示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3using Xsolla.Auth;
4using Xsolla.Core;
5
6namespace Recipes
7{
8 public class AuthorizationPage : MonoBehaviour
9 {
10 // Declaration of variables for UI elements on the page
11
12 [SerializeField] private InputField UsernameInput;
13
14 [SerializeField] private InputField PasswordInputField;
15
16 [SerializeField] private Toggle RememberMeToggle;
17
18 [SerializeField] private Button AuthorizationButton;
19
20 private void Start()
21 {
22 // Handling the button click
23
24 AuthorizationButton.onClick.AddListener(() =>
25 {
26 var username = UsernameInput.text;
27 var password = PasswordInputField.text;
28 var rememberMe = RememberMeToggle.isOn;
29
30 XsollaAuth.Instance.SignIn(username, password, rememberMe, null, onSuccess: OnSuccess, onError: OnError);
31 });
32 }
33
34 private void OnSuccess(string token)
35 {
36 UnityEngine.Debug.Log($"Authorization successful. Token: {token}");
37 // Some actions
38 }
39
40 private void OnError(Error error)
41 {
42 UnityEngine.Debug.Log($"Authorization failed. Description: {error.errorMessage}");
43 // Some actions
44 }
45 }
46}
实现密码重置
本教程介绍以下逻辑的实现:
创建页面界面
为密码重置页面创建一个场景并在页面上添加以下元素:
- 用户名/邮箱字段
- 密码重置按钮
下图为页面结构的示例。

创建页面控制器
- 创建一个继承自MonoBehaviour基类的脚本
ResetPasswordPage
。 - 声明网页界面元素的变量并在
Inspector 面板中设置它们的值。 - 添加逻辑来处理对密码重置按钮的点击:
- 在
Start
方法中,订阅点击事件。 - 添加一个在点击该按钮后调用的匿名方法。
- 在该方法中,声明
username
变量,并按页面中相应字段的值对其进行初始化。 - 调用
XsollaAuth.Instance.ResetPassword
SDK方法,并向其传入username
变量以及OnSuccess
和OnError
方法。
- 在
密码重置页面的脚本示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3using Xsolla.Auth;
4using Xsolla.Core;
5
6namespace Recipes
7{
8 public class ResetPasswordPage : MonoBehaviour
9 {
10 // Declaration of variables for UI elements on the page
11
12 [SerializeField] private InputField UsernameInput;
13
14 [SerializeField] private Button ResetPasswordButton;
15
16 private void Start()
17 {
18 // Handling the button click
19
20 ResetPasswordButton.onClick.AddListener(() =>
21 {
22 var username = UsernameInput.text;
23
24 XsollaAuth.Instance.ResetPassword(username, null, null, OnSuccess, OnError);
25 });
26 }
27
28 private void OnSuccess()
29 {
30 UnityEngine.Debug.Log("Password reset successful");
31 // Some actions
32 }
33
34 private void OnError(Error error)
35 {
36 UnityEngine.Debug.Log($"Password reset failed. Description: {error.errorMessage}");
37 // Some actions
38 }
39 }
40}
成功发出密码重置请求后,用户将收到一封包含密码重置链接的邮件。在发布商帐户 > 登录管理器项目 > 安全性 > OAuth 2.0 > OAuth 2.0重定向URI中,您可以配置用户成功完成认证、邮箱验证或密码重置后将其重定向到的URL地址或路径。
本指南说明如何使用SDK方法实现通过社交网络帐户进行用户注册和登录。
与通过用户名/邮箱地址和密码进行用户认证不同,您无需实现单独的用户注册逻辑。如果用户的首次登录是通过社交网络进行,将自动创建一个帐户。
如果您在应用程序中将社交网络登录设置为一种备选认证方法,则在满足下列条件的情况下,社交网络帐户将自动与现有用户帐户关联:
- 已使用用户名/邮箱地址和密码注册的用户通过社交网络帐户登录您的应用程序。
- 社交网络返回一个邮箱地址。
- 社交网络帐户中的用户邮箱地址与注册您的应用程序时使用的邮箱地址一致。
LinkSocialProvider
SDK方法。本教程介绍以下逻辑的实现:
示例展示了如何设置通过Twitter帐户进行用户登录。您可以用相同的方法设置其他社交网络。
示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的认证系统实现方案。
创建页面界面
为登录页创建一个场景并在其中添加社交网络登录按钮。下图为页面结构的示例。

创建页面控制器
- 创建一个继承自MonoBehaviour基类的脚本
SocialAuthorizationPage
。 - 声明应用程序登录页界面元素的变量并在
Inspector 面板中设置它们的值。 - 添加逻辑来处理对登录按钮的点击:
- 在
Start
方法中,订阅点击事件。 - 添加一个在点击该按钮后调用的匿名方法。
- 要传入登录页URL,请在匿名方法中声明
url
变量。在SocialProvider
参数中传递一个Facebook
值,从而通过GetSocialNetworkAuthUrl
SDK方法初始化该变量。 - 要打开一个浏览器,请调用
BrowserHelper.Instance.Open
方法。如要使用内置浏览器,请向方法传入url
变量和true
值。
- 在
- 要获取令牌并关闭浏览器,请跟踪用户成功登录后的页面URL变化:
- 声明
singlePageBrowser
变量并通过BrowserHelper.Instance.GetLastBrowser
SDK方法对其进行初始化。 - 订阅有效页面URL更改事件并将
OnUrlChanged
方法设置为处理程序。
- 声明
- 要获取令牌并关闭浏览器,请跟踪用户成功登录后的页面URL变化:
- 实现令牌获取:
- 使用
ParseUtils.TryGetValueFromUrl
工具方法解析OnUrlChanged
方法中传递的活动页面URL。 - 添加对活动页面URL中的认证代码进行检查。
ParseUtils.TryGetValueFromUrl
方法在code
变量中传入认证代码。 - 要用认证代码交换令牌,请调用
ExchangeCodeToToken
SDK方法并向其传入code
变量和以下方法:OnSuccess
— 注册成功时调用OnError
— 发生错误时调用
- 使用
在脚本示例中,OnSuccess
和OnError
方法调用标准Debug.Log方法。您还可以添加其他动作。
如果用户成功登录,将在token
参数中传入授权令牌。该令牌在向艾克索拉服务器发送请求时使用。如果发生了错误,则将在error
参数中传入错误代码和描述。
- 获取令牌后,请删除带浏览器的游戏对象。
登录页面的脚本示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3using Xsolla.Auth;
4using Xsolla.Core;
5
6namespace Recipes
7{
8 public class SocialAuthorizationPage : MonoBehaviour
9 {
10 // Declaration of variables for UI elements on the page
11
12 [SerializeField] private Button FacebookButton;
13
14 private void Start()
15 {
16 // Handling the button click
17
18 FacebookButton.onClick.AddListener(() =>
19 {
20 // Opening browser
21
22 var url = XsollaAuth.Instance.GetSocialNetworkAuthUrl(SocialProvider.Facebook);
23 BrowserHelper.Instance.Open(url, true);
24
25 // Determining the end of authentication
26 BrowserHelper.Instance.InAppBrowser.AddUrlChangeHandler(OnUrlChanged);
27 });
28 }
29
30 // Getting token
31 private void OnUrlChanged(string url)
32 {
33 if (ParseUtils.TryGetValueFromUrl(url, ParseParameter.code, out var code))
34 {
35 XsollaAuth.Instance.ExchangeCodeToToken(code, OnSuccess, OnError);
36 BrowserHelper.Instance.Close();
37 }
38 }
39
40 private void OnSuccess(string token)
41 {
42 UnityEngine.Debug.Log($"Authorization successful. Token: {token}");
43 // Some actions
44 }
45
46 private void OnError(Error error)
47 {
48 UnityEngine.Debug.Log($"Authorization failed. Description: {error.errorMessage}");
49 // Some actions
50 }
51 }
52}
本教程介绍如何使用SDK方法在游戏内商店中显示以下商品:
- 虚拟物品
- 虚拟物品组
- 捆绑包
- 虚拟货币套餐
开始之前,请在发布商帐户中配置商品:
本教程介绍以下逻辑的实现:
示例中的逻辑与界面比您实际在应用程序中的要简单得多。演示项目提供了一种可能的游戏内商店商品目录实现方案。
目录中的每个商品示例显示以下内容:
- 商品名称
- 商品描述
- 商品价格
- 图片
如果游戏内商店中还存储了其他信息,也可以显示那些信息。
实现虚拟物品的显示
创建商品小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 商品背景图片
- 商品名称
- 商品描述
- 商品价格
- 商品图片
下图为小组件结构的示例。

创建商品小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
VirtualItemWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualItemWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text PriceText;
15
16 public Image IconImage;
17 }
18}
创建显示商品列表的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 商品小组件显示区域
下图为页面结构的示例。

创建页面控制器
- 创建继承自
MonoBehaviour
基类的脚本VirtualItemsPage
。 - 声明以下变量:
WidgetsContainer
— 小组件的容器WidgetPrefab
— 商品小组件预制件
- 将脚本与页面游戏对象关联:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个VirtualItemsPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。
- 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取商品列表的逻辑。在
OnAuthenticationSuccess
方法中调用XsollaCatalog.Instance.GetCatalog
SDK方法,并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
OnItemsRequestSuccess
,用于成功的获取商品列表操作OnError
回调方法,用于发生错误的情况- 基于列表第一个商品的偏移量,包含在
offset
参数中 - 加载商品的数量,包含在
limit
参数中
offset
和limit
参数非必需。它们用于分页 — 多页显示目录中的商品。页面上商品的最大数量是50。如果目录中包含的商品超过50个,则需要分页。- 在
OnItemsRequestSuccess
方法中,添加为每个收到的商品创建小组件的逻辑:- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
VirtualItemWidget
组件附加到widget
变量上。
- 将以下数据传入商品小组件:
- 将
storeItem.name
变量值传入商品名元素。 - 将
storeItem.description
变量值传入商品描述元素。 - 实现以下逻辑来显示商品价格:
- 如果
storeItem.price
变量的值不等于null
,则该商品以真实货币形式销售。请以{amount} {currency}
格式指定价格并将其传入小组件元素。 - 如果
storeItem.virtual_prices
变量的值不等于null
,则该商品以虚拟货币形式销售。请以{name}: {amount}
格式指定价格并将其传入小组件元素。
- 如果
- 将
storeItem.virtual_prices
变量是同一商品在不同货币下的价格数组。示例显示的是发布商帐户商店 > 虚拟物品中商品设置里指定的默认价格。- 要显示商品图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL。
- 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。
- 要显示商品图片,请使用
页面控制器脚本示例:
- C#
1using System.Linq;
2using UnityEngine;
3using Xsolla.Auth;
4using Xsolla.Catalog;
5using Xsolla.Core;
6
7namespace Recipes
8{
9 public class VirtualItemsPage : MonoBehaviour
10 {
11 // Declaration of variables for containers and widget prefabs
12
13 public Transform WidgetsContainer;
14
15 public GameObject WidgetPrefab;
16
17 private void Start()
18 {
19 // Starting the authentication process
20
21 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
22 }
23
24 private void OnAuthenticationSuccess(string token)
25 {
26 // After successful authentication starting the request for catalog from store
27
28 XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
29 }
30
31 private void OnItemsRequestSuccess(StoreItems storeItems)
32 {
33 // Iterating the items collection and assign values for appropriate ui elements
34
35 foreach (var storeItem in storeItems.items)
36 {
37 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
38 var widget = widgetGo.GetComponent<VirtualItemWidget>();
39
40 widget.NameText.text = storeItem.name;
41 widget.DescriptionText.text = storeItem.description;
42
43 if (storeItem.price != null)
44 {
45 var realMoneyPrice = storeItem.price;
46 widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
47 }
48 else if (storeItem.virtual_prices != null)
49 {
50 var virtualCurrencyPrice = storeItem.virtual_prices.First(x => x.is_default);
51 widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
52 }
53
54 ImageLoader.Instance.GetImageAsync(storeItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
55 }
56 }
57
58 private void OnError(Error error)
59 {
60 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
61 }
62 }
63}
下图为脚本的运行结果。

实现虚拟物品组的显示
创建商品小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 商品背景图片
- 商品名称
- 商品描述
- 商品价格
- 商品图片
下图为小组件结构的示例。

创建商品小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
VirtualItemWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualItemWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text PriceText;
15
16 public Image IconImage;
17 }
18}
创建打开商品组按钮的小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将允许商品组显示的按钮添加为预制件的子对象并配置其视觉显示。
下图为小组件结构的示例。

创建打开商品组按钮的脚本
- 创建继承自
MonoBehaviour
基类的VirtualItemGroupButton
脚本。 - 声明打开商品组按钮的变量,并在
Inspector 面板中设置变量的值。 - 向预制件的根对象添加一个脚本:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个VirtualItemGroupButton
脚本。
- 在
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualItemGroupButton : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9 public Text NameText;
10
11 public Button Button;
12 }
13}
创建显示商品列表的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 商品组按钮显示区域
- 商品小组件显示区域
下图为页面结构的示例。

创建页面控制器
- 创建继承自
MonoBehaviour
基类的VirtualItemsByGroupsPage
脚本。 - 声明变量:
GroupButtonsContainer
— 组按钮的容器GroupButtonPrefab
— 按钮预制件ItemWidgetsContainer
— 商品小组件容器WidgetPrefab
— 商品小组件预制件
- 将脚本附加至页面游戏对象:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个VirtualItemsByGroupsPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。 - 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取商品列表的逻辑。在
OnAuthenticationSuccess
方法中调用XsollaCatalog.Instance.GetCatalog
SDK方法,并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
OnItemsRequestSuccess
,用于成功的获取商品列表操作OnError
回调方法,用于发生错误的情况- 基于列表第一个商品的偏移量,包含在
offset
参数中 - 加载商品的数量,包含在
limit
参数中
offset
和limit
参数非必需。它们用于分页 — 多页显示目录中的商品。页面上商品的最大数量是50。如果目录中包含的商品超过50个,则需要分页。- 在
OnItemsRequestSuccess
方法中,添加形成商品组列表的逻辑:- 从收到的商品列表中获取唯一组的列表。将其添加至显示所有商品(不论类别)的
All
元素。 - 删除所有子对象以清空按钮容器。方法是调用
DeleteAllChildren
方法,然后向其传入容器对象。 - 对于每个商品组:
- 从收到的商品列表中获取唯一组的列表。将其添加至显示所有商品(不论类别)的
- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
VirtualItemGroupButton
设置为groupButton
变量。 - 将
groupName
变量值传入组名称元素。 - 向单击按钮的动作添加一个匿名方法。在该方法中,调用
OnGroupSelected
方法并将商品组的名称和商品列表作为参数传递。
- 要显示所有商品,请调用
OnGroupSelected
方法并传入All
作为组名称。
- 要显示所有商品,请调用
- 在
OnGroupSelected
方法中,添加商品初始显示的逻辑:- 创建
itemsForDisplay
变量并在商品组名称有All
值时向其分配所有收到的商品。否则将组名称与groupName
变量匹配的商品关联至itemsForDisplay
变量。 - 删除所有子对象以清空按钮容器。方法是调用
DeleteAllChildren
方法,然后向其传入容器对象。
- 创建
- 添加为每个收到的商品创建小组件的逻辑:
- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
VirtualItemWidget
组件附加到widget
变量上。
- 将以下数据传入商品小组件:
- 将
storeItem.name
变量值传入商品名元素。 - 将
storeItem.description
变量值传入商品描述元素。 - 实现以下逻辑来显示商品价格:
- 将
- 如果
storeItem.price
变量的值不等于null
,则该商品以真实货币形式销售。请以{amount} {currency}
格式指定价格并将其传入小组件元素。 - 如果
storeItem.virtual_prices
变量的值不等于null
,则该商品以虚拟货币形式销售。请以{name}: {amount}
格式指定价格并将其传入小组件元素。
- 如果
storeItem.virtual_prices
变量是同一商品在不同货币下的价格数组。示例显示的是发布商帐户商店 > 虚拟物品中商品设置里指定的默认价格。- 要显示商品图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL。
- 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。
- 要显示商品图片,请使用
- C#
1using System.Collections.Generic;
2using System.Linq;
3using UnityEngine;
4using Xsolla.Auth;
5using Xsolla.Catalog;
6using Xsolla.Core;
7
8namespace Recipes
9{
10 public class VirtualItemsByGroupsPage : MonoBehaviour
11 {
12 // Declaration of variables for containers and widget prefabs
13 public Transform GroupButtonsContainer;
14
15 public GameObject GroupButtonPrefab;
16
17 public Transform ItemWidgetsContainer;
18
19 public GameObject ItemWidgetPrefab;
20
21 private void Start()
22 {
23 // Starting the authentication process
24 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess,
25 onError: OnError);
26 }
27
28 private void OnAuthenticationSuccess(string token)
29 {
30 // After successful authentication starting the request for catalog from store
31 XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0,
32 limit: 50);
33 }
34
35 private void OnItemsRequestSuccess(StoreItems storeItems)
36 {
37 // Selecting the group’s name from items and order them alphabetical
38 var groupNames = storeItems.items
39 .SelectMany(x => x.groups)
40 .GroupBy(x => x.name)
41 .Select(x => x.First())
42 .OrderBy(x => x.name)
43 .Select(x => x.name)
44 .ToList();
45
46 // Add group name for “all groups”, which will mean show all items regardless of group affiliation
47 groupNames.Insert(0, "All");
48
49 // Clear container
50 DeleteAllChildren(GroupButtonsContainer);
51
52 // Iterating the group names and creating ui-button for each
53 foreach (var groupName in groupNames)
54 {
55 var buttonObj = Instantiate(GroupButtonPrefab, GroupButtonsContainer, false);
56 var groupButton = buttonObj.GetComponent<VirtualItemGroupButton>();
57
58 groupButton.NameText.text = groupName;
59 groupButton.Button.onClick.AddListener(() => OnGroupSelected(groupName, storeItems));
60 }
61
62 // Calling method for redraw page
63 OnGroupSelected("All", storeItems);
64 }
65
66 private void OnGroupSelected(string groupName, StoreItems storeItems)
67 {
68 // Declaring variable for items which will display on page
69 IEnumerable<StoreItem> itemsForDisplay;
70 if (groupName == "All")
71 {
72 itemsForDisplay = storeItems.items;
73 }
74 else
75 {
76 itemsForDisplay = storeItems.items.Where(item => item.groups.Any(group => group.name == groupName));
77 }
78
79 // Clear container
80 DeleteAllChildren(ItemWidgetsContainer);
81
82 // Iterating the items collection and assign values for appropriate ui elements
83 foreach (var storeItem in itemsForDisplay)
84 {
85 var widgetGo = Instantiate(ItemWidgetPrefab, ItemWidgetsContainer, false);
86 var widget = widgetGo.GetComponent<VirtualItemWidget>();
87
88 widget.NameText.text = storeItem.name;
89 widget.DescriptionText.text = storeItem.description;
90
91 if (storeItem.price != null)
92 {
93 var realMoneyPrice = storeItem.price;
94 widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
95 }
96 else if (storeItem.virtual_prices != null)
97 {
98 var virtualCurrencyPrice = storeItem.virtual_prices.First(x => x.is_default);
99 widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
100 }
101
102 ImageLoader.Instance.GetImageAsync(storeItem.image_url,
103 (url, sprite) => widget.IconImage.sprite = sprite);
104 }
105 }
106
107 // Utility method for delete all children of container
108 private static void DeleteAllChildren(Transform parent)
109 {
110 var childList = parent.Cast<Transform>().ToList();
111 foreach (var childTransform in childList)
112 {
113 Destroy(childTransform.gameObject);
114 }
115 }
116
117 private void OnError(Error error)
118 {
119 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
120 }
121 }
122}
页面控制器脚本示例:

实现捆绑包的显示
创建捆绑小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 小组件背景图片
- 捆绑包名称
- 捆绑包描述
- 捆绑包价格
- 捆绑包内容描述(商品及其数量)
- 捆绑包图片
下图为小组件结构的示例。

创建小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
BundleWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class BundleWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9 public Text NameText;
10
11 public Text DescriptionText;
12
13 public Text PriceText;
14
15 public Text ContentText;
16
17 public Image IconImage;
18 }
19}
创建显示捆绑包的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 捆绑包小组件显示区域
下图为页面结构的示例。

创建页面控制器
- 创建继承自
MonoBehaviour
基类的BundlesPage
脚本。 - 声明变量:
WidgetsContainer
— 小组件的容器WidgetPrefab
— 捆绑包小组件预制件
- 将脚本附加到页面游戏对象上:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个BundlesPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。 - 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取捆绑包列表的逻辑。在
OnAuthenticationSuccess
方法中调用XsollaCatalog.Instance.GetBundles
SDK方法,并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
OnItemsRequestSuccess
回调方法,用于成功的获取捆绑包列表操作OnError
回调方法,用于发生错误的情况
- 在
OnBundlesRequestSuccess
方法中,添加为每个收到的捆绑包创建小组件的逻辑:- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
BundleWidget
组件附加到widget
变量上。
- 将以下数据传入捆绑包小组件:
- 将
bundleItem.name
变量值传入商品名称元素。 - 将
bundleItem.description
变量值传入商品描述元素。 - 实现以下逻辑来显示捆绑包内容:
- 用捆绑包中的每个商品组成一行,其中包含商品名称及其数量。该行的格式为
{name} x {quantity}
。 - 将所有行组成一行,用换行符分隔。
- 将新行传入小组件元素。
- 用捆绑包中的每个商品组成一行,其中包含商品名称及其数量。该行的格式为
- 将
- 实现以下逻辑以显示捆绑包价格:
- 如果
bundleItem.price
变量的值不等于null
,则该捆绑包以真实货币形式销售。请以{amount} {currency}
格式指定价格并将其传入小组件元素。 - 如果
bundleItem.virtual_prices
变量的值不等于null
,则该捆绑包以虚拟货币形式销售。请以{name}: {amount}
格式指定价格并将其传入小组件元素。
- 如果
- 实现以下逻辑以显示捆绑包价格:
bundleItem.virtual_prices
变量是同一捆绑包在不同货币下的价格的数组。示例显示的是发布商帐户商店 > 捆绑包中商品设置里指定的默认价格。- 要显示商品图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL。
- 作为回调的匿名函数。在该函数中,将收到的精灵添加为捆绑包图片。
- 要显示商品图片,请使用
页面控制器脚本示例:
- C#
1using System.Linq;
2using UnityEngine;
3using Xsolla.Auth;
4using Xsolla.Catalog;
5using Xsolla.Core;
6
7namespace Recipes
8{
9 public class BundlesPage : MonoBehaviour
10 {
11 // Declaration of variables for containers and widget prefabs
12 public Transform WidgetsContainer;
13
14 public GameObject WidgetPrefab;
15
16 private void Start()
17 {
18 // Starting the authentication process
19 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
20 }
21
22 private void OnAuthenticationSuccess(string token)
23 {
24 // After successful authentication starting the request for bundles from store
25 XsollaCatalog.Instance.GetBundles(XsollaSettings.StoreProjectId, OnBundlesRequestSuccess, OnError);
26 }
27
28 private void OnBundlesRequestSuccess(BundleItems bundleItems)
29 {
30 // Iterating the bundles collection and assign values for appropriate ui elements
31 foreach (var bundleItem in bundleItems.items)
32 {
33 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
34 var widget = widgetGo.GetComponent<BundleWidget>();
35
36 widget.NameText.text = bundleItem.name;
37 widget.DescriptionText.text = bundleItem.description;
38
39 var bundleContent = bundleItem.content.Select(x => $"{x.name} x {x.quantity}");
40 widget.ContentText.text = string.Join("\n", bundleContent);
41
42 if (bundleItem.price != null)
43 {
44 var realMoneyPrice = bundleItem.price;
45 widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
46 }
47 else if (bundleItem.virtual_prices != null)
48 {
49 var virtualCurrencyPrice = bundleItem.virtual_prices.First(x => x.is_default);
50 widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
51 }
52
53 ImageLoader.Instance.GetImageAsync(bundleItem.image_url,
54 (url, sprite) => widget.IconImage.sprite = sprite);
55 }
56 }
57
58 private void OnError(Error error)
59 {
60 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
61 }
62 }
63}
下图为脚本的运行结果。

实现虚拟货币套餐的显示
创建虚拟货币套餐的小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 小组件背景图片
- 套餐名称
- 套餐描述
- 套餐价格
- 套餐图片
下图为小组件结构的示例。

创建小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
VirtualCurrencyPackageWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualCurrencyPackageWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text PriceText;
15
16 public Image IconImage;
17 }
18}
创建显示虚拟货币套餐的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 虚拟货币套餐小组件显示区域
下图为页面结构的示例。

创建页面控制器
- 创建继承自
MonoBehaviour
基类的VirtualCurrencyPackagesPage
脚本。 - 声明变量:
WidgetsContainer
— 小组件的容器WidgetPrefab
— 虚拟货币套餐预制件
- 将脚本附加至页面游戏对象:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个VirtualCurrencyPackagesPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。 - 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:
- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取商品列表的逻辑。在
OnAuthenticationSuccess
方法中调用XsollaCatalog.Instance.GetVirtualCurrencyPackagesList
SDK方法,并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
OnItemsRequestSuccess
,用于成功的获取商品列表操作OnError
回调方法,用于发生错误的情况
- 在
OnPackagesRequestSuccess
方法中,添加为每个收到的套餐创建小组件的逻辑:- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
VirtualCurrencyPackageWidget
组件附加到widget
变量上。
- 将以下数据传入套餐小组件:
- 将
packageItem.name
变量值传入套餐名元素。 - 将
packageItem.description
变量值传入套餐描述元素。 - 实现以下逻辑来显示套餐价格:
- 将
- 如果
packageItem.price
变量的值不等于null
,则该套餐以真实货币形式销售。请以{amount} {currency}
格式指定价格并将其传入小组件元素。 - 如果
packageItem.virtual_prices
变量的值不等于null
,则该套餐以虚拟货币形式销售。请以{name}: {amount}
格式指定价格并将其传入小组件元素。
- 如果
packageItem.virtual_prices
变量是同一套餐在不同货币下的价格的数组。示例显示的是发布商帐户商店 > 虚拟货币 > 套餐中套餐设置里指定的默认价格。- 要显示商品图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL。
- 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。
- 要显示商品图片,请使用
页面控制器脚本示例:
- C#
1using System.Linq;
2using UnityEngine;
3using Xsolla.Auth;
4using Xsolla.Catalog;
5using Xsolla.Core;
6
7namespace Recipes
8{
9 public class VirtualCurrencyPackagesPage : MonoBehaviour
10 {
11 // Declaration of variables for containers and widget prefabs
12 public Transform WidgetsContainer;
13
14 public GameObject WidgetPrefab;
15
16 private void Start()
17 {
18 // Starting the authentication process
19 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
20 }
21
22 private void OnAuthenticationSuccess(string token)
23 {
24 // After successful authentication starting the request for packages from store
25 XsollaCatalog.Instance.GetVirtualCurrencyPackagesList(XsollaSettings.StoreProjectId, OnPackagesRequestSuccess, OnError);
26 }
27
28 private void OnPackagesRequestSuccess(VirtualCurrencyPackages packageItems)
29 {
30 // Iterating the packages collection and assign values for appropriate ui elements
31 foreach (var packageItem in packageItems.items)
32 {
33 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
34 var widget = widgetGo.GetComponent<VirtualCurrencyPackageWidget>();
35
36 widget.NameText.text = packageItem.name;
37 widget.DescriptionText.text = packageItem.description;
38
39 if (packageItem.price != null)
40 {
41 var realMoneyPrice = packageItem.price;
42 widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
43 }
44 else if (packageItem.virtual_prices != null)
45 {
46 var virtualCurrencyPrice = packageItem.virtual_prices.First(x => x.is_default);
47 widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
48 }
49
50 ImageLoader.Instance.GetImageAsync(packageItem.image_url,
51 (url, sprite) => widget.IconImage.sprite = sprite);
52 }
53 }
54
55 private void OnError(Error error)
56 {
57 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
58 }
59 }
60}
下图为脚本的运行结果。

本说明主要介绍如何使用SDK方法实现以真实货币计价的形式销售虚拟物品。
开始之前,需实现在目录中显示虚拟物品。下方示例中我们描述了如何实现虚拟物品的购买。其他商品类型的配置与此类似。
本教程介绍以下逻辑的实现:
示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种以真实货币计价的形式销售商品以及显示商品目录的可能方案。
完成商品小组件
在商品小组件中添加购买按钮,并配置其显示元素。
下图为小组件结构的示例。

完成商品小组件脚本
- 打开
VirtualItemWidget
脚本。 - 声明购买按钮的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualItemWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text PriceText;
15
16 public Image IconImage;
17
18 public Button BuyButton;
19 }
20}
完成显示商品列表的页面控制器
- 打开
VirtualItemsPage
脚本。 - 在
OnAuthenticationSuccess
方法中,向Token.Instance
变量传入授权令牌。
- 通过
XsollaAuth.Instance.SignIn
SDK方法进行用户授权过程中收到的JWT。 - 通过自定义ID(在您的服务器上生成的用户ID)在应用程序后端收到的JWT。如实现了自己的授权系统,请使用此令牌。
- 添加处理点击虚拟物品购买按钮的逻辑:
- 在
OnItemsRequestSuccess
方法中,订阅按钮点击事件。 - 添加发生按钮点击后调用的匿名方法。
- 在该方法中,调用
XsollaCatalog.Instance.PurchaseItem
SDK方法以生成一个订单并向其传入:
- 在
- 项目ID(
projectId
参数中) - 商品标识符(
itemSku
参数中) OnOrderCreateSuccess
方法,以处理商品购买订单的成功生成OnError
回调方法,用于发生错误的情况
- 项目ID(
- 实现支付页面的打开。方法是添加
OnOrderCreateSuccess
方法并在其中调用:XsollaOrders.Instance.OpenPurchaseUi
SDK方法,用于打开支付页面TrackOrderStatus
协程,用于跟踪订单状态中的改变
- 在
TrackOrderStatus
协程中,实现每秒获取一次订单状态信息。方法是使用XsollaOrders.Instance.CheckOrderStatus
SDK方法,并向其传入:- 项目ID(
projectId
参数中) - 支付详情中的订单号(
orderId
参数中) - 用于处理成功收到订单状态信息的匿名方法
- 用于错误处理的匿名方法
- 项目ID(
- 在用于处理成功收到订单状态信息的匿名方法中,实现订单支付过程中的
OnPurchaseSuccess
方法回调(支付状态done
或paid
)。 - 在
OnPurchaseSuccess
方法中,实现成功购买虚拟物品的处理。
- 如果使用内置浏览器来打开支付页面,请关闭该浏览器。
页面脚本示例:
- C#
1using System.Collections;
2using UnityEngine;
3using Xsolla.Auth;
4using Xsolla.Catalog;
5using Xsolla.Core;
6using Xsolla.Orders;
7
8namespace Recipes
9{
10 public class VirtualItemsPage : MonoBehaviour
11 {
12 // Declaration of variables for containers and widget prefabs
13
14 public Transform WidgetsContainer;
15
16 public GameObject WidgetPrefab;
17
18 private void Start()
19 {
20 // Starting the authentication process
21
22 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
23 }
24
25 private void OnAuthenticationSuccess(string token)
26 {
27 // After successful authentication starting the request for catalog from store
28 Token.Instance = Token.Create(token);
29 XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
30 }
31
32 private void OnItemsRequestSuccess(StoreItems storeItems)
33 {
34 // Iterating the items collection and assign values for appropriate ui elements
35
36 foreach (var storeItem in storeItems.items)
37 {
38 if (storeItem.price == null)
39 continue;
40
41 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
42 var widget = widgetGo.GetComponent<VirtualItemWidget>();
43
44 widget.NameText.text = storeItem.name;
45 widget.DescriptionText.text = storeItem.description;
46
47 var realMoneyPrice = storeItem.price;
48 widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
49
50 ImageLoader.Instance.GetImageAsync(storeItem.image_url,
51 (url, sprite) => widget.IconImage.sprite = sprite);
52
53 widget.BuyButton.onClick.AddListener(() =>
54 {
55 XsollaCatalog.Instance.PurchaseItem(XsollaSettings.StoreProjectId, storeItem.sku, OnOrderCreateSuccess, OnError);
56 });
57 }
58 }
59
60 private void OnOrderCreateSuccess(PurchaseData purchaseData)
61 {
62 XsollaOrders.Instance.OpenPurchaseUi(purchaseData);
63 StartCoroutine(TrackOrderStatus(purchaseData));
64 }
65
66 private IEnumerator TrackOrderStatus(PurchaseData purchaseData)
67 {
68 var isDone = false;
69 while (!isDone)
70 {
71 XsollaOrders.Instance.CheckOrderStatus
72 (
73 XsollaSettings.StoreProjectId,
74 purchaseData.order_id,
75 status =>
76 {
77 if (status.status == "paid" || status.status == "done")
78 {
79 isDone = true;
80 OnPurchaseSuccess();
81 }
82 },
83 error => { OnError(error); }
84 );
85
86 yield return new WaitForSeconds(1f);
87 }
88 }
89
90 private void OnPurchaseSuccess()
91 {
92 UnityEngine.Debug.Log($"Purchase successful");
93 BrowserHelper.Instance.Close();
94 }
95
96 private void OnError(Error error)
97 {
98 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
99 }
100 }
101}
本说明主要介绍如何使用SDK方法实现以虚拟货币计价的形式销售虚拟物品。
开始之前,需实现在目录中显示虚拟物品。下方示例中我们描述了如何实现虚拟物品的购买。其他商品类型的配置与此类似。
本教程介绍以下逻辑的实现:
示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种以真实货币计价的形式销售商品以及显示商品目录的可能方案。
完成商品小组件
在商品小组件中添加购买按钮,并配置其显示元素。
下图为小组件结构的示例。

完成商品小组件脚本
- 打开
VirtualItemWidget
脚本。 - 声明购买按钮的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualItemWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text PriceText;
15
16 public Image IconImage;
17
18 public Button BuyButton;
19 }
20}
完成显示商品列表的页面控制器
- 打开
VirtualItemsPage
脚本。 - 在
OnAuthenticationSuccess
方法中,向Token.Instance
变量传入授权令牌。
- 通过
XsollaAuth.Instance.SignIn
SDK方法进行用户授权过程中收到的JWT。 - 通过自定义ID(在您的服务器上生成的用户ID)在应用程序后端收到的JWT。如实现了自己的授权系统,请使用此令牌。
- 添加处理点击虚拟物品购买按钮的逻辑:
- 在
OnItemsRequestSuccess
方法中,订阅按钮点击事件。 - 添加发生按钮点击后调用的匿名方法。
- 在该方法中,调用
XsollaCatalog.Instance.PurchaseItem
SDK方法以生成一个订单并向其传入:
- 在
- 项目ID(
projectId
参数中) - 商品标识符(
itemSku
参数中) OnOrderCreateSuccess
方法,以处理商品购买订单的成功生成OnError
回调方法,用于发生错误的情况
- 项目ID(
- 在
OnOrderCreateSuccess
方法中,实现订单状态检查过程。方法是使用XsollaOrders.Instance.CheckOrderStatus
SDK方法,并向其传入:- 项目ID(
projectId
参数中) - 支付详情中的订单号(
orderId
参数中) - 用于处理成功收到订单状态信息的匿名方法
- 用于错误处理的匿名方法
- 项目ID(
- 在用于处理成功收到订单状态信息的匿名方法中,实现订单支付过程中的
OnPurchaseSuccess
方法回调(支付状态done
或paid
)。 - 在
OnPurchaseSuccess
方法中,实现成功购买虚拟物品的处理。
页面脚本示例:
- C#
1using System.Linq;
2using UnityEngine;
3using Xsolla.Auth;
4using Xsolla.Catalog;
5using Xsolla.Core;
6using Xsolla.Orders;
7
8namespace Recipes
9{
10 public class VirtualItemsPage : MonoBehaviour
11 {
12 // Declaration of variables for containers and widget prefabs
13
14 public Transform WidgetsContainer;
15
16 public GameObject WidgetPrefab;
17
18 private void Start()
19 {
20 // Starting the authentication process
21
22 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
23 }
24
25 private void OnAuthenticationSuccess(string token)
26 {
27 // After successful authentication starting the request for catalog from store
28 Token.Instance = Token.Create(token);
29 XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
30 }
31
32 private void OnItemsRequestSuccess(StoreItems storeItems)
33 {
34 // Iterating the items collection and assign values for appropriate ui elements
35 foreach (var storeItem in storeItems.items)
36 {
37 if (storeItem.virtual_prices.Length == 0)
38 continue;
39
40 var widget = Instantiate(WidgetPrefab, WidgetsContainer, false).GetComponent<VirtualItemWidget>();
41
42 widget.NameText.text = storeItem.name;
43 widget.DescriptionText.text = storeItem.description;
44
45 var defaultPrice = storeItem.virtual_prices.First(x => x.is_default);
46 widget.PriceText.text = $"{defaultPrice.name}: {defaultPrice.amount}";
47
48 ImageLoader.Instance.GetImageAsync(storeItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
49
50 widget.BuyButton.onClick.AddListener(() =>
51 {
52 var price = storeItem.virtual_prices.First(x => x.is_default);
53 XsollaCatalog.Instance.PurchaseItemForVirtualCurrency(XsollaSettings.StoreProjectId, storeItem.sku, price.sku, OnOrderCreateSuccess, OnError);
54 });
55 }
56 }
57
58 private void OnOrderCreateSuccess(PurchaseData purchaseData)
59 {
60 XsollaOrders.Instance.CheckOrderStatus
61 (
62 XsollaSettings.StoreProjectId,
63 purchaseData.order_id,
64 status =>
65 {
66 if (status.status == "paid" || status.status == "done")
67 {
68 OnPurchaseSuccess();
69 }
70 },
71 error =>
72 {
73 OnError(error);
74 }
75 );
76 }
77
78
79 private void OnPurchaseSuccess()
80 {
81 UnityEngine.Debug.Log($"Purchase successful");
82 }
83
84 private void OnError(Error error)
85 {
86 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
87 }
88 }
89}
本教程介绍如何使用SDK方法在应用中显示虚拟货币的余额。
示例中的逻辑与界面比您实际在应用程序中的要简单得多。演示项目提供了一种可能的游戏内商店商品目录实现方案。
创建显示余额的小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 小组件背景图片
- 虚拟货币名称
- 虚拟货币数量
- 虚拟货币图片
下图为小组件结构的示例。

创建显示余额的小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
VirtualCurrencyWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class VirtualCurrencyWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text AmountText;
13
14 public Image IconImage;
15 }
16}
创建包含虚拟货币列表的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 小组件显示区域
下图为页面结构的示例。

创建包含虚拟货币列表页面的控制器
- 创建继承自
MonoBehaviour
基类的脚本VirtualCurrenciesPage
。 - 声明以下变量:
WidgetsContainer
— 小组件的容器WidgetPrefab
— 余额显示小组件预制件
- 将脚本附加到页面游戏对象上:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个VirtualCurrenciesPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。 - 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取虚拟货币列表的逻辑。方法是在
OnAuthenticationSuccess
方法中:- 将授权令牌传入
Token.Instance
变量。
- 将授权令牌传入
- 通过
XsollaAuth.Instance.SignIn
SDK方法进行用户授权过程中收到的JWT。 - 通过自定义ID(在您的服务器上生成的用户ID)在应用程序后端收到的JWT。如实现了自己的授权系统,请使用此令牌。
- 调用
XsollaInventory.Instance.GetVirtualCurrencyBalance
SDK方法并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
- 调用
OnBalanceRequestSuccess
方法,用于获取商品列表成功的情况OnError
回调方法,用于发生错误的情况
- 在
OnBalanceRequestSuccess
方法中,添加为收到的每种虚拟货币创建小组件的逻辑:- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
VirtualCurrencyWidget
组件附加到widget
变量上。
- 将以下数据传入余额小组件:
- 将
balanceItem.name
变量值传入虚拟货币名元素。 - 将
balanceItem.amount.ToString()
变量值传入虚拟货币数量元素。 - 实现以下逻辑来显示商品价格。要显示虚拟货币图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL。
- 匿名回调函数。在该函数中,将收到的精灵添加为虚拟货币图片。
- 将
页面控制器脚本示例:
- C#
1using UnityEngine;
2using Xsolla.Auth;
3using Xsolla.Core;
4using Xsolla.Inventory;
5
6namespace Recipes
7{
8 public class VirtualCurrenciesPage : MonoBehaviour
9 {
10 // Declaration of variables for containers and widget prefabs
11
12 public Transform WidgetsContainer;
13
14 public GameObject WidgetPrefab;
15
16 private void Start()
17 {
18 // Starting the authentication process
19
20 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
21 }
22
23 private void OnAuthenticationSuccess(string token)
24 {
25 // After successful authentication starting the request for virtual currencies
26
27 Token.Instance = Token.Create(token);
28 XsollaInventory.Instance.GetVirtualCurrencyBalance(XsollaSettings.StoreProjectId, OnBalanceRequestSuccess, OnError);
29 }
30
31 private void OnBalanceRequestSuccess(VirtualCurrencyBalances balance)
32 {
33 // Iterating the virtual currencies list and assign values for appropriate ui elements
34
35 foreach (var balanceItem in balance.items)
36 {
37 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
38 var widget = widgetGo.GetComponent<VirtualCurrencyWidget>();
39
40 widget.NameText.text = balanceItem.name;
41 widget.AmountText.text = balanceItem.amount.ToString();
42
43 ImageLoader.Instance.GetImageAsync(balanceItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
44 }
45 }
46
47 private void OnError(Error error)
48 {
49 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
50 }
51 }
52}
下图为脚本的运行结果。

本教程介绍如何使用SDK方法显示用户物品库中的商品。
示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的物品库实现方案。
创建商品小组件
- 创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 从
Hierarchy 面板拖动一个游戏对象到Project 面板,以转换预制件中创建的游戏对象。 - 选择一个创建的预制件,然后在
Inspector 面板中单击Open Prefab 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 商品背景图片
- 商品名称
- 商品描述
- 商品数量
- 商品图片
下图为小组件结构的示例。

创建商品小组件脚本
- 创建一个继承自MonoBehaviour基类的脚本
InventoryItemWidget
。 - 声明商品小组件界面元素的变量并在
Inspector 面板中设置它们的值。
小组件脚本的示例:
- C#
1using UnityEngine;
2using UnityEngine.UI;
3
4namespace Recipes
5{
6 public class InventoryItemWidget : MonoBehaviour
7 {
8 // Declaration of variables for UI elements
9
10 public Text NameText;
11
12 public Text DescriptionText;
13
14 public Text QuantityText;
15
16 public Image IconImage;
17 }
18}
创建显示物品库的页面
- 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择
GameObject > Create Empty 。 - 将以下UI元素添加为预制件子对象并配置其视觉显示:
- 页面背景图片
- 商品小组件显示区域
下图为页面结构的示例。

创建页面控制器
- 创建继承自
MonoBehaviour
基类的脚本InventoryItemsPage
。 - 声明以下变量:
WidgetsContainer
— 商品小组件的容器WidgetPrefab
— 商品小组件预制件
- 将脚本附加到页面游戏对象上:
- 在
Hierarchy 面板中选择一个对象。 - 在
Inspector 面板中,单击Add Component ,然后选择一个InventoryItemsPage
脚本。
- 在
- 在
Inspector 面板中设置变量的值。 - 通过在
Start
方法中调用XsollaAuth.Instance.SignIn
SDK方法添加登录逻辑,并向其传入:- 用户名或邮箱地址,包含在
username
参数中 - 用户密码,包含在
password
参数中
- 用户名或邮箱地址,包含在
xsolla
,密码:xsolla
)。rememberUser
参数中记住帐户的标志OnAuthenticationSuccess
回调方法,用于成功的用户登录OnError
回调方法,用于发生错误的情况
- 添加获取物品库中商品列表的逻辑。方法是在
OnAuthenticationSuccess
方法中:- 将授权令牌传入
Token.Instance
变量。
- 将授权令牌传入
- 通过
XsollaAuth.Instance.SignIn
SDK方法进行用户授权过程中收到的JWT。 - 通过自定义ID(在您的服务器上生成的用户ID)在应用程序后端收到的JWT。如实现了自己的授权系统,请使用此令牌。
- 调用
XsollaInventory.Instance.GetInventoryItems
SDK方法并向其传入:- 项目ID,包含在
projectId
参数中
- 项目ID,包含在
- 调用
OnItemsRequestSuccess
,用于获取商品列表成功的情况OnError
回调方法,用于发生错误的情况
- 对于
OnItemsRequestSuccess
方法中收到的每个商品,添加创建小组件的逻辑:- 使用
InventoryItem.IsVirtualCurrency
方法添加一个检查,确保收到的商品不是虚拟货币。
- 使用
- 实例化一个商品小组件预制件作为容器子对象。
- 将收到的
InventoryItemWidget
组件附加到widget
变量上。
- 将以下数据传入商品小组件:
- 将
inventoryItem.name
变量值传入商品名元素。 - 将
inventoryItem.description
变量值传入商品描述元素。 - 将
inventoryItem.amount.ToString()
传入商品数量元素。 - 要显示商品图片,请使用
ImageLoader.Instance.GetImageAsync
工具方法并向其传入:- 图片URL
- 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。
- 将
页面控制器脚本示例:
- C#
1using UnityEngine;
2using Xsolla.Auth;
3using Xsolla.Core;
4using Xsolla.Inventory;
5
6namespace Recipes
7{
8 public class InventoryItemsPage : MonoBehaviour
9 {
10 // Declaration of variables for containers and widget prefabs
11 public Transform WidgetsContainer;
12
13 public GameObject WidgetPrefab;
14
15 private void Start()
16 {
17 // Starting the authentication process
18 XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
19 }
20
21 private void OnAuthenticationSuccess(string token)
22 {
23 // After successful authentication starting the request for virtual currencies
24 Token.Instance = Token.Create(token);
25 XsollaInventory.Instance.GetInventoryItems(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError);
26 }
27
28 private void OnItemsRequestSuccess(InventoryItems inventoryItems)
29 {
30 // Iterating the item list and assign values for appropriate ui elements
31
32 foreach (var inventoryItem in inventoryItems.items)
33 {
34 if (inventoryItem.IsVirtualCurrency())
35 continue;
36
37 var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
38 var widget = widgetGo.GetComponent<InventoryItemWidget>();
39
40 widget.NameText.text = inventoryItem.name;
41 widget.DescriptionText.text = inventoryItem.description;
42 widget.QuantityText.text = inventoryItem.quantity.ToString();
43
44 ImageLoader.Instance.GetImageAsync(inventoryItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
45 }
46 }
47
48 private void OnError(Error error)
49 {
50 UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
51 }
52 }
53}
下图为脚本的运行结果。

有用链接
上次更新时间: 2025年8月29日发现了错别字或其他内容错误? 请选择文本,然后按Ctrl+Enter。