4

現在、アプリ内購入をコード化しようとしています。Google が扱っていないもののいくつかのベスト プラクティスに関するドキュメント、情報、チュートリアルを探していました。

私がこれまでに行ったこと:

Google Play との通信を処理する課金サービスを実行しています。このサービスは「サンプル」トランザクションを完了することができ、私のアプリはメッセージを受け取ります。

コンテンツをデバイスに配信したいと思います。次に起こる必要があると思うこと:

  1. 私のアプリは私のサーバーに接続し、成功したトランザクションの証拠を示す必要があります。証明書の握手やそのようなナンセンスを行います。

  2. 次に、コンテンツをダウンロードして、そのコンテンツをデータベースに配置します。おそらく、ある種のデバイス固有の暗号化でデータベースを暗号化する必要があります。

上記の2つのことを行う方法と、他に行う必要があることを学びたいと思っています。妥当な量のセキュリティ/暗号化が必要です。ドキュメント/チュートリアル/サンプル プロジェクトはどれも素晴らしいものです。このようなものを検索してみましたが、探しているものが見つかりませんでした。

4

1 に答える 1

3

サンプルの課金サービス クライアント コードにいくつかの変更を加える必要があります。

まず、可能な限り安全にするために、サーバーを呼び出して、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 ファイルに配置してください。

于 2012-05-03T22:39:15.080 に答える