在应用程序侧集成SDK

  1. 为应用程序的登录系统、游戏内商店及其他页面设计界面。
  2. 根据您的应用程序逻辑使用SDK方法设置事件处理。要开始使用基本的SDK功能,请按照下方的分步教程进行操作。

注:
您可以按照Unity说明中的信息创建自己的解决方案,也可以将演示场景用作模板。要根据自己的应用程序调整演示场景UI,请使用UI生成器
请按照以下分步教程了解基本SDK功能的使用。

通过用户名/邮箱和密码进行用户登录

本说明解释如何使用SDK方法实现以下内容:

  • 用户注册
  • 重新发送注册验证邮件请求
  • 用户登录
  • 用户密码重置

您可以使用用户名或邮箱地址来认证用户身份。以下示例中,我们使用用户的用户名来进行认证,使用邮箱地址来进行注册验证及重置密码。

注:
如果您在网站上(例如Web商店)使用了登录管理器小组件,请确保该网站与您的应用程序实现相同的用户认证方法。小组件默认使用邮箱地址进行认证。如要设置通过用户名进行用户登录,请联系您的帐户经理。

示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的认证系统实现方案。

实现用户注册

本教程介绍以下逻辑的实现:

创建页面界面

为注册页面创建一个场景并在页面上添加以下元素:

  • 用户名字段
  • 用户邮箱地址字段
  • 用户密码字段
  • 注册按钮

下图为页面结构的示例。

创建页面控制器

  1. 创建一个继承自MonoBehaviour基类的脚本RegistrationPage
  2. 声明网页界面元素的变量并Inspector面板中设置它们的值
  3. 添加逻辑来处理对注册按钮的点击:

    1. Start方法中,订阅点击事件。
    2. 添加一个在点击该按钮后调用的匿名方法。
    3. 在该方法中,声明usernameemailpassword变量,并按页面中相应字段的值对其进行初始化。
    4. 调用XsollaAuth.Instance.Register SDK方法,并向其传入usernameemailpassword变量以及下列方法:

      • OnSuccess — 注册成功时调用
      • OnError — 发生错误时调用

注:

在脚本示例中,OnSuccessOnError方法调用标准Debug.Log方法。错误代码和描述在error参数中传递。

您还可以添加其他动作,例如打开一个包含重新发送注册邮件请求的页面或在注册成功时打开一个登录页面。

注册页面的脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;
using Xsolla.Auth;
using Xsolla.Core;

namespace Recipes
{
    public class RegistrationPage : MonoBehaviour
    {
        // Declaration of variables for UI elements on the page

        [SerializeField] private InputField UsernameInput;

        [SerializeField] private InputField EmailInputField;

        [SerializeField] private InputField PasswordInputField;

        [SerializeField] private Button RegisterButton;

        private void Start()
        {
            // Handling the button click
         RegisterButton.onClick.AddListener(() =>
            {
                var username = UsernameInput.text;
                var email = EmailInputField.text;
                var password = PasswordInputField.text;

                XsollaAuth.Instance.Register(username, email, password, onSuccess: OnSuccess, onError: OnError);
            });
        }

        private void OnSuccess()
        {
            UnityEngine.Debug.Log("Registration successful");
            // Some actions
     }

        private void OnError(Error error)
        {
            UnityEngine.Debug.Log($"Registration failed. Description: {error.errorMessage}");
            // Some actions
     }
    }
}

设置注册验证邮件

成功注册后,用户将在指定邮箱中收到一封注册验证邮件。您可以在发布商帐户中自定义发送给用户的邮件

如果您开发的是Android应用程序,请设置深度链接以在用户验证注册后将用户返回到应用程序。

注:
如果您安全性标准允许,可禁用通过邮箱地址进行注册验证。请联系您的帐户经理进行禁用或发送邮件至am@xsolla.com与我们联系。

实现重新发送注册验证邮件请求

本教程介绍以下逻辑的实现:

创建页面界面

为包含重新发送验证邮件请求的页面创建一个场景并在页面上添加以下元素:

  • 用户名/邮箱字段
  • 重新发送邮件按钮

下图为页面结构的示例。

创建页面控制器

  1. 创建一个继承自MonoBehaviour基类的脚本ResendConfirmationEmail
  2. 声明网页界面元素的变量并Inspector面板中设置它们的值
  3. 添加逻辑来处理对重新发送邮件按钮的点击:

    1. Start方法中,订阅点击事件。
    2. 添加一个在点击该按钮后调用的匿名方法。
    3. 在该方法中,声明username变量,并按页面中相应字段的值对其进行初始化。
    4. 调用XsollaAuth.Instance.ResendConfirmationLink SDK方法,并向其传入username变量以及OnSuccessOnError方法。

重新发送邮件页面的脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;
using Xsolla.Auth;
using Xsolla.Core;

namespace Recipes
{
    public class ResendConfirmationEmail : MonoBehaviour
    {
        // Declaration of variables for UI elements on the page

        [SerializeField] private InputField UsernameInput;

        [SerializeField] private Button ResendEmailButton;

        private void Start()
        {
            // Handling the button click
         ResendEmailButton.onClick.AddListener(() =>
            {
                var username = UsernameInput.text;

                XsollaAuth.Instance.ResendConfirmationLink(username, onSuccess: OnSuccess, onError: OnError);
            });
        }

        private void OnSuccess()
        {
            UnityEngine.Debug.Log("Resend confirmation email successful");
            // Some actions
     }

        private void OnError(Error error)
        {
            UnityEngine.Debug.Log($"Resend confirmation email failed. Description: {error.errorMessage}");
            // Some actions
     }
    }
}

如果请求成功,用户将在注册时指定的邮箱中收到一封注册验证邮件。

实现用户登录

本教程介绍以下逻辑的实现:

创建页面界面

为登录页面创建一个场景并在页面上添加以下元素:

  • 用户名字段
  • 密码字段
  • 记住我复选框
  • 登录按钮

下图为页面结构的示例。

创建页面控制器

  1. 创建一个继承自MonoBehaviour基类的脚本AutorizationPage
  2. 声明网页界面元素的变量并Inspector面板中设置它们的值
  3. 添加逻辑来处理对登录按钮的点击:

    1. Start方法中,订阅点击事件。
    2. 添加一个在点击该按钮后调用的匿名方法。
    3. 在该方法中,声明usernamepassword变量,并按页面中相应字段的值对其进行初始化。创建rememberMe变量,并使用一个复选框状态对其进行初始化以记住帐户。
    4. 调用XsollaAuth.Instance.SignIn SDK方法,并向其传入usernamepasswordrememberMe变量以及OnSuccessOnError方法。

注:
用户成功登录后,将在token参数中传入授权令牌。授权令牌在向艾克索拉服务器发送的请求中需用到。

登录页面的脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;
using Xsolla.Auth;
using Xsolla.Core;

namespace Recipes
{
    public class AuthorizationPage : MonoBehaviour
    {
        // Declaration of variables for UI elements on the page

        [SerializeField] private InputField UsernameInput;

        [SerializeField] private InputField PasswordInputField;

        [SerializeField] private Toggle RememberMeToggle;

        [SerializeField] private Button AuthorizationButton;

        private void Start()
        {
            // Handling the button click

            AuthorizationButton.onClick.AddListener(() =>
            {
                var username = UsernameInput.text;
                var password = PasswordInputField.text;
                var rememberMe = RememberMeToggle.isOn;

                XsollaAuth.Instance.SignIn(username, password, rememberMe, null, onSuccess: OnSuccess, onError: OnError);
            });
        }

        private void OnSuccess(string token)
        {
            UnityEngine.Debug.Log($"Authorization successful. Token: {token}");
            // Some actions
     }

        private void OnError(Error error)
        {
            UnityEngine.Debug.Log($"Authorization failed. Description: {error.errorMessage}");
            // Some actions
     }
    }
}

实现密码重置

本教程介绍以下逻辑的实现:

创建页面界面

为密码重置页面创建一个场景并在页面上添加以下元素:

  • 用户名/邮箱字段
  • 密码重置按钮

下图为页面结构的示例。

创建页面控制器

  1. 创建一个继承自MonoBehaviour基类的脚本ResetPasswordPage
  2. 声明网页界面元素的变量并Inspector面板中设置它们的值
  3. 添加逻辑来处理对密码重置按钮的点击:

    1. Start方法中,订阅点击事件。
    2. 添加一个在点击该按钮后调用的匿名方法。
    3. 在该方法中,声明username变量,并按页面中相应字段的值对其进行初始化。
    4. 调用XsollaAuth.Instance.ResetPassword SDK方法,并向其传入username变量以及OnSuccessOnError方法。

密码重置页面的脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;
using Xsolla.Auth;
using Xsolla.Core;

namespace Recipes
{
    public class ResetPasswordPage : MonoBehaviour
    {
        // Declaration of variables for UI elements on the page

        [SerializeField] private InputField UsernameInput;

        [SerializeField] private Button ResetPasswordButton;

        private void Start()
        {
            // Handling the button click

            ResetPasswordButton.onClick.AddListener(() =>
            {
                var username = UsernameInput.text;

                XsollaAuth.Instance.ResetPassword(username, null, OnSuccess, OnError);
            });
        }

        private void OnSuccess()
        {
            UnityEngine.Debug.Log("Password reset successful");
            // Some actions
     }

        private void OnError(Error error)
        {
            UnityEngine.Debug.Log($"Password reset failed. Description: {error.errorMessage}");
            // Some actions
     }
    }
}

成功发出密码重置请求后,用户将收到一封包含密码重置链接的邮件。在发布商帐户 > 登录管理器项目 > 常规设置 > URL > 回调URL中,您可以配置用户成功完成认证、邮箱验证或密码重置后将其重定向到的URL地址或路径。

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

社交网络帐户登录

本指南说明如何使用SDK方法实现通过社交网络帐户进行用户注册和登录。

通过用户名/邮箱地址和密码进行用户认证不同,您无需实现单独的用户注册逻辑。如果用户的首次登录是通过社交网络进行,将自动创建一个帐户。

如果您在应用程序中将社交网络登录设置为一种备选认证方法,则在满足下列条件的情况下,社交网络帐户将自动与现有用户帐户关联:

  • 已使用用户名/邮箱地址和密码注册的用户通过社交网络帐户登录您的应用程序。
  • 社交网络返回一个邮箱地址。
  • 社交网络帐户中的用户邮箱地址与注册您的应用程序时使用的邮箱地址一致。

注:
您可以实现社交网络帐户的手动关联。您可以在应用程序中添加一个让用户将社交网络帐户与帐户关联的页面。在页面控制器中,请使用LinkSocialProvider SDK方法。

本教程介绍以下逻辑的实现:

示例展示了如何设置通过Twitter帐户进行用户登录。您可以用相同的方法设置其他社交网络。

示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的认证系统实现方案。

创建页面界面

为登录页创建一个场景并在其中添加社交网络登录按钮。下图为页面结构的示例。

创建页面控制器

  1. 创建一个继承自MonoBehaviour基类的脚本SocialAuthorizationPage
  2. 声明应用程序登录页界面元素的变量并Inspector面板中设置它们的值
  3. 添加逻辑来处理对登录按钮的点击:

    1. Start方法中,订阅点击事件。
    2. 添加一个在点击该按钮后调用的匿名方法。
    3. 要传入登录页URL,请在匿名方法中声明url变量。在SocialProvider参数中传递一个Facebook值,从而通过GetSocialNetworkAuthUrl SDK方法初始化该变量。
    4. 要打开一个浏览器,请调用BrowserHelper.Instance.Open方法。如要使用内置浏览器,请向方法传入url变量和true值。

注:
社交网络登录不适用于外部浏览器。SDK包含一个由艾克索拉研发的内置浏览器。您可以使用艾克索拉内置浏览器或其他内置浏览解决方案。

    1. 要获取令牌并关闭浏览器,请跟踪用户成功登录后的页面URL变化:
      1. 声明singlePageBrowser变量并通过BrowserHelper.Instance.GetLastBrowser SDK方法对其进行初始化。
      2. 订阅有效页面URL更改事件并将OnUrlChanged方法设置为处理程序。

  1. 实现令牌获取:
    1. 使用ParseUtils.TryGetValueFromUrl工具方法解析OnUrlChanged方法中传递的活动页面URL。
    2. 添加对活动页面URL中的认证代码进行检查。ParseUtils.TryGetValueFromUrl方法在code变量中传入认证代码。
    3. 要用认证代码交换令牌,请调用ExchangeCodeToToken SDK方法并向其传入code变量和以下方法:
      • OnSuccess — 注册成功时调用
      • OnError — 发生错误时调用

注:

在脚本示例中,OnSuccessOnError方法调用标准Debug.Log方法。您还可以添加其他动作。

如果用户成功登录,将在token参数中传入授权令牌。该令牌在向艾克索拉服务器发送请求时使用。如果发生了错误,则将在error参数中传入错误代码和描述。

    1. 获取令牌后,请删除带浏览器的游戏对象

登录页面的脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;
using Xsolla.Auth;
using Xsolla.Core;

namespace Recipes
{
    public class SocialAuthorizationPage : MonoBehaviour
    {
        // Declaration of variables for UI elements on the page

        [SerializeField] private Button FacebookButton;

        private void Start()
        {
            // Handling the button click

            FacebookButton.onClick.AddListener(() =>
            {
                // Opening browser

                var url = XsollaAuth.Instance.GetSocialNetworkAuthUrl(SocialProvider.Facebook);
                BrowserHelper.Instance.Open(url, true);

                // Determining the end of authentication
             BrowserHelper.Instance.InAppBrowser.AddUrlChangeHandler(OnUrlChanged);
            });
        }

        // Getting token
     private void OnUrlChanged(string url)
        {
            if (ParseUtils.TryGetValueFromUrl(url, ParseParameter.code, out var code))
            {
                XsollaAuth.Instance.ExchangeCodeToToken(code, OnSuccess, OnError);
                Destroy(BrowserHelper.Instance.gameObject);
            }
        }

        private void OnSuccess(string token)
        {
            UnityEngine.Debug.Log($"Authorization successful. Token: {token}");
            // Some actions
     }

        private void OnError(Error error)
        {
            UnityEngine.Debug.Log($"Authorization failed. Description: {error.errorMessage}");
            // Some actions
     }
    }
}

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

显示商品目录

本教程介绍如何使用SDK方法在游戏内商店中显示以下商品:

  • 虚拟物品
  • 虚拟物品组
  • 捆绑包
  • 虚拟货币套餐

开始之前,请在发布商帐户中配置商品:

  1. 配置虚拟物品和虚拟物品组
  2. 配置虚拟货币套餐
  3. 配置捆绑包

本教程介绍以下逻辑的实现:

示例中的逻辑与界面比您实际在应用程序中的要简单得多。演示项目提供了一种可能的游戏内商店商品目录实现方案。

注:

目录中的每个商品示例显示以下内容:

  • 商品名称
  • 商品描述
  • 商品价格
  • 图片

如果游戏内商店中还存储了其他信息,也可以显示那些信息。

实现虚拟物品的显示

创建商品小组件

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

下图为小组件结构的示例。

创建商品小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本VirtualItemWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualItemWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Image IconImage;
    }
}

创建显示商品列表的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 商品小组件显示区域

下图为页面结构的示例。

创建页面控制器

  1. 创建继承自MonoBehaviour基类的脚本VirtualItemsPage
  2. 声明以下变量:
    • WidgetsContainer — 小组件的容器
    • WidgetPrefab — 商品小组件预制件

  1. 将脚本与页面游戏对象关联:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个VirtualItemsPage脚本。
  2. Inspector面板中设置变量的值。

  1. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:
    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在登录脚本示例中我们使用的是演示帐户的凭证(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取商品列表的逻辑。在OnAuthenticationSuccess方法中调用XsollaCatalog.Instance.GetCatalog SDK方法,并向其传入:
    • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

    • OnItemsRequestSuccess,用于成功的获取商品列表操作
    • OnError回调方法,用于发生错误的情况
    • 基于列表第一个商品的偏移量,包含在offset参数中
    • 加载商品的数量,包含在limit参数中

注:
offsetlimit参数非必需。它们用于分页 — 多页显示目录中的商品。页面上商品的最大数量是50。如果目录中包含的商品超过50个,则需要分页。

  1. OnItemsRequestSuccess方法中,添加为每个收到的商品创建小组件的逻辑:
    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的VirtualItemWidget组件附加到widget变量上。

  1. 将以下数据传入商品小组件:
    1. storeItem.name变量值传入商品名元素。
    2. storeItem.description变量值传入商品描述元素。
    3. 实现以下逻辑来显示商品价格:
      • 如果storeItem.price变量的值不等于null,则该商品以真实货币形式销售。请以{amount} {currency}格式指定价格并将其传入小组件元素。
      • 如果storeItem.virtual_prices变量的值不等于null,则该商品以虚拟货币形式销售。请以{name}: {amount}格式指定价格并将其传入小组件元素。

注:
storeItem.virtual_prices变量是同一商品在不同货币下的价格数组。示例显示的是发布商帐户商店 > 虚拟物品中商品设置里指定的默认价格。

    1. 要显示商品图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL。
      • 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。

页面控制器脚本示例:

Copy
Full screen
Small screen
using System.Linq;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;

namespace Recipes
{
    public class VirtualItemsPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs

        public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process

            XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for catalog from store

            XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
        }

        private void OnItemsRequestSuccess(StoreItems storeItems)
        {
            // Iterating the items collection and assign values for appropriate ui elements

            foreach (var storeItem in storeItems.items)
            {
                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<VirtualItemWidget>();

                widget.NameText.text = storeItem.name;
                widget.DescriptionText.text = storeItem.description;

                if (storeItem.price != null)
                {
                    var realMoneyPrice = storeItem.price;
                    widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
                }
                else if (storeItem.virtual_prices != null)
                {
                    var virtualCurrencyPrice = storeItem.virtual_prices.First(x => x.is_default);
                    widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
                }

                ImageLoader.Instance.GetImageAsync(storeItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

下图为脚本的运行结果。

实现虚拟物品组的显示

创建商品小组件

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

下图为小组件结构的示例。

创建商品小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本VirtualItemWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualItemWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Image IconImage;
    }
}

创建打开商品组按钮的小组件

  1. 创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. Hierarchy面板拖动一个游戏对象到Project面板,以转换预制件中创建的游戏对象。
  3. 选择一个创建的预制件,然后在Inspector面板中单击Open Prefab
  4. 将允许商品组显示的按钮添加为预制件的子对象并配置其视觉显示。

下图为小组件结构的示例。

创建打开商品组按钮的脚本

  1. 创建继承自MonoBehaviour基类的VirtualItemGroupButton脚本。
  2. 声明打开商品组按钮的变量,并在Inspector面板中设置变量的值。
  3. 向预制件的根对象添加一个脚本:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个VirtualItemGroupButton脚本。

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualItemGroupButton : MonoBehaviour
    {
        // Declaration of variables for UI elements
     public Text NameText;

        public Button Button;
    }
}

创建显示商品列表的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 商品组按钮显示区域
    • 商品小组件显示区域

下图为页面结构的示例。

创建页面控制器

  1. 创建继承自MonoBehaviour基类的VirtualItemsByGroupsPage脚本。
  2. 声明变量:
    • GroupButtonsContainer — 组按钮的容器
    • GroupButtonPrefab — 按钮预制件
    • ItemWidgetsContainer — 商品小组件容器
    • WidgetPrefab — 商品小组件预制件

  1. 将脚本附加至页面游戏对象:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个VirtualItemsByGroupsPage脚本。
  2. Inspector面板中设置变量的值。
  3. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:
    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在登录脚本示例中我们使用的是演示帐户的凭证(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取商品列表的逻辑。在OnAuthenticationSuccess方法中调用XsollaCatalog.Instance.GetCatalog SDK方法,并向其传入:
    • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

    • OnItemsRequestSuccess,用于成功的获取商品列表操作
    • OnError回调方法,用于发生错误的情况
    • 基于列表第一个商品的偏移量,包含在offset参数中
    • 加载商品的数量,包含在limit参数中

注:
offsetlimit参数非必需。它们用于分页 — 多页显示目录中的商品。页面上商品的最大数量是50。如果目录中包含的商品超过50个,则需要分页。

  1. OnItemsRequestSuccess方法中,添加形成商品组列表的逻辑:
    1. 从收到的商品列表中获取唯一组的列表。将其添加至显示所有商品(不论类别)的All元素。
    2. 删除所有子对象以清空按钮容器。方法是调用DeleteAllChildren方法,然后向其传入容器对象。
    3. 对于每个商品组:

      1. 实例化一个商品小组件预制件作为容器子对象。
      2. 将收到的VirtualItemGroupButton设置为groupButton变量。
      3. groupName变量值传入组名称元素。
      4. 向单击按钮的动作添加一个匿名方法。在该方法中,调用OnGroupSelected方法并将商品组的名称和商品列表作为参数传递。

    1. 要显示所有商品,请调用OnGroupSelected方法并传入All作为组名称。

  1. OnGroupSelected方法中,添加商品初始显示的逻辑:
    1. 创建itemsForDisplay变量并在商品组名称有All值时向其分配所有收到的商品。否则将组名称与groupName变量匹配的商品关联至itemsForDisplay变量。
    2. 删除所有子对象以清空按钮容器。方法是调用DeleteAllChildren方法,然后向其传入容器对象。

  1. 添加为每个收到的商品创建小组件的逻辑:
    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的VirtualItemWidget组件附加到widget变量上。

  1. 将以下数据传入商品小组件:
    1. storeItem.name变量值传入商品名元素。
    2. storeItem.description变量值传入商品描述元素。
    3. 实现以下逻辑来显示商品价格:

      • 如果storeItem.price变量的值不等于null,则该商品以真实货币形式销售。请以{amount} {currency}格式指定价格并将其传入小组件元素。
      • 如果storeItem.virtual_prices变量的值不等于null,则该商品以虚拟货币形式销售。请以{name}: {amount}格式指定价格并将其传入小组件元素。

注:
storeItem.virtual_prices变量是同一商品在不同货币下的价格数组。示例显示的是发布商帐户商店 > 虚拟物品中商品设置里指定的默认价格。

    1. 要显示商品图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL。
      • 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。

Copy
Full screen
Small screen
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;

namespace Recipes
{
    public class VirtualItemsByGroupsPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs
     public Transform GroupButtonsContainer;

        public GameObject GroupButtonPrefab;

        public Transform ItemWidgetsContainer;

        public GameObject ItemWidgetPrefab;

        private void Start()
        {
            // Starting the authentication process
         XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess,
                onError: OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for catalog from store
         XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0,
                limit: 50);
        }

        private void OnItemsRequestSuccess(StoreItems storeItems)
        {
            // Selecting the group’s name from items and order them alphabetical
         var groupNames = storeItems.items
                .SelectMany(x => x.groups)
                .GroupBy(x => x.name)
                .Select(x => x.First())
                .OrderBy(x => x.name)
                .Select(x => x.name)
                .ToList();

            // Add group name for “all groups”, which will mean show all items regardless of group affiliation
         groupNames.Insert(0, "All");

            // Clear container
         DeleteAllChildren(GroupButtonsContainer);

            // Iterating the group names and creating ui-button for each
         foreach (var groupName in groupNames)
            {
                var buttonObj = Instantiate(GroupButtonPrefab, GroupButtonsContainer, false);
                var groupButton = buttonObj.GetComponent<VirtualItemGroupButton>();

                groupButton.NameText.text = groupName;
                groupButton.Button.onClick.AddListener(() => OnGroupSelected(groupName, storeItems));
            }

            // Calling method for redraw page
         OnGroupSelected("All", storeItems);
        }

        private void OnGroupSelected(string groupName, StoreItems storeItems)
        {
            // Declaring variable for items which will display on page
         IEnumerable<StoreItem> itemsForDisplay;
            if (groupName == "All")
            {
                itemsForDisplay = storeItems.items;
            }
            else
            {
                itemsForDisplay = storeItems.items.Where(item => item.groups.Any(group => group.name == groupName));
            }

            // Clear container
         DeleteAllChildren(ItemWidgetsContainer);

            // Iterating the items collection and assign values for appropriate ui elements
         foreach (var storeItem in itemsForDisplay)
            {
                var widgetGo = Instantiate(ItemWidgetPrefab, ItemWidgetsContainer, false);
                var widget = widgetGo.GetComponent<VirtualItemWidget>();

                widget.NameText.text = storeItem.name;
                widget.DescriptionText.text = storeItem.description;

                if (storeItem.price != null)
                {
                    var realMoneyPrice = storeItem.price;
                    widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
                }
                else if (storeItem.virtual_prices != null)
                {
                    var virtualCurrencyPrice = storeItem.virtual_prices.First(x => x.is_default);
                    widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
                }

                ImageLoader.Instance.GetImageAsync(storeItem.image_url,
                    (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        // Utility method for delete all children of container
     private static void DeleteAllChildren(Transform parent)
        {
            var childList = parent.Cast<Transform>().ToList();
            foreach (var childTransform in childList)
            {
                Destroy(childTransform.gameObject);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

页面控制器脚本示例:

实现捆绑包的显示

创建捆绑小组件

  1. 创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. Hierarchy面板拖动一个游戏对象到Project面板,以转换预制件中创建的游戏对象。
  3. 选择一个创建的预制件,然后在Inspector面板中单击Open Prefab
  4. 将以下UI元素添加为预制件子对象并配置其视觉显示:

    • 小组件背景图片
    • 捆绑包名称
    • 捆绑包描述
    • 捆绑包价格
    • 捆绑包内容描述(商品及其数量)
    • 捆绑包图片

下图为小组件结构的示例。

创建小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本BundleWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class BundleWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements
     public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Text ContentText;

        public Image IconImage;
    }
}

创建显示捆绑包的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 捆绑包小组件显示区域

下图为页面结构的示例。

创建页面控制器

  1. 创建继承自MonoBehaviour基类的BundlesPage脚本。
  2. 声明变量:
    • WidgetsContainer — 小组件的容器
    • WidgetPrefab — 捆绑包小组件预制件

  1. 将脚本附加到页面游戏对象上:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个BundlesPage脚本。

  1. Inspector面板中设置变量的值。
  2. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:
    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在登录脚本示例中我们使用的是演示帐户的凭证(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取捆绑包列表的逻辑。在OnAuthenticationSuccess方法中调用XsollaCatalog.Instance.GetBundles SDK方法,并向其传入:
    • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

    • OnItemsRequestSuccess回调方法,用于成功的获取捆绑包列表操作
    • OnError回调方法,用于发生错误的情况

  1. OnBundlesRequestSuccess方法中,添加为每个收到的捆绑包创建小组件的逻辑:
    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的BundleWidget组件附加到widget变量上。

  1. 将以下数据传入捆绑包小组件:
    1. bundleItem.name变量值传入商品名称元素。
    2. bundleItem.description变量值传入商品描述元素。
    3. 实现以下逻辑来显示捆绑包内容:
      1. 用捆绑包中的每个商品组成一行,其中包含商品名称及其数量。该行的格式为{name} x {quantity}
      2. 将所有行组成一行,用换行符分隔。
      3. 将新行传入小组件元素。

    1. 实现以下逻辑以显示捆绑包价格:
      • 如果bundleItem.price变量的值不等于null,则该捆绑包以真实货币形式销售。请以{amount} {currency}格式指定价格并将其传入小组件元素。
      • 如果bundleItem.virtual_prices变量的值不等于null,则该捆绑包以虚拟货币形式销售。请以{name}: {amount}格式指定价格并将其传入小组件元素。

注:
bundleItem.virtual_prices变量是同一捆绑包在不同货币下的价格的数组。示例显示的是发布商帐户商店 > 捆绑包中商品设置里指定的默认价格。

    1. 要显示商品图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL。
      • 作为回调的匿名函数。在该函数中,将收到的精灵添加为捆绑包图片。

页面控制器脚本示例:

Copy
Full screen
Small screen
using System.Linq;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;

namespace Recipes
{
    public class BundlesPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs
     public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process
         XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for bundles from store
         XsollaCatalog.Instance.GetBundles(XsollaSettings.StoreProjectId, OnBundlesRequestSuccess, OnError);
        }

        private void OnBundlesRequestSuccess(BundleItems bundleItems)
        {
            // Iterating the bundles collection and assign values for appropriate ui elements
         foreach (var bundleItem in bundleItems.items)
            {
                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<BundleWidget>();

                widget.NameText.text = bundleItem.name;
                widget.DescriptionText.text = bundleItem.description;

                var bundleContent = bundleItem.content.Select(x => $"{x.name} x {x.quantity}");
                widget.ContentText.text = string.Join("\n", bundleContent);

                if (bundleItem.price != null)
                {
                    var realMoneyPrice = bundleItem.price;
                    widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
                }
                else if (bundleItem.virtual_prices != null)
                {
                    var virtualCurrencyPrice = bundleItem.virtual_prices.First(x => x.is_default);
                    widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
                }

                ImageLoader.Instance.GetImageAsync(bundleItem.image_url,
                    (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

下图为脚本的运行结果。

实现虚拟货币套餐的显示

创建虚拟货币套餐的小组件

  1. 创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. Hierarchy面板拖动一个游戏对象到Project面板,以转换预制件中创建的游戏对象。
  3. 选择一个创建的预制件,然后在Inspector面板中单击Open Prefab
  4. 将以下UI元素添加为预制件子对象并配置其视觉显示:

    • 小组件背景图片
    • 套餐名称
    • 套餐描述
    • 套餐价格
    • 套餐图片

下图为小组件结构的示例。

创建小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本VirtualCurrencyPackageWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualCurrencyPackageWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Image IconImage;
    }
}

创建显示虚拟货币套餐的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 虚拟货币套餐小组件显示区域

下图为页面结构的示例。

创建页面控制器

  1. 创建继承自MonoBehaviour基类的VirtualCurrencyPackagesPage脚本。
  2. 声明变量:
    • WidgetsContainer — 小组件的容器
    • WidgetPrefab — 虚拟货币套餐预制件

  1. 将脚本附加至页面游戏对象:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个VirtualCurrencyPackagesPage脚本。
  2. Inspector面板中设置变量的值。
  3. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:

    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在登录脚本示例中我们使用的是演示帐户的凭证(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取商品列表的逻辑。在OnAuthenticationSuccess方法中调用XsollaCatalog.Instance.GetVirtualCurrencyPackagesList SDK方法,并向其传入:
    • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

    • OnItemsRequestSuccess,用于成功的获取商品列表操作
    • OnError回调方法,用于发生错误的情况

  1. OnPackagesRequestSuccess方法中,添加为每个收到的套餐创建小组件的逻辑:
    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的VirtualCurrencyPackageWidget组件附加到widget变量上。

  1. 将以下数据传入套餐小组件:
    1. packageItem.name变量值传入套餐名元素。
    2. packageItem.description变量值传入套餐描述元素。
    3. 实现以下逻辑来显示套餐价格:

      • 如果packageItem.price变量的值不等于null,则该套餐以真实货币形式销售。请以{amount} {currency}格式指定价格并将其传入小组件元素。
      • 如果packageItem.virtual_prices变量的值不等于null,则该套餐以虚拟货币形式销售。请以{name}: {amount}格式指定价格并将其传入小组件元素。

注:
packageItem.virtual_prices变量是同一套餐在不同货币下的价格的数组。示例显示的是发布商帐户商店 > 虚拟货币 > 套餐中套餐设置里指定的默认价格。

    1. 要显示商品图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL。
      • 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。

页面控制器脚本示例:

Copy
Full screen
Small screen
using System.Linq;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;

namespace Recipes
{
    public class VirtualCurrencyPackagesPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs
     public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process
         XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for packages from store
         XsollaCatalog.Instance.GetVirtualCurrencyPackagesList(XsollaSettings.StoreProjectId, OnPackagesRequestSuccess, OnError);
        }

        private void OnPackagesRequestSuccess(VirtualCurrencyPackages packageItems)
        {
            // Iterating the packages collection and assign values for appropriate ui elements
         foreach (var packageItem in packageItems.items)
            {
                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<VirtualCurrencyPackageWidget>();

                widget.NameText.text = packageItem.name;
                widget.DescriptionText.text = packageItem.description;

                if (packageItem.price != null)
                {
                    var realMoneyPrice = packageItem.price;
                    widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";
                }
                else if (packageItem.virtual_prices != null)
                {
                    var virtualCurrencyPrice = packageItem.virtual_prices.First(x => x.is_default);
                    widget.PriceText.text = $"{virtualCurrencyPrice.name}: {virtualCurrencyPrice.amount}";
                }

                ImageLoader.Instance.GetImageAsync(packageItem.image_url,
                    (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

下图为脚本的运行结果。

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

以真实货币计价的形式销售虚拟物品

本说明主要介绍如何使用SDK方法实现以真实货币计价的形式销售虚拟物品。

开始之前,需实现在目录中显示虚拟物品。下方示例中我们描述了如何实现虚拟物品的购买。其他商品类型的配置与此类似。

本教程介绍以下逻辑的实现:

示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种以真实货币计价的形式销售商品以及显示商品目录的可能方案。

完成商品小组件

在商品小组件中添加购买按钮,并配置其显示元素。

下图为小组件结构的示例。

完成商品小组件脚本

  1. 打开VirtualItemWidget脚本。
  2. 声明购买按钮的变量并在Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualItemWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Image IconImage;

        public Button BuyButton;
    }
}

完成显示商品列表的页面控制器

  1. 打开VirtualItemsPage脚本。
  2. OnAuthenticationSuccess方法中,向Token.Instance变量传入授权令牌。

注:
您可以使用以下令牌之一:

  1. 添加处理点击虚拟物品购买按钮的逻辑:
    1. OnItemsRequestSuccess方法中,订阅按钮点击事件。
    2. 添加发生按钮点击后调用的匿名方法。
    3. 在该方法中,调用XsollaCatalog.Instance.PurchaseItem SDK方法以生成一个订单并向其传入:

      • 项目ID(projectId参数中)
      • 商品标识符(itemSku参数中)
      • OnOrderCreateSuccess方法,以处理商品购买订单的成功生成
      • OnError回调方法,用于发生错误的情况

  1. 实现支付页面的打开。方法是添加OnOrderCreateSuccess方法并在其中调用:
    • XsollaOrders.Instance.OpenPurchaseUi SDK方法,用于打开支付页面
    • TrackOrderStatus协程,用于跟踪订单状态中的改变

注:
默认情况下,支付页面在内置浏览器中打开。如要在外部浏览器中打开,请在Unity编辑器主菜单中前往Window > Xsolla > Edit Settings,然后取消勾选Inspector面板中的Enable in-app browser?复选框。如果要为Android应用使用外部浏览器,建议设置深度链接在用户完成支付后将其重定向到应用中。

  1. TrackOrderStatus协程中,实现每秒获取一次订单状态信息。方法是使用XsollaOrders.Instance.CheckOrderStatus SDK方法,并向其传入:
    • 项目ID(projectId参数中)
    • 支付详情中的订单号(orderId参数中)
    • 用于处理成功收到订单状态信息的匿名方法
    • 用于错误处理的匿名方法

  1. 在用于处理成功收到订单状态信息的匿名方法中,实现订单支付过程中的OnPurchaseSuccess方法回调(支付状态donepaid)。
  2. OnPurchaseSuccess方法中,实现成功购买虚拟物品的处理。

注:

在脚本示例中,商品购买成功时调用了Debug.Log基方法。您还可以添加其他动作,例如物品库显示等。

不需要实现向物品库添加所购商品的逻辑——它会自动完成。

  1. 如果使用内置浏览器来打开支付页面,请关闭该浏览器。

页面脚本示例:

Copy
Full screen
Small screen
using System.Collections;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;
using Xsolla.Orders;

namespace Recipes
{
    public class VirtualItemsPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs

        public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process

            XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for catalog from store
         Token.Instance = Token.Create(token);
            XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
        }

        private void OnItemsRequestSuccess(StoreItems storeItems)
        {
            // Iterating the items collection and assign values for appropriate ui elements

            foreach (var storeItem in storeItems.items)
            {
                if (storeItem.price == null)
                    continue;

                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<VirtualItemWidget>();

                widget.NameText.text = storeItem.name;
                widget.DescriptionText.text = storeItem.description;

                var realMoneyPrice = storeItem.price;
                widget.PriceText.text = $"{realMoneyPrice.amount} {realMoneyPrice.currency}";

                ImageLoader.Instance.GetImageAsync(storeItem.image_url,
                    (url, sprite) => widget.IconImage.sprite = sprite);

                widget.BuyButton.onClick.AddListener(() =>
                {
                    XsollaCatalog.Instance.PurchaseItem(XsollaSettings.StoreProjectId, storeItem.sku, OnOrderCreateSuccess, OnError);
                });
            }
        }

        private void OnOrderCreateSuccess(PurchaseData purchaseData)
        {
            XsollaOrders.Instance.OpenPurchaseUi(purchaseData);
            StartCoroutine(TrackOrderStatus(purchaseData));
        }

        private IEnumerator TrackOrderStatus(PurchaseData purchaseData)
        {
            var isDone = false;
            while (!isDone)
            {
                XsollaOrders.Instance.CheckOrderStatus
                (
                    XsollaSettings.StoreProjectId,
                    purchaseData.order_id,
                    status =>
                    {
                        if (status.status == "paid" || status.status == "done")
                        {
                            isDone = true;
                            OnPurchaseSuccess();
                        }
                    },
                    error => { OnError(error); }
                );

                yield return new WaitForSeconds(1f);
            }
        }

        private void OnPurchaseSuccess()
        {
            UnityEngine.Debug.Log($"Purchase successful");
            BrowserHelper.Instance.Close();
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

以虚拟货币计价的形式销售虚拟物品

本说明主要介绍如何使用SDK方法实现以虚拟货币计价的形式销售虚拟物品。

开始之前,需实现在目录中显示虚拟物品。下方示例中我们描述了如何实现虚拟物品的购买。其他商品类型的配置与此类似。

本教程介绍以下逻辑的实现:

示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种以真实货币计价的形式销售商品以及显示商品目录的可能方案。

完成商品小组件

在商品小组件中添加购买按钮,并配置其显示元素。

下图为小组件结构的示例。

完成商品小组件脚本

  1. 打开VirtualItemWidget脚本。
  2. 声明购买按钮的变量并在Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualItemWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text PriceText;

        public Image IconImage;

        public Button BuyButton;
    }
}

完成显示商品列表的页面控制器

  1. 打开VirtualItemsPage脚本。
  2. OnAuthenticationSuccess方法中,向Token.Instance变量传入授权令牌。

注:
您可以使用以下令牌之一:

  1. 添加处理点击虚拟物品购买按钮的逻辑:
    1. OnItemsRequestSuccess方法中,订阅按钮点击事件。
    2. 添加发生按钮点击后调用的匿名方法。
    3. 在该方法中,调用XsollaCatalog.Instance.PurchaseItem SDK方法以生成一个订单并向其传入:

      • 项目ID(projectId参数中)
      • 商品标识符(itemSku参数中)
      • OnOrderCreateSuccess方法,以处理商品购买订单的成功生成
      • OnError回调方法,用于发生错误的情况

  1. OnOrderCreateSuccess方法中,实现订单状态检查过程。方法是使用XsollaOrders.Instance.CheckOrderStatus SDK方法,并向其传入:
    • 项目ID(projectId参数中)
    • 支付详情中的订单号(orderId参数中)
    • 用于处理成功收到订单状态信息的匿名方法
    • 用于错误处理的匿名方法

  1. 在用于处理成功收到订单状态信息的匿名方法中,实现订单支付过程中的OnPurchaseSuccess方法回调(支付状态donepaid)。
  2. OnPurchaseSuccess方法中,实现成功购买虚拟物品的处理。

注:

在脚本示例中,商品购买成功时调用了Debug.Log基方法。您还可以添加其他动作,例如物品库显示虚拟货币余额更改等。

不需要实现向物品库添加所购商品的逻辑——它会自动完成。

页面脚本示例:

Copy
Full screen
Small screen
using System.Linq;
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Catalog;
using Xsolla.Core;
using Xsolla.Orders;

namespace Recipes
{
    public class VirtualItemsPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs

        public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process

            XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, onSuccess: OnAuthenticationSuccess, onError: OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for catalog from store
         Token.Instance = Token.Create(token);
            XsollaCatalog.Instance.GetCatalog(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError, offset: 0, limit: 50);
        }

        private void OnItemsRequestSuccess(StoreItems storeItems)
        {
            // Iterating the items collection and assign values for appropriate ui elements
         foreach (var storeItem in storeItems.items)
            {
                if (storeItem.virtual_prices.Length == 0)
                    continue;

                var widget = Instantiate(WidgetPrefab, WidgetsContainer, false).GetComponent<VirtualItemWidget>();

                widget.NameText.text = storeItem.name;
                widget.DescriptionText.text = storeItem.description;

                var defaultPrice = storeItem.virtual_prices.First(x => x.is_default);
                widget.PriceText.text = $"{defaultPrice.name}: {defaultPrice.amount}";

                ImageLoader.Instance.GetImageAsync(storeItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);

                widget.BuyButton.onClick.AddListener(() =>
                {
                    var price = storeItem.virtual_prices.First(x => x.is_default);
                    XsollaCatalog.Instance.PurchaseItemForVirtualCurrency(XsollaSettings.StoreProjectId, storeItem.sku, price.sku, OnOrderCreateSuccess, OnError);
                });
            }
        }

        private void OnOrderCreateSuccess(PurchaseData purchaseData)
        {
            XsollaOrders.Instance.CheckOrderStatus
            (
                XsollaSettings.StoreProjectId,
                purchaseData.order_id,
                status =>
                {
                    if (status.status == "paid" || status.status == "done")
                    {
                        OnPurchaseSuccess();
                    }
                },
                error =>
                {
                    OnError(error);
                }
            );
        }


        private void OnPurchaseSuccess()
        {
            UnityEngine.Debug.Log($"Purchase successful");
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

显示虚拟货币余额

本教程介绍如何使用SDK方法在应用中显示虚拟货币的余额。

示例中的逻辑与界面比您实际在应用程序中的要简单得多。演示项目提供了一种可能的游戏内商店商品目录实现方案。

创建显示余额的小组件

  1. 创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. Hierarchy面板拖动一个游戏对象到Project面板,以转换预制件中创建的游戏对象。
  3. 选择一个创建的预制件,然后在Inspector面板中单击Open Prefab
  4. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 小组件背景图片
    • 虚拟货币名称
    • 虚拟货币数量
    • 虚拟货币图片

下图为小组件结构的示例。

创建显示余额的小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本VirtualCurrencyWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class VirtualCurrencyWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text AmountText;

        public Image IconImage;
    }
}

创建包含虚拟货币列表的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 小组件显示区域

下图为页面结构的示例。

创建包含虚拟货币列表页面的控制器

  1. 创建继承自MonoBehaviour基类的脚本VirtualCurrenciesPage
  2. 声明以下变量:
    • WidgetsContainer — 小组件的容器
    • WidgetPrefab — 余额显示小组件预制件

  1. 将脚本附加到页面游戏对象上:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个VirtualCurrenciesPage脚本。

  1. Inspector面板中设置变量的值。
  2. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:
    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在脚本示例中,我们使用了演示帐户的凭证进行登录(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取虚拟货币列表的逻辑。方法是在OnAuthenticationSuccess方法中:
    1. 将授权令牌传入Token.Instance变量。

注:
您可以使用以下令牌之一:

    1. 调用XsollaInventory.Instance.GetVirtualCurrencyBalance SDK方法并向其传入:
      • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

      • OnBalanceRequestSuccess方法,用于获取商品列表成功的情况
      • OnError回调方法,用于发生错误的情况

  1. OnBalanceRequestSuccess方法中,添加为收到的每种虚拟货币创建小组件的逻辑:
    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的VirtualCurrencyWidget组件附加到widget变量上。

  1. 将以下数据传入余额小组件:
    1. balanceItem.name变量值传入虚拟货币名元素。
    2. balanceItem.amount.ToString()变量值传入虚拟货币数量元素。
    3. 实现以下逻辑来显示商品价格。要显示虚拟货币图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL。
      • 匿名回调函数。在该函数中,将收到的精灵添加为虚拟货币图片。

页面控制器脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Core;
using Xsolla.Inventory;

namespace Recipes
{
    public class VirtualCurrenciesPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs

        public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process

            XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for virtual currencies

            Token.Instance = Token.Create(token);
            XsollaInventory.Instance.GetVirtualCurrencyBalance(XsollaSettings.StoreProjectId, OnBalanceRequestSuccess, OnError);
        }

        private void OnBalanceRequestSuccess(VirtualCurrencyBalances balance)
        {
            // Iterating the virtual currencies list and assign values for appropriate ui elements

            foreach (var balanceItem in balance.items)
            {
                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<VirtualCurrencyWidget>();

                widget.NameText.text = balanceItem.name;
                widget.AmountText.text = balanceItem.amount.ToString();

                ImageLoader.Instance.GetImageAsync(balanceItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

下图为脚本的运行结果。

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏

显示物品库中的物品

本教程介绍如何使用SDK方法显示用户物品库中的商品。

示例中的逻辑与界面比您在应用程序中的简单得多。演示项目提供了一种可能的物品库实现方案。

创建商品小组件

  1. 创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. Hierarchy面板拖动一个游戏对象到Project面板,以转换预制件中创建的游戏对象。
  3. 选择一个创建的预制件,然后在Inspector面板中单击Open Prefab
  4. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 商品背景图片
    • 商品名称
    • 商品描述
    • 商品数量
    • 商品图片

下图为小组件结构的示例。

创建商品小组件脚本

  1. 创建一个继承自MonoBehaviour基类的脚本InventoryItemWidget
  2. 声明商品小组件界面元素的变量并Inspector面板中设置它们的值

小组件脚本的示例:

Copy
Full screen
Small screen
using UnityEngine;
using UnityEngine.UI;

namespace Recipes
{
    public class InventoryItemWidget : MonoBehaviour
    {
        // Declaration of variables for UI elements

        public Text NameText;

        public Text DescriptionText;

        public Text QuantityText;

        public Image IconImage;
    }
}

创建显示物品库的页面

  1. 在场景上创建一个空游戏对象。方法是前往主菜单,然后选择GameObject > Create Empty
  2. 将以下UI元素添加为预制件子对象并配置其视觉显示:
    • 页面背景图片
    • 商品小组件显示区域

下图为页面结构的示例。

创建页面控制器

  1. 创建继承自MonoBehaviour基类的脚本InventoryItemsPage
  2. 声明以下变量:
    • WidgetsContainer — 商品小组件的容器
    • WidgetPrefab — 商品小组件预制件

  1. 将脚本附加到页面游戏对象上:
    1. Hierarchy面板中选择一个对象。
    2. Inspector面板中,单击Add Component,然后选择一个InventoryItemsPage脚本。

  1. Inspector面板中设置变量的值。
  2. 通过在Start方法中调用XsollaAuth.Instance.SignIn SDK方法添加登录逻辑,并向其传入:
    • 用户名或邮箱地址,包含在username参数中
    • 用户密码,包含在password参数中

注:
在脚本示例中,我们使用了演示帐户的凭证进行登录(用户名:xsolla,密码:xsolla)。

    • rememberUser参数中记住帐户的标志
    • OnAuthenticationSuccess回调方法,用于成功的用户登录
    • OnError回调方法,用于发生错误的情况

  1. 添加获取物品库中商品列表的逻辑。方法是在OnAuthenticationSuccess方法中:
    1. 将授权令牌传入Token.Instance变量。

注:
您可以使用以下令牌之一:

    1. 调用XsollaInventory.Instance.GetInventoryItems SDK方法并向其传入:
      • 项目ID,包含在projectId参数中

注:
您可以在发布商帐户的项目设置中找到项目ID。脚本示例中,我们将值从SDK设置传入参数。

      • OnItemsRequestSuccess,用于获取商品列表成功的情况
      • OnError回调方法,用于发生错误的情况

  1. 对于OnItemsRequestSuccess方法中收到的每个商品,添加创建小组件的逻辑:
    1. 使用InventoryItem.IsVirtualCurrency方法添加一个检查,确保收到的商品不是虚拟货币。

注:
本例中,我们仅演示显示物品库中的虚拟物品、捆绑包和订阅。实现虚拟货币余额的显示另在单独页面上说明。

    1. 实例化一个商品小组件预制件作为容器子对象。
    2. 将收到的InventoryItemWidget组件附加到widget变量上。

  1. 将以下数据传入商品小组件:
    1. inventoryItem.name变量值传入商品名元素。
    2. inventoryItem.description变量值传入商品描述元素。
    3. inventoryItem.amount.ToString()传入商品数量元素。
    4. 要显示商品图片,请使用ImageLoader.Instance.GetImageAsync工具方法并向其传入:
      • 图片URL
      • 作为回调的匿名函数。在该函数中,将收到的精灵添加为商品图片。

页面控制器脚本示例:

Copy
Full screen
Small screen
using UnityEngine;
using Xsolla.Auth;
using Xsolla.Core;
using Xsolla.Inventory;

namespace Recipes
{
    public class InventoryItemsPage : MonoBehaviour
    {
        // Declaration of variables for containers and widget prefabs
     public Transform WidgetsContainer;

        public GameObject WidgetPrefab;

        private void Start()
        {
            // Starting the authentication process
         XsollaAuth.Instance.SignIn("xsolla", "xsolla", true, null, null, OnAuthenticationSuccess, OnError);
        }

        private void OnAuthenticationSuccess(string token)
        {
            // After successful authentication starting the request for virtual currencies
         Token.Instance = Token.Create(token);
            XsollaInventory.Instance.GetInventoryItems(XsollaSettings.StoreProjectId, OnItemsRequestSuccess, OnError);
        }

        private void OnItemsRequestSuccess(InventoryItems inventoryItems)
        {
            // Iterating the item list and assign values for appropriate ui elements

            foreach (var inventoryItem in inventoryItems.items)
            {
                if (inventoryItem.IsVirtualCurrency())
                    continue;

                var widgetGo = Instantiate(WidgetPrefab, WidgetsContainer, false);
                var widget = widgetGo.GetComponent<InventoryItemWidget>();

                widget.NameText.text = inventoryItem.name;
                widget.DescriptionText.text = inventoryItem.description;
                widget.QuantityText.text = inventoryItem.quantity.ToString();

                ImageLoader.Instance.GetImageAsync(inventoryItem.image_url, (url, sprite) => widget.IconImage.sprite = sprite);
            }
        }

        private void OnError(Error error)
        {
            UnityEngine.Debug.LogError($"Error message: {error.errorMessage}");
        }
    }
}

下图为脚本的运行结果。

本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
隐藏
您的进度
感谢您的反馈!

有用链接

上次更新时间: 2022年8月8日

发现了错别字或其他内容错误? 请选择文本,然后按Ctrl+Enter。

报告问题
我们非常重视内容质量。您的反馈将帮助我们做得更好。
请留下邮箱以便我们后续跟进
感谢您的反馈!