开发指南
查询商品信息
这里的商品信息是指【苹果商品信息】、【谷歌商品信息】和 【Steam 商品信息】,不支持【网页商品信息】。通过此方法,传入对应平台的商品集合 productIds,可查询游戏在 Apple Store/Google Play/Steam 平台中设定的内购商品包含货币符号、货币价格等 sku 信息,具体信息可参见下文 商品数据结构定义。
- Android
- iOS
- Unity
- UE
// PaymentActivity.java
import com.xd.intl.payment.XDGPayment;
import com.xd.intl.payment.callback.XDGPaymentCallback;
import com.xd.intl.payment.constant.Constants;
import com.xd.intl.payment.entities.GoogleProductDetails;
import com.xd.intl.payment.wallet.XDGPaymentResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
// ...
private void queryProductIds() {
// 需要查询的商品 ID 集合 (Google Play 定义的商品 ID)
List<String> productIds = new ArrayList<>(Arrays.asList("product1", "product2"));
// 支付结果回调
XDGPaymentCallback<List<GoogleProductDetails>> callback = new XDGPaymentCallback<List<GoogleProductDetails>>() {
@Override
public void onPaymentCallback(XDGPaymentResult result, List<GoogleProductDetails> data) {
if (result.code == Constants.PaymentResponseCode.OK) {
if (data != null && !data.isEmpty()) {
// 查询成功
// queryProductsSuccess();
} else {
// 查询商品为空
}
} else {
// 查询失败
}
}
};
XDGPayment.queryWithProductIds(productIds, callback);
}
// ...
/** 查询商品价格,请等待回调之后再做下一次查询,否则可能造成数据错乱
* @param productIds 需要查询的商品名数组
*/
NSArray *procudtIds = @[@"com.xd.sdkdemo1.stone30", @"com.xd.sdkdemo1.stone50"];
[XDGPayment queryWithProductIds:procudtIds completionHandler:^(NSArray<XDGProductInfo *> * _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"查询失败 %@", error);
} else {
// 查询成功, result 是查询结果
}
}];
XDGPayment.QueryWithProductIds(string[] productIds, info => {
if (info.xdgError != null){
} else{
}
});
FXDGPayment::QueryWithProductIds(
{/** Id array */},
FXDGProductInfo::FArrayDelegate::CreateLambda([](const TArray<FXDGProductInfo>& Infos) {
//成功
}),
FXDGError::FDelegate::CreateLambda([](const FXDGError& Error) {
//失败
}));
商品数据结构定义
- Android
- iOS
- Unity
- UE
详情请参考 GoogleProductDetails 类。
@interface XDGProductInfo : NSObject
// 本地化商品描述
@property(nonatomic,strong,readonly) NSString *localizedDescription;
// 本地化商品标题
@property(nonatomic,strong,readonly) NSString *localizedTitle;
// 价格
@property(nonatomic,strong,readonly) NSDecimalNumber *price;
// 价格本地化信息(包含货币符号等)
@property(nonatomic,strong,readonly) NSLocale *priceLocale;
// 商品ID
@property(nonatomic,strong,readonly) NSString *productIdentifier;
@end
// Unity 在不同平台返回的商品类型相同,但字段不同
#if UNITY_IOS
[Serializable]
public class SkuDetailBean
{
// 本地化商品描述
public string localizedDescription;
// 本地化商品标题
public string localizedTitle;
// 价格
public double price;
// 商品ID
public string productIdentifier;
// 本地化标识
public string localeIdentifier;
// 价格本地化信息(包含货币符号等)
public PriceLocale priceLocale;
}
#elif UNITY_ANDROID
[Serializable]
public class SkuDetailBean
{
// 原始 json 字符串
private string _originString;
// 商品描述
public string description;
// 商品名称
public string name;
// 商品 ID
public string productId;
// Google 结算库 BillingClient.ProductType 的类型: BillingClient.ProductType.INAPP(inapp)、BillingClient.ProductType.SUBS(subs)
public string productType;
// 正在销售的产品的标题
public string title;
// 一次性购买商品详情
public GoogleOneTimePurchaseOfferDetails googleOneTimePurchaseOfferDetails;
}
#else
public class SkuDetailBean
{
// 商品名称
public string ProductSkuName { get; set; }
// 商品sku
public string ProductSkuCode { get; set; }
// 商品描述
public string Desc { get; set; }
// 渠道商品sku
public string ChannelSkuCode { get; set; }
// 货币
public string Currency { get; set; }
// 地区
public string Region { get; set; }
// 原价
public double CostPrice { get; set; }
// 现价
public double SalePrice { get; set; }
}
#endif
struct XDGPAYMENT_API FXDGProductInfo
{
//苹果支付
#if PLATFORM_IOS
/** 本地化商品描述 */
FString LocalizedDescription;
/** 本地化商品标题 */
FString LocalizedTitle;
/** 价格 */
double Price;
struct FPriceLocale
{
FString LocaleIdentifier;
FString LanguageCode;
FString CountryCode;
FString ScriptCode;
FString CalendarIdentifier;
FString DecimalSeparator;
FString CurrencySymbol;
};
/** 价格本地化信息(包含货币符号等) */
FPriceLocale PriceLocale;
/** 商品ID */
FString ProductIdentifier;
#endif
//谷歌支付
#if PLATFORM_ANDROID
/** 原始 json 字符串 */
FString OriginString;
/** 商品描述 */
FString Description;
/** 商品名称 */
FString Name;
/** 商品 ID */
FString ProductId;
/** Google 结算库 BillingClient.ProductType 的类型: BillingClient.ProductType.INAPP(inapp)、BillingClient.ProductType.SUBS(subs) */
FString ProductType;
/** 正在销售的产品的标题 */
FString Title;
struct GoogleOneTimePurchaseOfferDetails
{
FString FormattedPrice;
long PriceAmountMicros = 0;
FString PriceCurrencyCode;
};
/** 一次性购买商品详情 */
GoogleOneTimePurchaseOfferDetails OneTimePurchaseOfferDetails;
//Steam支付
#elif PLATFORM_WINDOWS || PLATFORM_MAC
#if defined ENABLE_STEAM_LOGIN
/** 商品名称 */
FString productSkuName;
/** 商品sku */
FString productSkuCode;
/** 商品描述 */
FString desc;
/** 渠道商品sku */
FString channelSkuCode;
/** 货币 */
FString currency;
/** 地区 */
FString region;
/** 原价 */
double costPrice = 0.0;
/** 现价 */
double salePrice = 0.0;
#endif
#endif
};
商店平台支付
这里支付指的是【苹果支付】,【谷歌支付】和【Steam 支付】
- 苹果和谷歌支付需要同时在苹果或谷歌后台和 XDSDK 平台中配置商品信息,在接口中使用的 productId 为苹果或谷歌后台的商品 ID
- Steam 支付则只需要在 XDSDK 平台配置商品信息,在接口中使用的 productId 为平台配置的商品 ID
SDK 会在对应平台调用系统级别的支付功能进行商品的购买。游戏传入的支付参数会在支付完成时通过 s2s 的形式透传回游戏的 Server 端以便游戏进行校验和发货。
- 这里的回调只当做【支付完成】看待,【支付成功】需要对接 XDServer 后,以服务端推送信息为准。
- 由于 Apple 支付票据有概率会出现多票据合并的情况,此时会丢失游戏传入的 orderId,并由平台随机生成一个唯一的 orderId。
发起商品购买
- SDK 在 v6.23.0 中增加了新接口支持 Apple 的批量购买,需要设置
quantity
的值。 - 关于 Google 结算库的批量购买无法通过 SDK
quantity
字段直接指定,详情请参考Google Pay 接入指引 - 老接口仍然可以使用,但将无法支持部分新增功能。
- Android
- iOS
- Unity
- UE
使用 PaymentParams 类来构造支付参数。
// PaymentActivity.java
import com.xd.intl.payment.XDGPayment;
import com.xd.intl.payment.api.PaymentParams;
import com.xd.intl.payment.callback.XDGPaymentCallback;
import com.xd.intl.payment.constant.Constants;
import com.xd.intl.payment.wallet.XDGPaymentResult;
// ...
private void initiatePayment() {
PaymentParams paymentParams = PaymentParams.newBuilder()
.setGameOrderId("gameOrderId") // 订单 ID。游戏侧订单号,服务端支付回调会包含该字段,如无该字段,传空
.setProductId("productId") // 商品 ID。Google Play 定义的商品 ID
.setRoleId("roleId") // 角色 ID。支付角色 ID,服务端支付回调会包含该字段
.setServerId("serverId") // 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
.setExt("ext") // 附加信息。服务端支付回调会包含该字段
.build();
// 支付结果回调
XDGPaymentCallback<Object> callback = new XDGPaymentCallback<Object>() {
@Override
public void onPaymentCallback(XDGPaymentResult result, Object data) {
if (result.code == Constants.PaymentResponseCode.OK) {
// 支付成功
} else {
// 支付失败
}
}
};
XDGPayment.initiatePayment(PaymentActivity.this, paymentParams, callback);
}
// ...
XDGPaymentParams *params = [XDGPaymentParams new];
params.gameOrderId = @"可选,游戏侧订单号,不填会自动生成随机订单号";
params.productId = @"必须,在苹果后台配置的商品 ID";
params.roleId = @"必须,角色 ID";
params.serverId = @"必须,服务器 ID";
params.ext = @"可选,透传参数";
params.quantity = 1; // 购买数量,限制为 1-10
[XDGPayment payWithParams:params completionHandler:^(XDGOrderInfo * _Nullable orderInfo, NSError * _Nullable error) {
if (error) {
// 支付失败
} else {
// 支付成功
}
}];
XDGPaymentParams paymentParams = new XDGPaymentParams(
"可选,游戏侧订单号,不填会自动生成随机订单号",
"必须,在苹果后台配置的商品 ID",
"必须,角色 ID",
"必须,服务器 ID",
"可选,透传参数",
1);// 购买数量,限制为 1-10,默认为 1,只对 Apple 支付生效
XDGPayment.PayWithParams(paymentParams,
resultWrapper =>
{
if (resultWrapper.xdgError != null)
{
SetResultText($"Wrapper支付异常: {JsonConvert.SerializeObject(resultWrapper.xdgError, Formatting.Indented)}");
}
else
{
SetResultText($"Wrapper 支付完成: {JsonConvert.SerializeObject(resultWrapper.orderInfo, Formatting.Indented)}");
}
});
FXdgPaymentParams Params;
Params.GameOrderId = TEXT("游戏订单号。可以为空,为空时 SDK 会自动生成");
Params.ProductId = TEXT("商品ID。不建议为空");
Params.RoleId = TEXT("角色 ID。不建议为空");
Params.ServerId = TEXT("服务器 ID。不建议为空");
Params.Ext = TEXT("扩展字段。可以为空,透传给游戏服务器");
Params.Quantity = 1;// 购买数量,限制为 1-10,默认为 1,只对 Apple 支付生效
FXDGPayment::PayWithParams(Params, FXdgDelegate<FXDGOrderInfo>::CreateLambda([](FXdgResult<FXDGOrderInfo>& Result)
{
if (Result.HasValue())
{
FXDGOrderInfo& InfoRef = Result.GetValue(); // 成功
}
else
{
FXDGError& ErrorRef = Result.GetError(); // 失败
}
}));
支付老接口,可以继续使用,但可能不支持部分新功能
- Android
- iOS
- Unity
- UE
// PaymentActivity.java
import com.xd.intl.payment.XDGPayment;
import com.xd.intl.payment.callback.XDGPaymentCallback;
import com.xd.intl.payment.constant.Constants;
import com.xd.intl.payment.wallet.XDGPaymentResult;
// ...
private void payWithProduct() {
// 支付结果回调
XDGPaymentCallback<Object> callback = new XDGPaymentCallback<Object>() {
@Override
public void onPaymentCallback(XDGPaymentResult result, Object data) {
if (result.code == Constants.PaymentResponseCode.OK) {
// 支付成功
} else {
// 支付失败
}
}
};
XDGPayment.payWithProduct(
"gameOrderId", // 订单 ID。游戏侧订单号,服务端支付回调会包含该字段,如无该字段,传空
"productId", // 商品 ID。Google Play 定义的商品 ID
"roleId", // 角色 ID。支付角色 ID,服务端支付回调会包含该字段
"serverId", // 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
"ext", // 附加信息。服务端支付回调会包含该字段
callback
);
}
// ...
/**
* @param orderId 订单 ID。游戏侧订单号,服务端支付回调会包含该字段。如果无,传空字符串。
* @param productId 商品 ID。到 AppStore 购买的商品 ID
* @param roleId 角色 ID。支付角色 ID,服务端支付回调会包含该字段
* @param serverId 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
* @param ext 透传参数。服务端支付回调会包含该字段。可用于标记区分充值回调地址 (此字段长度不能超过 255 个字符)
* @param completionHandler 支付结果处理
*/
[XDGPayment payWithOrderId:@"" productId:productId roleId:roleId serverId:serverId ext:@"gagag" completionHandler:^(XDGOrderInfo * _Nonnull orderInfo, NSError * _Nonnull error) {
if (error) {
// 支付失败
} else {
// 支付成功,为了确保可靠性,建议支付成功对接服务端回调
}
}];
/**
* @param orderId 订单 ID。游戏侧订单号,服务端支付回调会包含该字段。如果无,传空字符串。
* @param productId 商品 ID。到 AppStore 购买的商品 ID
* @param roleId 角色 ID。支付角色 ID,服务端支付回调会包含该字段
* @param serverId 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
* @param ext 透传参数。服务端支付回调会包含该字段。可用于标记区分充值回调地址 (此字段长度不能超过 255 个字符)
* @param callback 支付结果处理
*/
XDGPayment.PayWithProduct(string orderId, string productId, string roleId, string serverId, string ext, Action<XDGOrderInfoWrapper> callback);
FXDGOrderInfo::FDelegate CompleteBlock = FXDGOrderInfo::FDelegate::CreateLambda([](const FXDGOrderInfo& OrderInfo) {
});
FXDGError::FDelegate ErrorDelegate = FXDGError::FDelegate::CreateLambda([](const FXDGError& Error) {
});
/**
* @param OrderIDStr 订单 ID。游戏侧订单号,服务端支付回调会包含该字段。如果无,传空字符串。
* @param ProductIDStr 商品 ID。到 AppStore 购买的商品 ID
* @param RoleIDStr 角色 ID。支付角色 ID,服务端支付回调会包含该字段
* @param ServerIDStr 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
* @param ExtStr 透传参数。服务端支付回调会包含该字段。可用于标记区分充值回调地址 (此字段长度不能超过 255 个字符)
* @param CompleteBlock 支付成功结果处理
* @param ErrorDelegate 支付错误结果处理
*/
FXDGPayment::PayWithProduct(OrderIDStr, ProductIDStr, RoleIDStr, ServerIDStr, ExtStr, CompleteBlock, ErrorDelegate);
订单数据结构定义
- Android
- iOS
- Unity
- UE
@interface XDGOrderInfo : NSObject
/// 游戏侧订单号
@property (nonatomic,copy,readonly) NSString *outTradeNo;
/// 商品 ID
@property (nonatomic,copy,readonly) NSString *productIdentifier;
/// 角色所在服务器 ID
@property (nonatomic,copy,readonly) NSString *serverId;
/// 角色 ID
@property (nonatomic,copy,readonly) NSString *roleId;
/// 当前订单所用货币
@property (nonatomic,copy,readonly) NSString *currency;
/// 当前订单价格
@property (nonatomic,strong,readonly) NSDecimalNumber *price;
@end
public class XDGOrderInfo
{
// 游戏侧订单号
public string orderId;
// 商品 ID
public string productId;
// 角色 ID
public string roleId;
// 角色所在服务器 ID
public string serverId;
// 透传参数
public string ext;
}
struct XDGPAYMENT_API FXDGOrderInfo
{
/** 订单号 */
FString OrderId;
/** 商品 ID */
FString ProductId;
/** 角色所在服务器ID */
FString ServerId;
/** 角色 ID */
FString RoleId;
};
网页支付(Android、PC)
安卓未上架 Google Play 平台的游戏或者 PC 平台的游戏可使用网页支付的形式进行游戏内的商品购买,同样的游戏定义的商品信息需要在平台中进行配置。 在网页支付中,因支付渠道回调可能存在延迟或用户误触关闭按钮的缘故,SDK 的支付回调的含义仅包含「支付完成」、「支付取消」、「其他错误」,游戏可通过回调作为触发点,通过轮询的方式查询支付最终的结果。
这里的回调也是当做【支付完成】看待,【支付成功】需要对接 XDServer 后,以服务端推送信息为准!
- Android
- Unity
- UE
// PaymentActivity.java
import com.xd.intl.payment.XDGPayment;
import com.xd.intl.payment.callback.XDGPaymentCallback;
import com.xd.intl.payment.constant.Constants;
import com.xd.intl.payment.wallet.XDGPaymentResult;
// ...
private void payWithWeb() {
// 支付结果回调
XDGPaymentCallback<Object> callback = new XDGPaymentCallback<Object>() {
@Override
public void onPaymentCallback(XDGPaymentResult result, Object data) {
if (result.code == Constants.PaymentResponseCode.OK) {
// 支付完成
} else {
// 支付失败
}
}
};
XDGPayment.payWithWeb(
"gameOrderId", // 订单 ID。游戏侧订单号,服务端支付回调会包含该字段,如无该字段,传空。
"productId", // 商品 ID。游戏的商品ID,必填
"productName", // 商品名称。用于内嵌支付内部显示,必填
1.00, // 商品价格,必填
"roleId", // 角色 ID。支付角色 ID,服务端支付回调会包含该字段,必填
"serverId", // 服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段,必填
"extras", // 附加信息。服务端支付回调会包含该字段,必填
callback
);
}
// ...
XDGPayment.PayWithWeb(
orderId,
productId,
productName,
price,
roleId,
serverId,
extras,
(type, msg) => {
});
type:
OK 完成
Cancel 取消
Processing 处理中
Error 失败
public class PaymentConstants
{
public static class PaymentResponseCode
{
public static int OK = 0; // 支付完成
public static int ERROR = -1; // 支付错误
public static int NETWORK_ERROR = -2; // 网络错误
public static int USER_CANCEL = 1; // 用户取消
public static int PURCHASE_PROCESSING = 2; // 支付处理中
}
}
FXDGPayment::FPayResultCodeDelegate Delegate = FXDGPayment::FPayResultCodeDelegate::CreateLambda([](EXDGPayResultCode ResultCode, const FString& Message) {
FString Result = "Unknow Code";
if (ResultCode == EXDGPayResultCode::OK) {
Result = TEXT("支付完成");
} else if (ResultCode == EXDGPayResultCode::Error) {
Result = TEXT("支付错误");
} else if (ResultCode == EXDGPayResultCode::NetworkError) {
Result = TEXT("网络错误");
} else if (ResultCode == EXDGPayResultCode::UserCancel) {
Result = TEXT("支付取消");
} else if (ResultCode == EXDGPayResultCode::PurchaseProcessing) {
Result = TEXT("支付处理中");
}
});
FXDGPayment::PayWithWeb(ServerIDStr, RoleIDStr, ProductIDStr, OrderIDStr, ProductNameStr, PayAmount, ExtrasStr, Delegate);
Android 原生支付(国内)
XDSDK 在 6.10.1 的版本开始针对 Android 平台增加了支付宝、微信的原生支付,内部会判断是否在 TapTap 沙盒
或 TapTap 云玩
环境,在此环境会继续走网页支付的流程,游戏在国内环境中可调用下列方法进行支付宝、微信的原生支付。
- Android
- iOS
- Unity
- UE
// PaymentActivity.java
import com.xd.intl.payment.XDGPayment;
import com.xd.intl.payment.callback.XDGPaymentCallback;
import com.xd.intl.payment.constant.Constants;
import com.xd.intl.payment.wallet.XDGPaymentResult;
// ...
private void pay() {
// 支付结果回调
XDGPaymentCallback<Object> callback = new XDGPaymentCallback<Object>() {
@Override
public void onPaymentCallback(XDGPaymentResult result, Object data) {
if (result != null) {
int code = result.code;
if (com.xd.intl.payment.constant.Constants.PaymentResponseCode.OK == code) {
// 支付成功
} else if (com.xd.intl.payment.constant.Constants.PaymentResponseCode.USER_CANCEL == code) {
// 支付取消
} else {
// 支付失败
}
}
}
};
// 支付参数指定
PayDetailsParams params = PayDetailsParams.newBuilder()
.setGameOrderId("gameOrderId") // 游戏订单 ID。游戏侧订单号,服务端支付回调会包含该字段,不建议为空,如无该字段,传空
.setProductId("productId") // 游戏商品 ID。不可为空
.setProductName("productName") // 游戏商品名称。走 Web 支付时 UI 预显示字段,可为空
.setPayAmount(1.0) // 商品价格。单位(元),走 Web 支付时 UI 预显示字段,可为 0
.setRoleId("roleId") // 游戏角色 ID。支付角色 ID,服务端支付回调会包含该字段
.setServerId("serverId") // 游戏服务器 ID。所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
.setExt("ext") // 附加参数。服务端支付回调会包含该字段
.build();
// SDK 内置 UI 支付
XDGPayment.pay(params, callback);
String payType = PayType.WECHAT_PAY; // 指定微信支付方式,支付宝支付方式为:PayType.ALIPAY
// 无 UI 支付
XDGPayment.pay(payType, params, callback);
}
// ...
// 该方法仅针对 Android 平台,iOS 暂不支持。
/// <summary>
/// 微信支付和支付宝支付的原生实现,带 UI 方式
/// </summary>
/// <param name="orderId"> 游戏订单 ID。游戏侧订单号,服务端支付回调会包含该字段,不建议为空,如无该字段,传空。</param>
/// <param name="productId">游戏商品 ID,不可为空</param>
/// <param name="productName">游戏商品名称,走 Web 支付时 UI 预显示字段,可为空</param>
/// <param name="payAmount">商品价格,单位(元),走 Web 支付时 UI 预显示字段,可为 0</param>
/// <param name="roleId">游戏角色 ID,支付角色 ID,服务端支付回调会包含该字段</param>
/// <param name="serverId">游戏服务器 ID,所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段</param>
/// <param name="ext">附加信息。服务端支付回调会包含该字段</param>
/// <param name="callback">支付回调:正常支付完成信息会在 callback.orderInfo 中,如果发生错误会在 callback.xdgError 字段中进行提示</param>
public static void Pay(string orderId,
string productId,
string productName,
double payAmount,
string roleId,
string serverId,
string ext,
Action<XDGOrderInfoWrapper> callback);
// 下面是带 UI 方式的示例代码
var orderId = "your_order_id";
var productId = "your_product_id";
var productName = "your_product_name";
double payAmount = 0.2;// your_price
var roleId = "player_role_id";
var serverId = "your_server_id";
var ext = "your_ext";
XDGPayment.Pay(
orderId,
productId,
productName,
payAmount,
roleId,
serverId,
ext,
(x) => {
if (x == null){
Debug.LogErrorFormat( $"PayWithUI 支付结果: NULL");
}
else{
var errorMsg = x.xdgError?.error_msg ?? "NULL";
var orderInfo = JsonUtility.ToJson(x.orderInfo) ?? "NULL";
Debug.LogFormat( $"PayWithUI 支付结果: {orderInfo} 错误信息:{errorMsg}");
}
});
/// <summary>
/// 微信支付和支付宝支付的原生实现,不带 UI 方式
/// </summary>
/// <param name="payType">游戏订单支付方式,目前一共有 2 种:Alipay-支付宝;WechatPay-微信支付</param>
/// <param name="orderId">游戏订单 ID。游戏侧订单号,服务端支付回调会包含该字段,不建议为空,如无该字段,传空</param>
/// <param name="productId">游戏商品 ID,不可为空</param>
/// <param name="productName">游戏商品名称,走 Web 支付时 UI 预显示字段,可为空</param>
/// <param name="payAmount">商品价格,单位(元),走 Web 支付时 UI 预显示字段,可为 0</param>
/// <param name="roleId">游戏角色 ID,支付角色 ID,服务端支付回调会包含该字段</param>
/// <param name="serverId">游戏服务器 ID,所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段</param>
/// <param name="ext">附加信息。服务端支付回调会包含该字段</param>
/// <param name="callback">支付回调:正常支付完成信息会在 callback.orderInfo 中,如果发生错误会在 xdgError 字段中进行提示</param>
public static void Pay(PayType payType,
string orderId,
string productId,
string productName,
double payAmount,
string roleId,
string serverId,
string ext,
Action<XDGOrderInfoWrapper> callback);
// 下面是不带 UI 方式的示例代码
var payType = PayType.Alipay;//PayType.Alipay-支付宝,PayType.WechatPay-微信
var orderId = "your_order_id";
var productId = "your_product_id";
var productName = "your_product_name";
double payAmount = 0.2;// your_price
var roleId = "player_role_id";
var serverId = "your_server_id";
var ext = "your_ext";
XDGPayment.Pay(
payType,
orderId,
productId,
productName,
payAmount,
roleId,
serverId,
ext,
(x) => {
if (x == null){
Debug.LogErrorFormat( $"PayWithUI 支付结果: NULL");
}
else{
var errorMsg = x.xdgError?.error_msg ?? "NULL";
var orderInfo = JsonUtility.ToJson(x.orderInfo) ?? "NULL";
Debug.LogFormat( $"PayWithUI 支付结果: {orderInfo} 错误信息:{errorMsg}");
}
});
FXDGPayDetailsParams Params;
Params.GameOrderId = TEXT("游戏订单 ID"); // 游戏订单 ID。游戏侧订单号,服务端支付回调会包含该字段,不建议为空,如无该字段,传空。
Params.ProductId = TEXT("游戏商品 ID"); // 游戏商品 ID,不可为空
Params.ProductName = TEXT("游戏商品名称"); // 游戏商品名称,走 Web 支付时 UI 预显示字段,可为空
Params.PayAmount = 0; // 商品价格,单位(元),走 Web 支付时 UI 预显示字段,可为 0
Params.RoleId = TEXT("游戏角色 ID"); // 游戏角色 ID,支付角色 ID,服务端支付回调会包含该字段
Params.ServerId = TEXT("游戏服务器 ID"); // 游戏服务器 ID,所在服务器 ID,不能有特殊字符,服务端支付回调会包含该字段
Params.Ext = TEXT("附加参数"); // 附加信息。服务端支付回调会包含该字段
FXDGPayment::FPayResultCodeDelegate Delegate = FXDGPayment::FPayResultCodeDelegate::CreateLambda([](EXDGPayResultCode ResultCode, const FString& Message) {
FString Result = "Unknow Code";
if (ResultCode == EXDGPayResultCode::OK) {
Result = TEXT("支付完成");
} else if (ResultCode == EXDGPayResultCode::Error) {
Result = TEXT("支付错误");
} else if (ResultCode == EXDGPayResultCode::NetworkError) {
Result = TEXT("网络错误");
} else if (ResultCode == EXDGPayResultCode::UserCancel) {
Result = TEXT("支付取消");
} else if (ResultCode == EXDGPayResultCode::PurchaseProcessing) {
Result = TEXT("支付处理中");
}
});
// SDK 内置 UI 支付
FXDGPayment::Pay(Params, Delegate);
// 无 UI 支付
EXDGPayType PayType = EXDGPayType::WeChatPay; // 指定微信支付方式,支付宝支付方式为:EXDGPayType::AliPay
FXDGPayment::Pay(PayType, Params, Delegate);
应用外购买或掉单
当游戏需要支持 Apple 提供的商店兑换码(暂不支持 Google 商店)进行内购或者处理异常情况下的消费掉单时,需要使用如下的两个方法进行处理。
首先使用查询接口获取当前已知的兑换码订单或者掉单数据,游戏需要通过返回结果内的数据来和玩家确认商品信息和发放角色,然后使用兑换或补单接口进行订单确认和消费。
查询订单数据
- Android
- iOS
- Unity
- UE
// 暂不支持
[XDGPayment queryRestoredPurchases:^(NSArray<XDGTransactionInfo *> * _Nonnull result) {
}];
// 查询礼包码或掉单数据
XDGPayment.QueryRestoredPurchase(restoredPurchases =>
{
if (restoredPurchases == null || restoredPurchases.Count == 0)
{
// 没有需要恢复的购买
}
else
{
foreach (var restoredPurchase in restoredPurchases)
{
// 此处仅为方便展示使用 foreach,实际支付请替换成队列或其他形式,不要在一个订单还没消费完成前进行下一笔消费。
string productId = restoredPurchase.productId;
if ("礼包码对应的商品ID".Equals(productId))
{
// 礼包码发放确认弹窗,用户确认之后走 XDGPayment.RestorePurchase 消费订单
}
else
{
// 掉单数据发放确认弹窗,用户确认之后走 XDGPayment.RestorePurchase 消费订单
}
}
}
});
FXDGPayment::QueryRestoredPurchases(FXDGTransactionInfo::FArrayDelegate::CreateLambda([Printer, this](const TArray<FXDGTransactionInfo>& Infos)
{
// Infos 是返回的交易信息
}));
礼包码兑换或掉单补单
在上述方法中返回的未完成订单,游戏可传入对应的参数进行 Apple/Google 的商品消费确认以保证用户购买的商品正常使用。
- Android
- iOS
- Unity
- UE
// 暂不支持
XDGTransactionInfo *transInfo = [[XDGTransactionInfo alloc] init];
[transInfo setValue:transactionIdentifier forKey:@"transactionIdentifier"];
[transInfo setValue:productIdentifier forKey:@"productIdentifier"];
[XDGPayment restorePurchase:transInfo orderId:orderId roleId:roleId serverId:serverId ext:ext completionHandler:^(XDGOrderInfo * _Nonnull orderInfo, NSError * _Nonnull error) {
}];
XDGPayment.RestorePurchase(string purchaseToken, string orderId, string productId, string roleId, string serverId, string ext, Action<XDGOrderInfoWrapper> callback);
FXDGPayment::RestorePurchase({{'FXDGPayment::QueryRestoredPurchases' 中返回的交易信息的其中一个}}, OrderIDStr, RoleIDStr, ServerIDStr, ExtStr,
FXDGOrderInfo::FDelegate::CreateLambda([Printer, this](const FXDGOrderInfo& OrderInfo)
{
// 成功
}), FXDGError::FDelegate::CreateLambda([Printer, this](const FXDGError& Error)
{
// 失败
}));