コンテンツにスキップ

レシートの検証

未提供のアイテム領収書

アイテムの送信は、購入後に時折失敗したりキャンセルされたりします。この状況を防ぐために、IAPV4クラスのrestore()メソッドを呼び出して、渡されていないアイテムの領収書情報を要求してください。

  • SUCCESSが返され、restore()を呼び出した後にReceiptListが送信されると、復元が必要なアイテムが存在します。未提供のアイテムを送信し、復元プロセスを完了してください。
  • restore()を呼び出した後にSUCCESSが返されない場合、ゲームスタジオに対してはこれ以上の処理は必要ありません。
  • restore()メソッドを呼び出す際にエラーが発生した場合、認識する必要があるエラーのみを通知し、他のエラーはスキップしてユーザーがゲームを続けられるようにしてください。
  • Google PlayのWindowsアプリでGOOGLE_PLAYSTOREマーケットを使用する場合(Hive SDK v4 Unity Windows 23.0.0以上)、restore()メソッドを呼び出す際に支払いに使用されるGoogleアカウントの認証情報が期限切れの場合、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: 受け取ったレシートリストを使用してレシートの検証をリクエストする
                } 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がレシートが有効かどうかを確認する必要があります。 検証APIのhiveiap_transaction_idはレシートによって発行されるユニークIDです。したがって、重複したレシートを確認するために、ゲームサーバーにIDを保存してください。 検証APIを使用してからリクエストパラメータからすべてのデータを送信すると、IAPサーバーはゲームデータを転送して販売状況を分析します。Hive One > Search Allでも、支払いを検索するためにAPIを利用してください。 詳細については、IAPレシート検証APIを参照してください。

購入済みまたは未購入のアイテムを提供する

ゲームサーバーが購入後にアイテムを送信する場合は、購入を完了するためにIAPV4クラスのtransactionFinish()メソッドを呼び出すことを確認してください。

Warning

transactionFinish()メソッドを呼び出さないと、アイテムは未渡しの状態のままになります。

この原因は、restore()メソッドを呼び出す際に受け取った領収書です。すべてのプロセスが完了した後にフィニッシュAPIを呼び出すことを確認してください。

Note

Hive SDK v4.12.0以降、Android Google Playストアで、支払い後にIAPV4クラスのTransactionFinish()メソッドの実装結果が3日以内またはテスト状態で5分以内に成功しない場合、支払いは自動的に返金されます。

以下は、アイテム送信のリクエストを完了するサンプルコードです。

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 を使用

支払いシステムを悪用するユーザーがいるかもしれません。たとえば、1つのゲームアカウントが複数のアプリストアアカウントを使用して支払いを行う場合です。ゲームスタジオ側では、支払いユーザー情報(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];

ゲームスタジオは、このハッシュ値を購入領収書情報と共に使用して、ユーザーの購入を分析できます。以下の例は、複数のゲーム内キャラクターがこのゲームアカウントに存在する場合に、特定のPlayerIdを介してAccountUuidでゲームアカウントの購入活動を分析する方法を示しています。この例は開発の参考のためのものであり、実際の動作を保証するものではありません。

ゲームサーバーに事前に購入メタ情報を保存する

購入リクエストが行われる前に、購入メタ情報(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とレシートの情報を使用してユーザーの購入活動を分析できます。