跳转至

收据验证

未给出的项目收据

发送物品有时会在购买后失败或被取消。为了防止这种情况,可以通过调用IAPV4类的restore()方法请求未提供的物品的收据信息。

  • 如果在调用 restore() 后返回 SUCCESS 并且发送了 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

using hive;    
    IAPV4.restore((ResultAPI result, List receiptList) => {    
         if (result.isSuccess()) {    
            if (result.errorCode = ResultAPI.ErrorCode.SUCCESS) {    
            // TODO: Request receipt verification using the received receiptList    
            } else if (result.errorCode = ResultAPI.ErrorCode.NOT_OWNED) {    
            // No unpaid items    
            }    
        }    
}
#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: 使用接收到的iapv4ReceiptList请求收据验证    
             } else if (result.getErrorCode() == ResultAPI.Companion.getRESTORE_NOT_OWNED()) {    
                 // 没有未付款项    
             }    
         }    
});

API 参考: IAPV4Interface .restore

import HIVEService    
    IAPV4Interface.restore() { result, receiptList in    
        if result.isSuccess() {    
            if result.getErrorCode() == .success {    
            // TODO: Request receipt verification using the received receiptList    
            } else if result.getErrorCode() == .notOwned {    
            // No unpaid items    
            }    
        }    
}

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 应该确认收据是否有效。 hiveiap_transaction_id 在验证 API 中是由收据发出的唯一 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

using hive;    
    String marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    IAPV4.transactionFinish(marketPid, (ResultAPI result, String marketPid) => {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});
#include "HiveIAPV4.h"

FString MarketPid = TEXT("YOUR_PRODUCT_MARKET_PID");
FHiveIAPV4::TransactionFinish(MarketPid, FHiveIAPV4OnTransactionFinishDelegate::CreateLambda([this, idx](const FHiveResultAPI& Result, const FString& MarketPid) {
        if (Result.IsSuccess()) {
                // call successful 
        }
}));

API 参考: IAPV4 ::transactionFinish

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
using namespace std;    
using namespace hive;    
string marketPid = "{YOUR_PRODUCT_MARKET_PID}";    

IAPV4::transactionFinish(marketPid, [=](ResultAPI const & result, string marketPid) {    
if (result.isSuccess()) {    
// call successful    
}    
});

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

import com.hive.IAPV4;    
    import com.hive.ResultAPI;    
    String pid = "{YOUR_PRODUCT_MARKET_PID}";    
    IAPV4.INSTANCE.transactionFinish(pid, (result, marketPid) -> {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});

API 参考: IAPV4Interface.transactionFinish

import HIVEService    
    let marketPid = "{YOUR_PRODUCT_MARKET_PID}"    
    IAPV4Interface.transactionFinish() { result, marketPid in    
    if result.isSuccess() {    
        // call successful    
        }    
}

API 参考: HIVEIAPV4::transactionFinish:handler:

#import <HIVEService/HIVEService-Swift.h>    
    NSString *marketPid = @"{YOUR_PRODUCT_MARKET_PID}";    
    [HIVEIAPV4 transactionFinish: marketPid handler: ^(HIVEResultAPI *result, NSString *marketPid) {    
         if ([result isSuccess]) {    
             // call successful    
         }    
}];

以下是请求发送多个项目的示例代码。

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,这是UUID v3格式中PlayerId的哈希值,由Hive SDK传递给应用商店。

API 参考: IAPV4.getAccountUuid

using hive;    
String accountUuid = IAPV4.getAccountUuid();
#include "HiveIAPV4.h"

FString AccountUuid = FHiveIAPV4::GetAccountUuid();

API 参考: IAPV4 ::getAccountUuid

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    
string accountUuid = IAPV4::getAccountUuid();

API 参考: IAPV4.getAccountUuid

import com.hive.IAPV4    
val accountUuid = IAPV4.getAccountUuid()

API 参考: IAPV4.INSTANCE .getAccountUuid

import com.hive.IAPV4;    
String accountUuid = IAPV4.INSTANCE.getAccountUuid();

API 参考: IAPV4Interface.getAccountUuid

import HIVEService    
let accountUuid = IAPV4Interface.getAccountUuid()

API 参考: [HIVEIAPV4 getAccountUuid ]

#import <HIVEService/HIVEService-Swift.h>    
NSString accountUuid = [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 数据发送到游戏服务器。下面的代码是供开发参考的伪代码。

IAPV4.purchaseproductId) {
    iapv4Receipt -> game.sendReceipt(iapv4Receipt.purchase_bypass_info)
}

收据验证请求

游戏服务器将 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

通过将购买元信息的 AccountUuidhiveiap_receiptAccountUuid 进行匹配来分析

通过将之前存储在购买元信息中的 AccountUuid 与从收据验证结果中获得的 AccountUuid 进行匹配,找到分析所需的用户信息,例如游戏角色信息。您可以通过将购买元信息与收据信息进行匹配,分析相应游戏账户的购买活动。

如果用户购买了多个商品,则可以通过将购买元信息与 hiveiap_receiptpurchaseTime 进行匹配来识别每个购买。有关 hiveiap_receipt 的详细信息,请参见 验证收据 并查看按市场划分的 API 响应。

获取用户购买活动信息:使用 iadPayload

在请求购买时,如果您的游戏公司还提供预定义数据以分析用户购买活动,使用Purchase()iapPayload,Hive 服务器会匹配与 iapPayload 对应的购买凭证,并将其发送到游戏服务器。游戏公司可以结合凭证中的信息和 iadPayload 中的信息来分析用户购买活动。

Note

通过这种方式,因为 Hive 服务器将每个购买的元信息与每个收据匹配并发送到您的游戏服务器,您无需像上面所示那样自己通过 AccountUuid 匹配购买的元信息和收据。

定义 iapPayload 并执行 Purchase()

在执行每个 产品购买请求 时,定义所需的字段和值在 iapPayload 中,并将其作为参数使用。该过程类似于定义 购买元数据

请求收据验证,并接收 iapPayload 及相应的收据。

当完成支付并请求收据验证时,Hive 服务器通过购买将 iapPayload 与其相应的收据匹配,并将其交付给游戏服务器。游戏工作室可以使用 iapPayload 和收据中的信息来分析用户购买活动。

以下是使用iapPayload的情况示例。

  • 市场账户: A, 蜂巢玩家ID: a, 应用角色: 1 登录
  • 购买(marketPid, "玩家ID a - 角色 1")
  • 切换账户到蜂巢玩家ID: b, 应用角色 2
  • 恢复()
  • 收到包含iapPayload "玩家ID a - 角色 1"的收据