内购

一、后端对接
请完成后端内购支付的接入,在后端实现对应接口后,再执行下一步操作。
未实现后端接口就进行页面对接,可能会触发平台服务器的告警。
二、客户端对接
用户支付在一个网页完成,因此客户端需要使用 SDK 在 WebView 打开指定支付页面。
SDK 方法名称
XL_OpenPayUrl 或 XL_OpenPayUrlW(宽字符接口)
C++ 调用示例
// 以下代码依赖 Windows API
#include <windows.h>
// 打开支付页面的接口导出为 XL_OpenPayUrl
HMODULE hModule = GetModuleHandle(_T("XLGameLauncher.dll"));
if (hModule || (hModule = LoadLibrary(_T("XLGameLauncher.dll"))))
{
void(WINAPI * XL_OpenPayUrl)(LPCSTR, LPCSTR);
(PVOID &)XL_OpenPayUrl = GetProcAddress(hModule, "XL_OpenPayUrl");
if (XL_OpenPayUrl)
{
// 第一个参数是支付链接,链接格式见下方文档解释
XL_OpenPayUrl("https://youxi.xunlei.com/gamepayexe?paramExt=xxxxxxxx", userId);
}
}
// 打开支付页面的宽字符接口导出为 XL_OpenPayUrlW
HMODULE hModule = GetModuleHandle(_T("XLGameLauncher.dll"));
if (hModule || (hModule = LoadLibrary(_T("XLGameLauncher.dll"))))
{
void(WINAPI * XL_OpenPayUrlW)(LPCWSTR, LPCWSTR);
(PVOID &)XL_OpenPayUrlW = GetProcAddress(hModule, "XL_OpenPayUrlW");
if (XL_OpenPayUrlW)
{
// 第一个参数是支付链接,链接格式见下方文档解释
XL_OpenPayUrlW(L"https://youxi.xunlei.com/gamepayexe?paramExt=xxxxxxxx", userId);
}
}
调用参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| 支付链接 | string | 详见支付链接章节 |
| userId | string | 平台的用户 ID |
支付链接
支付链接格式为:https://youxi.xunlei.com/gamepayexe?paramExt=xxxxxxxx ,链接中的 paramExt 参数请根据下方说明替换为实际值。
链接参数说明
支付链接有且仅有一个参数 paramExt,是一个由 JSON 经过 Base64 编码得到的字符串,JSON 需要包含的参数如下所示:
| 参数 | 类型 | 必选 | 说明 |
|---|---|---|---|
| cpOrderId | string | 是 | 游戏方的订单号 |
| userId | string | 是 | 平台的用户 ID(由平台提供) |
| gameId | string | 是 | 平台的游戏 ID(由平台提供) |
| role_id | String | 是 | 角色 ID |
| role_name | String | 是 | 角色名称 |
| serverId | string | 否 | 区服 ID |
| gameName | string | 否 | 平台的游戏名称(由平台提供) |
| productName | string | 是 | 商品名称 |
| 其他字段 | string / number | 否 | 其它自定义字段,回调游戏方接口时数据会写到 ext2 参数里面,参数不宜过多过长。 |
paramExt 参数 Base64 的加解密参考逻辑
此处使用业界通用的RFC 4648 第 4 章节描述的 Base64 版本。
URL 安全的 Base64
Base64 编码后的字符串在 URL 不能安全使用,因为这些字符串可能包含 / + = 字符,在 URL 使用可能出问题。
因此,编码后的字符串需要执行一次字符替换操作,将 / 替换为 _a,+ 替换为 _b,= 替换为 _c。Base64 解码前,按照同样的规则进行反向替换。
// 以下用 php 代码表示大致逻辑=
// 适用于 paramExt 的 Base64 编码过程
static function base_encode($str) {
// 将 JSON 字符串编码为 Base64 字符串
// base64_encode是 php 内置的 Base64 编码方法,其他编程语言请查找相关实现
$old = base64_encode($str);
// 将 Base64 编码后的字符串中的 / + = 替换成 _a _b _c ,以便作为 URL 参数传输
$src = array("/","+","=");
$dist = array("_a","_b","_c");
$new = str_replace($src,$dist,$old);
return $new;
}
// 适用于 paramExt 的 Base64 解码过程
static function base_decode($str) {
// 将字符串中的 _a _b _c 替换成 / + = ,以便 Base64 解码
$src = array("_a","_b","_c");
$dist = array("/","+","=");
$old = str_replace($src,$dist,$str);
// 将 Base64 字符串解码为 JSON 字符串
// base64_decode 是 php 内置的 Base64 编码方法,其他编程语言请查找相关实现
$new = base64_decode($old);
return $new;
}
// 举个例子
$payinfo = '{ "gameId": 6, "productName": "红宝石", "gameName": "王者荣耀", "extid": 123 }' // 标准 JSON 字符串
$paramExt = base_encode($payinfo) = 'eyAiZ2FtZUlkIjogNiwgInByb2R1Y3ROYW1lIjogIue6ouWuneefsyIsICJnYW1lTmFtZSI6ICLnjovogIXojaPogIAiLCAiZXh0aWQiOiAxMjMgfQ=='
Unity C# 代码示例
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public partial class XLGamePlatform : MonoBehaviour
{
private const string DLL_NAME = "XLGameLauncher.dll";
#region DLL Import for Payment
[DllImport(DLL_NAME, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private static extern void XL_OpenPayUrl(
[MarshalAs(UnmanagedType.LPStr)] string url,
[MarshalAs(UnmanagedType.LPStr)] string userId
);
[DllImport(DLL_NAME, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern void XL_OpenPayUrlW(
[MarshalAs(UnmanagedType.LPWStr)] string url,
[MarshalAs(UnmanagedType.LPWStr)] string userId
);
#endregion
#region Public Payment API
/// <summary>
/// 打开支付页面(内购)
/// </summary>
/// <param name="url">支付链接</param>
/// <param name="userId">平台的用户 ID</param>
public static void OpenPayUrl(string url, string userId)
{
if (!IsDllLoaded())
{
Debug.LogError("[XLGamePlatform] 迅雷游戏平台 DLL 未加载");
Debug.LogError("[XLGamePlatform] 游戏需要从迅雷游戏客户端启动才能正确使用 DLL,如有疑问请联系迅雷游戏平台技术人员");
return;
}
Debug.Log($"[XLGamePlatform] XL_OpenPayUrlW({url}, {userId})");
XL_OpenPayUrlW(url, userId);
}
/// <summary>
/// 打开支付页面(内购,ANSI 版本)
/// </summary>
public static void OpenPayUrlAnsi(string url, string userId)
{
if (!IsDllLoaded())
{
Debug.LogError("[XLGamePlatform] 迅雷游戏平台 DLL 未加载");
return;
}
Debug.Log($"[XLGamePlatform] XL_OpenPayUrl({url}, {userId})");
XL_OpenPayUrl(url, userId);
}
/// <summary>
/// URL 安全的 Base64 编码 - 遵循平台约定:
/// / 替换为 _a
/// + 替换为 _b
/// = 替换为 _c
/// </summary>
public static string Base64EncodeUrlSafe(string json)
{
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(json));
base64 = base64.Replace("/", "_a");
base64 = base64.Replace("+", "_b");
base64 = base64.Replace("=", "_c");
return base64;
}
/// <summary>
/// URL 安全的 Base64 解码
/// </summary>
public static string Base64DecodeUrlSafe(string base64)
{
base64 = base64.Replace("_a", "/");
base64 = base64.Replace("_b", "+");
base64 = base64.Replace("_c", "=");
byte[] bytes = Convert.FromBase64String(base64);
return Encoding.UTF8.GetString(bytes);
}
#endregion
#region Helper Methods
/// <summary>
/// 检查迅雷游戏平台 DLL 是否已经加载
/// </summary>
public static bool IsDllLoaded()
{
return GetModuleHandle(DLL_NAME) != IntPtr.Zero;
}
#endregion
#region Windows API
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region Payment Example
/// <summary>
/// 示例:内购支付打开链接
/// 参考:https://youxi.xunlei.com/gamepayexe?paramExt=xxxxxxxx
/// </summary>
public void OpenBuyUrl(string gameId, string userId, string cpOrderId, string productName, string roleId, string roleName, string serverId = "")
{
// 构建支付信息 JSON
Dictionary<string, object> payInfo = new Dictionary<string, object>
{
{ "cpOrderId", cpOrderId },
{ "userId", userId },
{ "gameId", gameId },
{ "role_id", roleId },
{ "role_name", roleName },
{ "serverId", serverId }
};
// 这里需要将字典序列化为 JSON 字符串
// 如果使用 Newtonsoft.Json: string json = JsonConvert.SerializeObject(payInfo);
string json = JsonUtility.ToJson(payInfo); // Unity 内置序列化
// 进行 URL 安全的 Base64 编码
string paramExt = Base64EncodeUrlSafe(json);
// 构建完整支付 URL
string payUrl = $"https://youxi.xunlei.com/gamepayexe?paramExt={paramExt}";
// 调用 SDK 打开支付页面
OpenPayUrl(payUrl, userId);
}
#endregion
}