跳轉至

收据验证

未給予的項目收據

發送項目有時會在購買後失敗或被取消。為了防止這種情況,請通過調用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: 使用收到的 receiptList 请求收据验证    
            } else if result.getErrorCode() == .notOwned {    
            // 没有未支付的项目    
            }    
        }    
}

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

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 Reference: 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 和收據中的資訊來分析用戶的購買活動。