アプリ内課金(IAP)v2.0ウェブアプリの例


アプリ内課金(IAP)v2.0ウェブアプリの例

Web SDKのダウンロード内のIAPサンプルコードはIAP v1.0を使用しますが、これは現在廃止されています。

このIAP v2.0ウェブアプリのサンプルリンクを使用して、IAP v2.0ウェブアプリのサンプルをダウンロードしてください。

サンプルにアクセスするには、お使いのローカルマシン上でHTTPサーバーを開始します。Pythonがインストールされている場合は、Python HTTPサーバーを使用できます。

  1. ダウンロードファイルを解凍します。
  2. ターミナルウィンドウで、新しく解凍されたフォルダ(IAPv2-web-app-sample)に移動します。
  3. python -m SimpleHTTPServerと入力してPythonサーバーを開始します。

追加のサーバーオプションについては、Mozillaに関するこちらの記事を参照してください。

サンプルの実行方法は次のとおりです。

  1. ブラウザーを開き、http://localhost:8000に移動します。
  2. ページの指示に従ってアプリを使用します。

サンプルの説明

index.htmlファイルの中身はシンプルで、次のスクリプトタグが含まれており、Amazon Servicesライブラリとテストライブラリを組み込めるようになっています。

<script src="https://resources.amazonwebapps.com/v1/latest/Amazon-Web-App-API.min.js">
type="text/javascript"></script>
<script src="https://resources.amazonwebapps.com/v1/latest/Amazon-Web-App-API-tester.min.js"
type="text/javascript"></script>

Button ClickerのJavaScriptファイルは以下に含まれています。


// このセットアップは、シンプルなモデルビューコントローラー形式を採用しており、
// onPurchaseResponseをいつでも呼び出せるという事実を示すことを
// 目的としています。
//
// APIを使用する際は、レスポンスが発生するタイミングは予測できない
// ということを理解する必要があります。たとえば、レシートが配信される前に
// ウェブアプリが終了される可能性があります。
// この場合は、そのアプリが次に実行されたときの
// APIの初期化時にレシートが処理されます。

// モデルデータ
var state = {
    clicksLeft:  10,
    activeButton: "",
    hasRedButton: false,
    hasGreenButton: false,
    hasBlueButton: false,
    lastPurchaseCheckTime: null
}

// モデルに基づいてビュー(HTML)を生成する

function refreshPageState() {
    $("#clicksLeft").text(state.clicksLeft);

    var button = $("#theButton");
    var redButton = $("#redButton");
    var greenButton = $("#greenButton");
    var blueButton = $("#blueButton");

    setClass(redButton, "locked", !state.hasRedButton);
    setClass(greenButton, "locked", !state.hasGreenButton);
    setClass(blueButton, "locked", !state.hasBlueButton);

    setClass(redButton, "active", state.activeButton == "red");
    setClass(greenButton, "active", state.activeButton == "green");
    setClass(blueButton, "active", state.activeButton == "blue");

    if (state.activeButton != "") {
        button.css("background-color", state.activeButton);
    } else {
        button.css("background-color", "gray");
    }
    persistPageState();
}

// 次回のアプリ実行時に前回実行時と同じ状態が維持されるように、
// localStorageにステートを保存します。IAPのステータスには、
// getPurchaseUpdatesに渡されるlastPurchaseCheckTimeが
// 含まれている必要があります。
function persistPageState() {
    localStorage.setItem("state", JSON.stringify(state));
}

// localStorageからステートを復元する
function loadPageState() {
    if ("state" in localStorage) {
        // これが初めての実行の場合、以前に設定した
        // デフォルトを使用して実行します。
        localStorage.setItem("state", JSON.stringify(state));
    }
}

function setClass(element, className, condition) {
    if (condition) {
        element.addClass(className);
    } else {
        element.removeClass(className);
    }
}

// コントローラー

// 消費型アイテムを処理する
function buttonPressed() {
    if (state.clicksLeft > 0) {
        state.clicksLeft--;
    } else {
        buyClicks();
    }
    refreshPageState();
}

// 非消費型アイテムを処理する
function redButtonPressed() {
    if (state.hasRedButton) {
        state.activeButton = "red";
    } else {
        buyButton("sample.redbutton");
    }
    refreshPageState();
}

// 非消費型アイテムを処理する
function greenButtonPressed() {
    if (state.hasGreenButton) {
        state.activeButton = "green";
    } else {
        buyButton("sample.greenbutton");
    }
    refreshPageState();
}

// 定期購入型アイテムを処理する
function blueButtonPressed() {
    if (state.hasBlueButton) {
        state.activeButton = "blue";
    } else {
        // 指定された(条件が設定されている)定期購入型アイテムを購入することが必要
        buyButton("sample.bluebutton.subscription.1mo");
    }
    refreshPageState();
}

function buyClicks() {
    if (window.AmazonIapV2 == null) {
        alert("クリック数の上限に達しました。なお、Amazonアプリ内課金をご利用いただけるのはAmazonアプリストアから入手したアプリだけです。");
    } else if (confirm("クリックを購入しますか?")) {
        //window.AmazonIapV2.purchase('sample.clicks');
        var requestOptions = {
            sku: 'sample.clicks'
        };
        window.AmazonIapV2.purchase(
            function(operationResponse) {
                console.debug(operationResponse.requestId);
            },
            function(errorResponse) {
                console.debug(errorResponse);
            },
            [requestOptions]
        );
    }
}

function buyButton(buttonName) {
    if (window.AmazonIapV2 == null) {
        alert("このボタンは購入できません。Amazonアプリ内課金をご利用いただけるのはAmazonアプリストアから入手したアプリだけです。");
    } else {
        //window.AmazonIapV2.purchase(buttonName);
        var requestOptions = {
            sku: buttonName
        };
        window.AmazonIapV2.purchase(
            function(operationResponse) {
                console.debug(operationResponse.requestId);
            },
            function(errorResponse) {
                console.debug(errorResponse);
            },
            [requestOptions]
        );
    }
}

// purchaseItemのコールバックから呼び出されるハンドラー関数により

// 1つのレシートを伴う購入レスポンスが発生
function onPurchaseResponse(e) {
    var response = e.response;
    if (response.status === 'SUCCESSFUL') {
        handleReceipt(response.purchaseReceipt);
    } else if (response.status === 'ALREADY_PURCHASED') {
        // 何らかの理由でサーバーと同期していません。最初から
        // 更新しましょう。
        var requestOptions = {
            reset: true
        };
        window.AmazonIapV2.getPurchaseUpdates(
            function(operationResponse) {
                // オペレーションレスポンスを処理する
                var requestId = operationResponse.requestId;
                console.debug(requestId);
            },
            function(errorResponse) {
                // エラーレスポンスを処理する
                console.debug(errorResponse);
            },
            [requestOptions]
        );
    } else if (response.status === 'FAILED') {
        alert('購入リクエストが中断されました。後でもう一度お試しください');
    } else if (response.status === 'INVALID_SKU') {
        alert('SKUが無効です。SKUの構成を確認してください。');
    }

    refreshPageState();
}

// getPurchaseUpdatesがレシートの配列を返す
function onPurchaseUpdatesResponse(e) {
    var response = e.response;
    for (var i = 0; i < response.receipts.length; i++) {
        handleReceipt(response.receipts[i]);
    }
    state.lastPurchaseCheckTime = response.offset;
    refreshPageState();
    if (response.hasMore) {
        // アップデートが多すぎてこのレスポンスで送信されない
        // ものがあった場合は、必ず残りを
        // 取得してください。
        var requestOptions = {
            reset: false
        };
        window.AmazonIapV2.getPurchaseUpdates(
            function(operationResponse) {
                // オペレーションレスポンスを処理する
                var requestId = operationResponse.requestId;
                console.debug(requestId);
            },
            function(errorResponse) {
                // エラーレスポンスを処理する
                console.debug(errorResponse);
            },
            [requestOptions]
        );
    }
}

// どちらの場合もレシートの内容の処理方法は同じ
function handleReceipt(receipt) {
    if (receipt.sku == "sample.redbutton") {
        // 非消費型アイテム
        state.hasRedButton = true;
    } else if (receipt.sku == "sample.greenbutton") {
        // 非消費型アイテム
        state.hasGreenButton = true;
    } else if (receipt.sku.substring(0, 30) == "sample.bluebutton.subscription") {
        // 定期購入型アイテムから親のIDが返されることがあるため
        // 親のIDと比較
        if (receipt.cancelDate == null) {
            // 現在が有効な期間中である場合、cancelDateはnull
            state.hasBlueButton = true;
        }

    } else if (receipt.sku == "sample.clicks") {
        // 消費型アイテム
        state.clicksLeft += 10;
    }
    //まだアイテム付与が完了していない場合は、このレシートのアイテムを付与します。
    //既に付与されたアイテムをトラッキングするためのreceiptIdを格納し、
    //FULFILLEDステータスを指定してreceiptIdのnotifyFulfillment()を呼び出します。
    //アイテムが以前のゲーム状態向けであるか、ゲームでサポートされていない
    //ためにアイテムを付与できない場合は、以下のように処理します
    //
    notifyFulfillment(receipt.receiptId);
}

/**
* @function notifyFulfillment
* @description NotifyFulfillmentは購入アイテムの付与についてAmazonに通知します。
* @param {String} receiptId レシートID
*/
function notifyFulfillment(receiptId) {
    //fulfillmentResultはFULFILLEDまたはUNAVAILABLE
    var requestOptions = {
        'receiptId': receiptId,
        'fulfillmentResult': 'FULFILLED'
    };
    window.AmazonIapV2.notifyFulfillment(
        function(operationResponse) {
            // オペレーションレスポンスを処理する
            console.debug(operationResponse);
        },
        function(errorResponse) {
            // エラーレスポンスを処理する
            console.debug(errorResponse);
        },
        [requestOptions]
    );

}

// セットアップ

function initialize() {
    loadPageState();
    amzn_wa.enableApiTester(amzn_wa_tester);
    refreshPageState();

    // ボタンクリックハンドラーをセットアップする
    $("#theButton").click(function() { buttonPressed(); });
    $("#redButton").click(function() { redButtonPressed(); });
    $("#greenButton").click(function() { greenButtonPressed(); });
    $("#blueButton").click(function() { blueButtonPressed(); });

    document.addEventListener('amazonPlatformReady', function() {
        // IAP APIを呼び出せるようにする
        if (window.AmazonIapV2 === null) {
            console.debug('Amazonアプリ内課金をご利用いただけるのはAmazonアプリストアから入手したアプリだけです');
        } else {
            window.AmazonIapV2.addListener('getUserDataResponse', function(resp) {});
            window.AmazonIapV2.addListener('getProductDataResponse', function(data) {});
            window.AmazonIapV2.addListener('purchaseResponse', this.onPurchaseResponse);
            window.AmazonIapV2.addListener('getPurchaseUpdatesResponse', this.onPurchaseUpdatesResponse);
        }
    }.bind(this));
}

$(function() {
    initialize();
});