跳到主要内容

应用内支付

概述

在开始接入之前,请确保您已经完成了开始教程。

配置

MSDK提供多种支付渠道模块。

您可以根据需求选择谷歌或华为支付渠道。

配置依赖

在app级别下的build.gradle中添加以下依赖,并将$msdk_version替换为实际的MSDK版本

implementation "com.garena.sdk.android:payment-google:$msdk_version"

配置清单文件

请确认在AndroidManifest.xml文件中已经声明applicationId

<meta-data
android:name="com.garena.sdk.applicationId"
android:value="YourAppId" />

核心购买流程

获取所有支付商品

获取所有支付商品的列表,包括促销商品、返利商品和应用商品。

默认条件下MSDK只返回不包含月卡的商品列表。如果你之前已经获取到有效的月卡ID,并且想要只获取该月卡的商品信息,可以调用builder.setRebateId(id)传入月卡id。

此外,可以通过builder.setRebateId(PaymentManager.ALL_ITEMS)获取所有的商品(包含月卡和非月卡商品),然后自己根据需要过滤商品列表。

    PaymentInfoRequestParams.Builder paramsBuilder = new PaymentInfoRequestParams.Builder();

paramsBuilder.setLocalizeProductPrice(true or false);
paramsBuilder.setRebateId(PaymentManager.NON_REBATE_ITEMS);

PaymentManager.getChannelList(this, paramsBuilder.build(), result -> {
// handle channel list result
if(result.isSuccess()) {
PaymentChannelInfo info = result.unwrap();
LocalizeResult localizeResult = info.getLocalizeResult();
List<PaymentChannel> channels = info.getChannels(); // by right, this should be a list of length 1

if(channels.size() >= 1) {
PaymentChannel channel = channels.get(0);

List<Denomination> items = channel.getItems();

// render your UI with the items
} else {
// this won't happen
}

} else {
MSDKError error = result.getErrorInfo();
// handle error
}
});

获取应用商品

获取有效的应用商品信息。游戏客户端应使用此信息来向用户显示相应的有效应用商品。

    PaymentManager.getAppItems(this, serverId, roleId, locale, itemIds, result ->{
if(result.isSuccess()) {
List<AppItem> appItems = result.unwrap();
// render your UI
} else {
MSDKError err = result.getErrorInfo();
}
});

进行支付

在获取支付选项后,您可以使用以下代码发起支付请求。支付请求将触发平台的原生支付流程。

重要注意事项

在充值和兑换成功时,请勿在MSDK回调API中使用point_amount。如果您直接使用此字段在游戏中添加现金余额,这样是不安全的。

请调用GOP服务器端的API(/app/point/get_balance),以便在MSDK回调API返回成功结果后获取新的现金余额。

    // create params with the selected denomination. You should have retrieved the denomination list by step b.1
PurchaseRequestParams purchaseRequestParams = new PurchaseRequestParams.Builder(itemId).build();

// pass the request params to SDK
PaymentManager.purchase(this /* activity instance */, purchaseRequestParams, (result, extra) -> {
if (result.isSuccess()) {
TransactionInfo transaction = result.unwrap();

} else {
MSDKError error = result.getErrorInfo();
// handle error

// since v5.9, we can obtain the exact payment step that the failure occurs
int paymentStep = extra.getPaymentStep();

if(paymentStep < PaymentStep.RECEIVE_RESULTS) {
// the error occurs before google returning the payment results to us.
}
}
PaymentEligibility paymentEligibility = extra.getPaymentEligibility();
// paymentEligibility can be null, so we MUST do a null check
if(paymentEligibility != null) {
// handle eligibility info
}
});

处理待处理/未完成的交易

在某些情况下,用户的购买可能会被中断或由于网络问题、服务器错误或其他问题而无法完成。为了确保用户收到他们购买的物品并保持良好的用户体验,MSDK提供了处理这些待处理或未完成交易的方法。

您应该在以下情况下调用这些方法:

  • 用户成功登录后
  • 收到支付失败回调时
  • 收到商品分发失败回调时

这有助于确保任何待处理的交易都能得到正确处理,用户能够收到他们购买的物品。

用户的存货中可能包括用户在Google Play使用兑换码获得的商品,或者是之前用户支付成功,但是因为网络原因没能成功发货的订单。可以通过PurchasedItemInfo.isPromotion()来区分。

// replace PaymentInfoRequestParams with serverId and roleId
PaymentManager.scanPurchaseInventory(this /* activity instance */, serverId, roleId, result -> {

});

返利卡购买

返利卡允许用户以优惠价格购买物品。当用户购买返利卡时,他们可以在指定时间内使用它来获得未来购买的折扣。折扣金额和有效期因返利卡而异。

在向用户展示返利卡之前,您需要使用下面的API获取当前有效的返利选项。请确保在每次购买后刷新列表,因为返利卡的有效性可能会发生变化。

获取返利卡

重要注意事项

永远不要缓存返回的数据,该数据会随着时间动态改变。

    PaymentManager.getRebateOptions(this, serverId, roleId, locale, rebateIds, result -> {
if (result.isSuccess()) {
List<RebateOptionItem> rebateOptions = result.unwrap();
// render the rebate card UI
} else {
MSDKError err = result.getErrorInfo();
}
});

进行支付

在获取返利选项后,您可以发起支付流程来购买返利物品。该过程与常规应用内购买类似,但需要额外的返利ID参数。

当购买成功时,您将收到包含交易详细信息的回调。

    // create params with the selected denomination
PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemId);
/* setup builder params*/
builder.setRebateId(rebateId);

// pass the request params to SDK
PaymentManager.purchase(this /* activity instance */, builder.build(), result -> {
if (result.isSuccess()) {
TransactionInfo transaction = result.unwrap();

} else {
MSDKError error = result.getErrorInfo();
// handle error
}
});

兑换返利卡

兑换功能允许用户领取他们的返利卡。您可以使用ID兑换特定的返利卡,也可以一次性兑换所有可用的返利卡。

请考虑以下情况:

  1. 如果兑换返利卡在GOP服务器上请求成功,但MSDK没有收到响应(例如由于网络错误),立即连续尝试调用兑换返利卡将返回错误。如果遇到这种情况,建议游戏服务器查询最新余额,其中将包括以前的兑换。
  2. 对于成功兑换时的完成回调,请调用GOP服务器API以获取最新余额,而不是使用回调返回的兑换金额进行手动余额计算。

兑换所有返利卡

    PaymentManager.redeemAll(this, serverId, roleId, result-> {
// handle result
});

兑换特定返利卡

    PaymentManager.redeem(this, rebateId, serverId, roleId, result -> {
if (result.isSuccess()) {
RedeemInfo redeemInfo = result.unwrap();

} else {
MSDKError err = result.getErrorInfo();
}
});

T-rex活动购买

获取活动配置

获取指定地区的活动信息列表.

    PaymentManager.loadEventConfigs(this /* activity instance*/, region, true, result->{
if(result.isSuccess()) {

} else {

}
});

获取活动配置商品

获取指定地区活动的所有支付商品,包括促销商品、返利商品和应用商品.

    PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemId, eventId);
/* setup builder params*/

PaymentManager.getEventsPricing(this, params, result -> {

}

进行活动支付

使用指定地区的产品ID购买与活动相关的商品

Proceed to buy the product with the selected denomination.

PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemId);
/* setup builder params*/
PaymentManager.payEventInit(this /* activity instance */, builder.build(), new PaymentManager.EventCallback() {
@Override
public void onInitResult(@NonNull Result<EventInitResult> result) {
// handle event init result
}

@Override
public void onResult(@NonNull Result<TransactionInfo> result, @NonNull PaymentExtraInfo extra) {
// handle purchase result
}
});

其他应用内购功能

防止支付套利

为防止用户利用不同货币之间的汇率差异对开发者造成损失,我们在v5.1.2版本开始支持了该功能。

游戏端只要在构建参数实例时传入玩家当前所在region即可。游戏端PM需要在Garena Open Platform完成货币与地区配置。

PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemId);
builder.setRegion(user region);

每日充值限额

现在游戏端可以限制每日应用内购买金额

该特性依赖防止支付套利特性,请确保已经完成了该特性的配置

目前API只接受整数值(单位美元)

    // setup the topup limit and region when create purchaseRequestParams with the Builder

PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemId);
...
builder.setRegion(user region);
builder.setTopupLimit(your expected topup limit in USD); // if passes 20, means the user can only spend 20 USD per day.
限制说明

目前,兑换优惠码应用外购买多量购买功能可以超过此限制

如果您的项目需要使用每日充值上限功能,请确保从Google Play控制台禁用这些功能

自定义数据透传

从 v5.12 开始,MSDK 支持在用户完成支付后,通过 [游戏服务器回调页面 (coming soon)],将自定义数据从移动客户端传递到游戏服务器。

要使用此功能,只需在发起支付流程时传入自定义数据即可。

数据限制

目前我们对自定义数据长度限制为1024。

PurchaseRequestParams.Builder builder = new PurchaseRequestParams.Builder(itemID);

builder.setGameData(/*custom game data in string type*/);

PaymentManager.purchase(activity, builder.build(), listener);

谷歌应用内购默认UI

MSDK为Android提供了默认的支付UI实现,以简化集成过程。该功能仅在Android平台上可用。

添加依赖

如果您想使用MSDK的默认UI,请在应用目录下的build.gradle中添加以下依赖。将$msdk_version替换为实际MSDK版本

    implementation "com.garena.sdk.android:payment-ui:$msdk_version"

展示支付界面

重要注意事项
  1. 如果计划将游戏推广至多个国家,那么建议在调用setLocale设置用户区域。否则,MSDK将应用默认逻辑。
  2. 如果计划将游戏推广至欧盟国家,那么你最好通过setOfferPersonalized指明你的商品是否采用了个性化的定价策略。 详情

personalized_offer_screenshot.png

当设置为true,在Google支付的弹窗上将展示This price has been customized for you文案。为false时则会隐藏。

    PaymentInfoRequestParams.Builder builder = new PaymentInfoRequestParams.Builder();
builder.setServerId(0);
builder.setRoleId(0);
builder.setItemIds(itemIds);
builder.setAppItemIds(appItemIds);
builder.setRebateIds(rebateIds);
builder.setLocalizeProductPrice(true or false);
builder.setVirtualCurrencyName("Diamond");

String virtualCurrencyName = "Diamond"; // will be displayed as the title of the purchase page

PaymentManager.showPurchasePage(this /* activity instance */, virtualCurrencyName, builder.build(), (result, extra) -> {
// handle purchase result
if(result.isSuccess()) {
TransactionInfo info = result.unwrap();
// handle result
} else {
MSDKError error = result.getErrorInfo();
// deal with error code and error message
Logger.print(error.toString()); // this line is just an example
}
// handle extra info
});

常见问题

如果一个用户在Google Play应用内购买中选择现金支付,每笔交易是否有任何过期时间?

是的。用户必须在7天内用现金支付,否则Google Play将取消交易

在用户用现金支付后,Garena Open Platform需要将购买的商品归属并告知给Google Play。否则,Google Play将在3天后退款

如果一个访客帐户有订阅并将访客帐户绑定到一个Google帐户,订阅是否也会被转移?

是的