将网上商店集成到 Unity 游戏中
使用经过身份验证的玩家会话从 Unity 游戏打开一个网上商店。
阅读时间9 分钟最后更新于 20 天前
在 Unity 游戏中开设一个网上商店,以便玩家可以从应用内购 (IAP) 目录中购买商品。 网上商店使用您已配置的 IAP 目录和付款提供商。玩家可以在 Web 上完成购买,而无需单独的游戏内店面。 要打开商店,请添加一个游戏内操作(例如按钮),打开商店 URL,并附加玩家的身份验证会话。该会话将玩家标识到网上商店。
先决条件
开始之前,请确保您符合以下先决条件:- 集成应用内购的 Unity 项目。
- 项目中的 Authentication SDK(3.7.1 或更高版本)。
- 目标环境中的一个网上商店。
shop.unity.com/{studio}/game/{slug}从游戏中打开网上商店
使用 SDK helper
Unity IAP SDK 提供RedirectToWebshopIPaymentProvidersExtendedPurchaseServiceRedirectToWebshopcatalogListingId// 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");
在打开之前需要合规性批准
要通过合规性检查对网上商店进行门禁,请在调用RedirectToWebshopSetComplianceCheckfalsePurchasingUnavailableStoreController(PaymentProvider.Name).PaymentProvidersExtendedPurchaseService .SetComplianceCheck(async context => await ShowComplianceDialog(context));
控制网上商店的打开方式
默认情况下,SDK 在外部浏览器中打开网上商店。要更改此设置,请在重定向之前在支付提供商的IPaymentProvidersExtendedPurchaseServiceSetWebshopPresentationMode(CheckoutPresentationMode)SetCheckoutPresentationMode手动集成
如果您无法使用 SDK helper,请直接构建并打开 Webshop URL。 要通过按钮或其他游戏内操作来打开网上商店,请从网上商店服务解析商店 URL,然后使用Application.OpenURLstorefront-linkGET默认情况下,服务会根据环境状态自动返回 URL:https://webshop.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/storefront-link
- 发布的生产环境会返回实时公共店面 URL。实时 URL 会匿名解析。
- 非生产环境或未发布的生产环境会返回短暂的预览草案 URL。
source=draft集成使用以下 Authentication SDK 令牌:https://webshop.services.api.unity.com/v1/projects/{projectId}/environments/{environmentId}/storefront-link?source=draft
- 解析预览草案时,访问令牌会授权请求。在
storefront-link标头中发送访问令牌。Authorization: Bearer - 会话令牌在浏览器中对玩家进行身份验证。在开店前使用 标记创建短暂的一次性受限令牌,然后将会话令牌作为
GenerateRestrictedTokenAsync查询参数附加到解析的 URL。sessionToken
商店打开后,它会从 URL 中删除这些参数,并将玩家的会话保留在浏览器中。有关会话和持久性的更多信息,请参阅从游戏打开网上商店。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; }}
如果没有要传递的区域设置或货币,请省略这些参数。默认情况下,IAP 目录使用玩家的浏览器区域设置,默认为美元 (USD)。有关目录区域设置处理的更多信息,请参阅 Catalog and payments in webshops(目录和付款)。
处理入站深层链接
为网上商店设置 Deeplink URL 时,商店会通过该自定义 URL 方案将玩家返回到游戏中。商店会在购买后以及玩家在未验证的登录页面上选择 Connect to game 时使用返回深层链接。 要接收返回深层链接,请在设备上注册自定义 URL 方案,并在运行时处理传入链接。有关商店如何构建返回 URL 的更多信息,请参阅从游戏打开网上商店。注册 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
在运行时处理链接
订阅Application.deepLinkActivatedApplication.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试开店
在发布之前测试预览草案,然后对真实商店重复测试。要测试草案,请使用draftPreview: trueOpenShopsource=draft- 在移动设备上构建并安装游戏。
- 触发调用 的游戏内按钮以启动设备的系统浏览器。
OpenShop - 确认浏览器打开到解析的店面 URL,并在 URL 中使用您的区域和货币。草案将打开环境范围的预览 URL。开直播店。
shop.unity.com/{studio}/game/{slug} - 确认商店打开时显示的是经过身份验证的商品列表,而不是未经过身份验证的登录页面。
- 完成沙盒购买。请参阅相关 IAP 付款提供商的沙盒文档以了解测试凭据。
- 当草案按预期工作时,请向 发出
OpenShop电话,然后针对实际发布的商店重复测试。draftPreview: false
sessionTokenprojectId