收据验证
未给出的项目收据¶
发送物品有时会在购买后失败或被取消。为了防止这种情况,可以通过调用IAPV4类的restore()
方法请求未提供的物品的收据信息。
- 如果返回
SUCCESS
并且在调用restore()
后发送ReceiptList,则需要恢复的项目存在。发送未给出的项目并完成恢复过程。 - 如果在调用
restore()
后未返回SUCCESS
,则游戏工作室不需要更多处理。 - 如果调用
restore()
方法时发生错误,请通知仅识别所需的一些错误,并跳过其他错误,以便用户继续玩游戏。 - 在Windows应用程序中使用
GOOGLE_PLAYSTORE
市场进行Google Play(Hive SDK v4 Unity Windows 23.0.0或更高版本)时,如果用于支付的Google帐户的身份验证信息在调用restore()
方法时过期,则Hive SDK会自动启动重新身份验证过程。
以下是请求未提供商品收据信息的示例代码。
API 参考: hive .IAPV4.restore
#include "HiveIAPV4.h"
FHiveIAPV4::Restore(FHiveIAPV4OnRestoreDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TArray<FHiveIAPV4Receipt>& IAPV4ReceiptList) {
if (Result.IsSuccess()) {
if (Result.ErrorCode == FHiveResultAPI::EErrorCode::SUCCESS) {
// TODO: 使用接收到的receiptList请求收据验证
} else if (Result.ErrorCode == FHiveResultAPI::EErrorCode::RESTORE_NOT_OWNED) {
// 没有未支付的项目
}
}
}));
API 参考: IAPV4 ::restore
#include <HIVE_SDK_Plugin/HIVE_CPP.h>
using namespace std;
using namespace hive;
IAPV4::restore([=](ResultAPI const & result, vector<reference_wrapper<IAPV4Receipt>> receiptList) {
if (result.isSuccess()) {
if (result.errorCode == ResultAPI::ErrorCode::SUCCESS) {
// TODO: 使用接收到的receiptList请求收据验证
} else if (result.errorCode == ResultAPI::ErrorCode::RESTORE_NOT_OWNED) {
// 没有未付款项
}
}
});
API 参考: IAPV4.restore
import com.hive.IAPV4
import com.hive.ResultAPI
IAPV4.restore(object : IAPV4.IAPV4RestoreListener {
override fun onIAPV4Restore(result: ResultAPI, iapv4ReceiptList: ArrayList<IAPV4.IAPV4Receipt>?) {
if (result.isSuccess) {
if (result.errorCode == ResultAPI.SUCCESS) {
// TODO: 使用接收到的iapv4ReceiptList请求收据验证
} else if (result.errorCode == ResultAPI.RESTORE_NOT_OWNED) {
// 没有未支付的项目
}
}
}
})
API 参考: com.hive.IAPV4.restore
import com.hive.IAPV4;
import com.hive.ResultAPI;
IAPV4.INSTANCE.restore((result, iapv4ReceiptList) -> {
if (result.isSuccess()) {
if (result.getErrorCode() == ResultAPI.Companion.getSUCCESS()) {
// TODO: Request receipt verification using the received iapv4ReceiptList
} else if (result.getErrorCode() == ResultAPI.Companion.getRESTORE_NOT_OWNED()) {
// No unpaid items
}
}
});
API 参考: IAPV4Interface .restore
API 参考: HIVEIAPV4::restore
#import <HIVEService/HIVEService-Swift.h>
[HIVEIAPV4 restore: ^(HIVEResultAPI *result, NSArray<HIVEIAPV4Receipt *> *receiptList) {
if ([result isSuccess]) {
if ([result getErrorCode] == HIVEResultAPITypeSuccess) {
// TODO: 使用收到的receiptList请求收据验证
} else if ([result getErrorCode] == HIVEResultAPITypeNotOwned){
// 没有未付款项
}
}
}];
Note
may differ by operating system/market. For more details, see the status of supported features.
购买恢复错误代码列表¶
错误代码 | 描述 |
---|---|
NEED_INITIALIZE | 无法初始化 |
NETWORK | 网络错误 |
NOT_SUPPORTED | 无法恢复(设备上拒绝了应用内购买等)。用户设置了不可用的商店 |
INVALID_SESSION | 无效的恢复会话 |
IN_PROGRESS | 恢复 API 正在进行中 |
RESTORE_NOT_OWNED | 没有可恢复的项目 |
NOT_OWNED | 没有可恢复的项目 |
RESPONSE_FAIL | IAP 服务器错误 |
验证购买收据¶
在从游戏服务器发送物品之前,IAP 的验证 API 应该确认收据是否有效。 验证 API 中的 hiveiap_transaction_id
是由收据发出的唯一 ID。因此,将 ID 保存到游戏服务器以检查重复的收据。 如果您使用验证 API 然后发送所有来自请求参数的数据,IAP 服务器将转发游戏数据以分析销售状态。只需利用 API 在 Hive One > 搜索所有 中搜索付款。 有关更多详细信息,请参阅 IAP 收据验证 API。
完成以提供已购买或未提供的物品¶
如果游戏服务器在购买后发送物品,请确保调用IAPV4类的transactionFinish()
方法以完成购买。
Warning
如果您不调用 transactionFinish()
方法,物品将保持在未交付状态。
此原因导致在调用restore()
方法时返回收据。 因此,请确保在所有过程完成后调用finish API。
Note
使用 Hive SDK v4.12.0 及更高版本在 Android Google Play 商店中,如果在支付后三天内或测试状态下五分钟内,IAPV4 类中实现 TransactionFinish()
方法的结果未成功,则支付将自动退款。
以下是完成物品发送请求的示例代码。
API 参考: hive .IAPV4.transactionFinish
API 参考: IAPV4 ::transactionFinish
API 参考: IAPV4.transactionFinish
import com.hive.IAPV4
import com.hive.ResultAPI
val marketPid = "{YOUR_PRODUCT_MARKET_PID}"
IAPV4.transactionFinish(marketPid, object : IAPV4.IAPV4TransactionFinishListener {
override fun onIAPV4TransactionFinish(result: ResultAPI, marketPid: String) {
if (result.isSuccess) {
// call successful
}
}
})
API 参考: com.hive.IAPV4.transactionFinish
API 参考: IAPV4Interface.transactionFinish
以下是请求发送多个项目的示例代码。
API 参考: hive .IAPV4.transactionMultiFinish
using hive;
List marketPidList = new List();
marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_01}");
marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_02}");
marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_03}");
IAPV4.transactionMultiFinish((List<ResultAPI> resultList, List<String> marketPidList) => {
for (ResultAPI result in resultList) {
if (result.isSuccess()) {
// call successful
}
}
});
#include "HiveIAPV4.h"
TArray<FString> MarketPidList;
MarketPidList.Add(TEXT("YOUR_PRODUCT_MARKET_PID_01"));
MarketPidList.Add(TEXT("YOUR_PRODUCT_MARKET_PID_02"));
MarketPidList.Add(TEXT("YOUR_PRODUCT_MARKET_PID_03"));
FHiveIAPV4::TransactionMultiFinish(MarketPidList, FHiveIAPV4OnTransactionMultiFinishDelegate::CreateLambda([this](const TArray<FHiveResultAPI>& ResultList, const TArray<FString>& MarketPidList) {
for (const auto& Result : ResultList) {
if (Result.IsSuccess()) {
// API 调用成功
}
}
}));
API 参考: IAPV4 ::transactionMultiFinish
#include <HIVE_SDK_Plugin/HIVE_CPP.h>
using namespace std;
using namespace hive;
vector<string> marketPidList;
marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_01}");
marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_02}");
marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_03}");
IAPV4::transactionMultiFinish(marketPidList, [=](vector<ResultAPI> const & resultList, vector<string> const & marketPidList) {
for (ResultAPI result : resultList) {
if (result.isSuccess()) {
// call successful
}
}
});
API 参考: IAPV4.transactionMultiFinish
import com.hive.IAPV4
import com.hive.ResultAPI
val marketPidList = arrayListOf(
"{YOUR_PRODUCT_MARKET_PID_01}",
"{YOUR_PRODUCT_MARKET_PID_02}",
"{YOUR_PRODUCT_MARKET_PID_03}"
)
IAPV4.transactionMultiFinish(marketPidList, object : IAPV4.IAPV4TransactionMultiFinishListener {
override fun onIAPV4TransactionMultiFinish(resultList: ArrayList<ResultAPI>, marketPidList: ArrayList<String>) {
for (i in 0 until resultList.size) {
if (resultList[i].isSuccess) {
// call successful
}
}
}
})
API 参考: com.hive.IAPV4.transactionMultiFinish
import com.hive.IAPV4;
import com.hive.ResultAPI;
ArrayList<String> marketPidList = new ArrayList<>(Arrays.asList(
"{YOUR_PRODUCT_MARKET_PID_01}",
"{YOUR_PRODUCT_MARKET_PID_02}",
"{YOUR_PRODUCT_MARKET_PID_03}"
));
IAPV4.INSTANCE.transactionMultiFinish(marketPidList, (resultList, marketPidList1) -> {
for (ResultAPI result : resultList) {
if (result.isSuccess()) {
// call successful
}
}
});
API 参考: IAPV4Interface.transactionMultiFinish
import HIVEService
var marketPidList = [String]()
marketPidList.append("{YOUR_PRODUCT_MARKET_PID_01}")
marketPidList.append("{YOUR_PRODUCT_MARKET_PID_02}")
marketPidList.append("{YOUR_PRODUCT_MARKET_PID_03}")
IAPV4Interface.transactionMultiFinish(marketPidList) { resultList, marketPidList in
for result in resultList {
if result.isSuccess() {
// call successful
}
}
}
API 参考: HIVEIAPV4::transactionMultiFinish
#import <HIVEService/HIVEService-Swift.h>
NSMutableArray<NSString *> *maketPidList = [NSMutableArray array];
[maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_01}"];
[maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_02}"];
[maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_03}"];
[HIVEIAPV4 transactionMultiFinish: maketPidList handler: ^(NSArray<HIVEResultAPI *> *resultList, NSArray<NSString *> *marketPidList) {
for (HIVEResultAPI *result in resultList) {
if ([result isSuccess]) {
// call successful
}
}
}];
获取用户购买活动信息: 使用 AccountUuid
¶
可能会有用户滥用支付系统,例如一个游戏账户使用多个应用商店账户进行支付。在游戏工作室方面,您可以通过比较支付用户信息(AccountUuid)来获取和分析特定用户行为。
下面的方法返回 AccountUuid
,这是 Hive SDK 传递给应用商店的 UUID v3 格式的 PlayerId 的哈希值。
API 参考: IAPV4.getAccountUuid
API 参考: IAPV4 ::getAccountUuid
API 参考: IAPV4.getAccountUuid
API 参考: IAPV4.INSTANCE .getAccountUuid
API 参考: IAPV4Interface.getAccountUuid
API 参考: [HIVEIAPV4 getAccountUuid ]
游戏工作室可以使用此哈希值和购买收据信息来分析用户的购买情况。
下面的示例展示了如何通过 AccountUuid
分析一个游戏账户的购买活动,该账户具有特定的 PlayerId,并且在该游戏账户中有多个游戏角色。此示例仅供开发参考,并不保证实际操作。
在游戏服务器中提前存储购买元信息¶
在购买请求发生之前,将购买元信息(AccountUuid
和角色信息)保存到游戏服务器。
/* The game client pass the info to the game server before the purchase occurs.
*
* @param purchaseTime: purchase time. The receipts are usually based on UTC. since the epoch (Jan 1, 1970).
* @param productId: purchase product ID.
* @param accountUuId: hashed PlayerId. It is included in the receipt and can be obtained with IAPV4.getAccountUuid().
* @param characterId: the character identifier within PlayerId.
*/
game.sendPurchaseGameData(purchaseTime, productId, accountUuid, characterId)
发送 bypassInfo
¶
当购买请求发生时,将 bypassInfo
数据发送到游戏服务器。下面的代码是供开发参考的伪代码。
收据验证请求¶
游戏服务器将 bypassInfo
数据传递给 IAP v4 服务器并请求验证收据。有关请求收据验证的详细信息,请参见 这里。 hiveiap_receipt
中包含的 AccountUuid
是在响应值中收到的应用市场/商店的原始收据。
# Apple
# Purchase time: purchase_date_ms
# Purchased products: product_id
# AccountUuid: app_account_token
# Google
# Purchase time: purchaseTime
# Purchased products: productId
# AccountUuid: obfuscatedAccountId
通过将购买元信息的 AccountUuid
与 hiveiap_receipt
的 AccountUuid
进行匹配进行分析¶
通过将之前存储在购买元信息中的AccountUuid
与从收据验证结果中获得的AccountUuid
进行匹配,找到分析所需的用户信息,例如游戏角色信息。您可以通过将购买元信息与收据信息进行匹配,分析相应游戏账户的购买活动。
如果用户购买了多个商品,则可以通过将购买元信息与 hiveiap_receipt
的 purchaseTime
进行匹配来识别每个购买。有关 hiveiap_receipt
的详细信息,请参见 验证收据 并检查按市场划分的 API 响应。
获取用户购买活动信息:使用 iadPayload
¶
当请求使用购买时,如果您在iapPayload
中包含游戏公司事先定义的购买活动分析数据,Hive 服务器将匹配与iapPayload
相对应的购买凭证并将其传递给游戏服务器。游戏工作室可以通过使用凭证中的信息以及iadPayload
中的信息来分析用户的购买活动。
Note
通过这种方式,因为 Hive 服务器将每个购买的元信息与每个收据匹配并发送到您的游戏服务器,您无需像上面所示那样自己通过 AccountUuid
匹配购买元信息和收据。
定义 iapPayload
并执行 Purchase()
¶
在执行每个 产品购买请求 时,定义所需的字段和值在 iapPayload
中,并将其作为参数使用。该过程类似于定义 购买元数据。
请求收据验证,并接收 iapPayload
和相应的收据。¶
当支付完成并请求收据验证时,Hive 服务器通过购买将 iapPayload
与其相应的收据匹配,并将其交付给游戏服务器。游戏工作室可以使用 iapPayload
和收据中的信息来分析用户购买活动。
以下是一个使用iapPayload的情况示例。
- 市场账户: A, Hive 玩家ID: a, 应用角色: 1 登录
- 购买(marketPid, "玩家ID a - 角色 1")
- 切换账户到 Hive 玩家ID: b, 应用角色 2
- 恢复()
- 收到包含 iapPayload "玩家ID a - 角色 1" 的收据