文档

将网上商店集成到 Unity 游戏中

使用经过身份验证的玩家会话从 Unity 游戏打开一个网上商店。
阅读时间14 分钟最后更新于 3 个月前

在 Unity 游戏中开设一个网上商店,以便玩家可以从应用内购 (IAP) 目录中购买商品。
网上商店使用您已配置的 IAP 目录和付款提供商。玩家可以在 Web 上完成购买,而无需单独的游戏内店面。
要打开商店,请添加一个游戏内操作(例如按钮),打开商店 URL,并附加玩家的身份验证会话。该会话将玩家标识到网上商店。

先决条件

开始之前,请确保您符合以下先决条件:
  • 集成应用内购的 Unity 项目。
  • 项目中的 Authentication SDK(3.7.1 或更高版本)。
  • 目标环境中的一个网上商店。
要开设实体店铺,请发布网上商店,使其在
shop.unity.com/{studio}/game/{slug}
上可用。要测试草案,只需在目标环境中创建一个网上商店。
有关更多信息,请参阅创建和发布第一个网上商店。

从游戏中打开网上商店

使用 SDK helper

Unity IAP SDK 提供
RedirectToWebshop
,可让您通过所需的参数和合规性检查来开设网上商店。
通过支付提供商的
IPaymentProvidersExtendedPurchaseService
调用
RedirectToWebshop
。将
catalogListingId
留空可打开网上商店首页,或传递列表 ID 可直接打开商品页面:
// Open the front page UnityIAPServices.StoreController(PaymentProvider.Name).PaymentProvidersExtendedPurchaseService.RedirectToWebshop();// Open a specific product page UnityIAPServices.StoreController(PaymentProvider.Name).PaymentProvidersExtendedPurchaseService.RedirectToWebshop(catalogListingId: "your-listing-id");

在打开之前需要合规性批准

要通过合规性检查对网上商店进行门禁,请在调用
RedirectToWebshop
之前向
SetComplianceCheck
注册回调。回调在每次重定向之前运行。返回
false
会取消重定向并使购买失败,
PurchasingUnavailable
:
StoreController(PaymentProvider.Name).PaymentProvidersExtendedPurchaseService .SetComplianceCheck(async context => await ShowComplianceDialog(context));

控制网上商店的打开方式

默认情况下,SDK 在外部浏览器中打开网上商店。要更改此设置,请在重定向之前在支付提供商的
IPaymentProvidersExtendedPurchaseService
上调用
SetWebshopPresentationMode(CheckoutPresentationMode)
。此设置独立于
SetCheckoutPresentationMode
。

手动集成

如果您无法使用 SDK helper,请直接构建并打开 Webshop URL。
要通过按钮或其他游戏内操作来打开网上商店,请从网上商店服务解析商店 URL,然后使用
Application.OpenURL
打开 URL。
在运行时解析 URL 可以让同一版本打开已发布的商店或环境草案预览。这样可以在发布之前测试草案。
要解析 URL,请向
storefront-link
终端发送
GET
请求:
https://webshop.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/storefront-link
默认情况下,服务会根据环境状态自动返回 URL:
  • 发布的生产环境会返回实时公共店面 URL。实时 URL 会匿名解析。
  • 非生产环境或未发布的生产环境会返回短暂的预览草案 URL。
要预览真实商店的未发布更改,请添加
source=draft
查询参数。这将返回预览 URL 草案,即使对于已发布的生产环境也是如此:
https://webshop.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/storefront-link?source=draft
集成使用以下 Authentication SDK 令牌:
  • 解析预览草案时,访问令牌会授权
    storefront-link
    请求。在
    Authorization: Bearer
    标头中发送访问令牌。
  • 会话令牌在浏览器中对玩家进行身份验证。在开店前使用
    GenerateRestrictedTokenAsync
    标记创建短暂的一次性受限令牌,然后将会话令牌作为
    sessionToken
    查询参数附加到解析的 URL。
解析 URL 后,请附加会话令牌、项目 ID 和环境,以便商店为正确的玩家打开。
有关每个查询参数以及商店在缺少参数时的行为方式的更多信息,请参阅从游戏打开网上商店。
using System;using System.Collections;using System.Collections.Generic;using Unity.Services.Authentication;using UnityEngine;using UnityEngine.Networking;public class WebshopLauncher :MonoBehaviour{ // Replace these with the values from your Unity Cloud project and webshop configuration. const string ProjectId = "<your-project-id>"; const string EnvironmentId = "<your-environment-id>"; // 在 API 请求路径中使用 const string EnvironmentName = "production"; // 在商店 URL 中使用 const string StorefrontLinkEndpoint = "https://webshop.services.api.unity.com/v1/projects/{0}/environments/{1}/storefront-link"; // draftPreview: request source=draft to preview unpublished changes even on a live env. public void OpenShop(string locale, string currency, bool draftPreview = false) { StartCoroutine(OpenShopRoutine(locale, currency, draftPreview)); } IEnumerator OpenShopRoutine(string locale, string currency, bool draftPreview) { var signedIn = AuthenticationService.Instance.IsSignedIn; // The access token is required for draft previews; live storefronts open anonymously // and ignore any token sent.每当玩家登录时发送。 if (draftPreview && !signedIn) { Debug.LogWarning("WebshopLauncher: draft preview requires the player to be signed in."); return break; } // 1.向 Webshop 服务询问店面 URL。 var endpoint = string.Format(StorefrontLinkEndpoint, ProjectId, EnvironmentId); if (draftPreview) endpoint += "?source=draft"; using var request = UnityWebRequest.Get(endpoint); request.SetRequestHeader("Accept", "application/json"); if (signedIn) request.SetRequestHeader("Authorization", $"Bearer {AuthenticationService.Instance.AccessToken}"); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { Debug.LogError($"WebshopLauncher: storefront-link request failed" + $"({request.responseCode}): {request.error}"); return break; } var link = JsonUtility.FromJson<StorefrontLinkResponse>(request.downloadHandler.text); if (link == null || string.IsNullOrEmpty(link.storefrontUrl)) { Debug.LogError("WebshopLauncher: storefront-link response did not contain a storefrontUrl."); return break; } // 2.为 Webshop 重定向生成一个短暂的一次性受限令牌。 var tokenOptions = new RestrictedTokenOptions { Services = new List<string> { "no-svc" },// ID 令牌无法用于任何实际服务 SingleUse = true,// 第一次刷新时由网上商店消耗 TtlSeconds = 60, // 重定向前已最小化 }; var tokenTask = AuthenticationService.Instance.GenerateRestrictedTokenAsync(tokenOptions); yield return new WaitUntil(() => tokenTask.IsCompleted); if (tokenTask.IsFaulted) { Debug.LogError($"WebshopLauncher: failed to generate restricted token: {tokenTask.Exception}"); return break; } // 3.打开商店。 var sessionToken = tokenTask.Result.SessionToken; var shopUrl = BuildShopUrl(link.storefrontUrl, sessionToken, locale, currency); Application.OpenURL(shopUrl); } static string BuildShopUrl(string storefrontUrl, string sessionToken, string locale, string currency) { var url = storefrontUrl; url = AppendParam(url, "sessionToken", sessionToken); url = AppendParam(url, "projectId", ProjectId); url = AppendParam(url, "environment", EnvironmentName); url = AppendParam(url, "locale", locale); url = AppendParam(url, "currency", currency); return url; } static string AppendParam(string url, string key, string value) { if (string.IsNullOrEmpty(value)) return url; var separator = url.Contains("?") ? '&' : '?'; return $"{url}{separator}{key}={UnityWebRequest.EscapeURL(value)}"; } [可序列化] class StorefrontLinkResponse { public string storefrontUrl; public bool live; }}
商店打开后,它会从 URL 中删除这些参数,并将玩家的会话保留在浏览器中。有关会话和持久性的更多信息,请参阅从游戏打开网上商店。
警告
儿童隐私儿童数据法,包括但不限于美国的《儿童网络隐私保护法》(COPPA),对如何收集和使用年龄受限用户(例如,13 岁、16 岁或 18 岁以下儿童,具体年龄取决于适用法律)的数据做出了限制。除非符合 Unity 服务条款中概述的适用法律,否则您不会向 Unity 传输属于年龄限制用户的任何“个人信息”。
如果没有要传递的区域设置或货币,请省略这些参数。默认情况下,IAP 目录使用玩家的浏览器区域设置,默认为美元 (USD)。有关目录区域设置处理的更多信息,请参阅 Catalog and payments in webshops(目录和付款)。
为网上商店设置 Deeplink URL 时,商店会通过该自定义 URL 方案将玩家返回到游戏中。商店会在购买后以及玩家在未验证的登录页面上选择 Connect to game 时使用返回深层链接。
要接收返回深层链接,请在设备上注册自定义 URL 方案,并在运行时处理传入链接。有关商店如何构建返回 URL 的更多信息,请参阅从游戏打开网上商店。
注意
对于连接到游戏流程,Unity IAP SDK 会自动重新打开网上商店。您不需要自己处理该链接。
确保满足以下要求:
  • 玩家在初始化 IAP 之前登录 Unity Authentication。
  • PaymentProvider 商店已连接。
处理购买后退货使用标准平台自定义 URL 方案处理,不需要特定于 Unity 的 SDK。
注意
仅在构建的播放器中返回深层链接解析,而不是在 Unity Editor 或 WebGL 中。Editor 未注册为自定义方案的处理程序,因此从浏览器打开的链接永远不会进入播放模式,WebGL 构建将使用其页面 URL 而不是自定义方案。在设备(iOS 或 Android)或独立版本上测试返回流程。有关平台支持和注册详细信息,请参阅 Unity 的深度链接手册。

注册 URL 方案

声明与在 Dashboard(后台)中的 Deeplink URL(深度链接 URL)字段中设置的方案相同。操作系统使用 方案将链接路由到您的游戏。
  • iOS 和 macOS:在 Edit > Project Settings > Player > Other Settings > Supported URL schemes 下添加方案。Unity 在构建时将其写入构建的应用程序的
    Info.plist
    (
    CFBundleURLTypes
    )。最好不要手动编辑生成的
    Info.plist
    ,因为每次构建都会重新生成。
  • Android通过自定义主清单或 Gradle 清单模板,将带有
    <data android:scheme="mygame" />
    条目的
    intent-filter
    添加到您的活动中。
方案必须与 Deeplink URL 值完全匹配。更改 Android 清单后,重新安装游戏,以便操作系统选择新方案。
订阅
Application.deepLinkActivated
,了解游戏运行时到达的链接。在启动时,还选中
Application.absoluteURL
来处理冷启动,即深层链接启动游戏的位置。
void Awake(){ // Links that arrive while the game is running. Application.deepLinkActivated += OnReturnFromWebshop; // Cold start: the deep link launched the game. if (!string.IsNullOrEmpty(Application.absoluteURL)) OnReturnFromWebshop(Application.absoluteURL);}void OnReturnFromWebshop(string url){ // Handle the post-purchase return: the shop appends ?status=success // (and playerId when available) after a completed purchase. if (new Uri(url).Query.Contains("status=success")) { // Purchase completed on the web — refresh the player's entitlements. } // The Connect to game sign-in link is reopened by the SDK automatically, // so it needs no handling here.}
商店仅发送
status=success
,因此请在此处处理该案例。SDK 会自动重新打开 Connect to game 登录链接,如上一条中所述。

试开店

在发布之前测试预览草案,然后对真实商店重复测试。要测试草案,请使用
draftPreview: true
调用
OpenShop
并确认玩家已登录。您可以以非生产环境为目标,或使用
source=draft
预览生产环境中未发布的更改。
要验证集成,请执行以下步骤:
  1. 在移动设备上构建并安装游戏。
  2. 触发调用
    OpenShop
    的游戏内按钮以启动设备的系统浏览器。
  3. 确认浏览器打开到解析的店面 URL,并在 URL 中使用您的区域和货币。草案将打开环境范围的预览 URL。
    shop.unity.com/{studio}/game/{slug}
    开直播店。
  4. 确认商店打开时显示的是经过身份验证的商品列表,而不是未经过身份验证的登录页面。
  5. 完成沙盒购买。请参阅相关 IAP 付款提供商的沙盒文档以了解测试凭据。
  6. 当草案按预期工作时,请向
    OpenShop
    发出
    draftPreview: false
    电话,然后针对实际发布的商店重复测试。
如果商店打开时显示的是未经身份验证的登录页面而不是商品列表,请确认游戏通过了 URL 的有效
sessionToken
和
projectId
。请参阅 Webshop 故障排除。