サンプルの課金サービス クライアント コードにいくつかの変更を加える必要があります。
まず、可能な限り安全にするために、サーバーを呼び出して、RestoreTransactions または購入のいずれかに使用される nonce を取得する必要があります。
何が起こるかを追ってみましょう。Google Play によって呼び出される BillingReceiver は次のとおりです。
/**
* This is called when Android Market sends information about a purchase state
* change. The signedData parameter is a plaintext JSON string that is
* signed by the server with the developer's private key. The signature
* for the signed data is passed in the signature parameter.
* @param context the context
* @param signedData the (unencrypted) JSON string
* @param signature the signature for the signedData
*/
private void purchaseStateChanged(Context context, String signedData, String signature) {
Intent intent = new Intent(Consts.ACTION_PURCHASE_STATE_CHANGED);
intent.setClass(context, BillingService.class);
intent.putExtra(Consts.INAPP_SIGNED_DATA, signedData);
intent.putExtra(Consts.INAPP_SIGNATURE, signature);
context.startService(intent);
}
BillingService.java 内の handleCommand を見ると、このインテントを処理しています。
/**
* The {@link BillingReceiver} sends messages to this service using intents.
* Each intent has an action and some extra arguments specific to that action.
* @param intent the intent containing one of the supported actions
* @param startId an identifier for the invocation instance of this service
*/
public void handleCommand(Intent intent, int startId) {
String action = intent.getAction();
if (Consts.DEBUG) {
Log.i(TAG, "handleCommand() action: " + action);
}
if (Consts.ACTION_CONFIRM_NOTIFICATION.equals(action)) {
String[] notifyIds = intent.getStringArrayExtra(Consts.NOTIFICATION_ID);
confirmNotifications(startId, notifyIds);
} else if (Consts.ACTION_GET_PURCHASE_INFORMATION.equals(action)) {
String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
getPurchaseInformation(startId, new String[] { notifyId });
} else if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
purchaseStateChanged(startId, signedData, signature);
} else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
ResponseCode responseCode = ResponseCode.valueOf(responseCodeIndex);
checkResponseCode(requestId, responseCode);
}
}
次に、PurchaseStateChanged 関数を呼び出します。この関数は、サーバーへの呼び出しに置き換えて、コンテンツ配信用のセッションを作成する必要があります。クラウド内のトランザクションを検証するには、Security.java のコードをサーバー側に移植する必要があります。
/**
* Verifies that the data was signed with the given signature, and calls
* {@link ResponseHandler#purchaseResponse(Context, PurchaseState, String, String, long)}
* for each verified purchase.
* @param startId an identifier for the invocation instance of this service
* @param signedData the signed JSON string (signed, not encrypted)
* @param signature the signature for the data, signed with the private key
*/
private void purchaseStateChanged(int startId, String signedData, String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(this, vp.purchaseState, vp.productId,
vp.orderId, vp.purchaseTime, vp.developerPayload);
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
}
公開鍵をサーバー側の移植された Security.java ファイルに配置してください。