コンテンツにスキップ

レシートの検証

未提供のアイテム領収書

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

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

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

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

Warning

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

この原因は、restore()メソッドを呼び出す際にレシートが返されることです。すべてのプロセスが完了した後にフィニッシュAPIを呼び出すことを確認してください。

Note

Hive SDK v4.12.0以降のAndroid Google Playストアでは、支払い後3日以内またはテストステータスで5分以内に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 を使用

支払いシステムを悪用するユーザーがいるかもしれません。例えば、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とレシートの情報を使用してユーザーの購入活動を分析できます。

以下はiapPayloadを使用した状況の例です。

  • マーケットアカウント: A, ハイブプレイヤーID: a, アプリキャラクター: 1 ログイン
  • 購入(marketPid, "プレイヤーID a - キャラクター 1")
  • アカウントをハイブプレイヤーID: b, アプリキャラクター 2 に切り替え
  • 復元()
  • iapPayload "プレイヤーID a - キャラクター 1" を含むレシートを受け取りました