我目前正在尝试编写应用内购买代码。我正在寻找有关Google无法处理的一些内容的最佳实践的文档,信息和教程。
到目前为止我做了什么:
我正在运行一项处理与Google Play通话的结算服务。此服务可以完成“示例”交易,我的应用程序会收到消息。
我现在要将内容传送到设备。我认为接下来需要发生的事情:
我的应用需要联系我的服务器并显示成功交易的一些证明。做一些证书手摇或一些这样的废话。
然后我将下载内容并将该内容放入数据库。我应该使用某种设备唯一的加密来加密数据库。
我正在寻找如何做上述事情和其他任何需要做的事情。我想要一个合理数量的安全/加密。任何文档/教程/示例项目都会很棒,我已经尝试过搜索这些东西并且找不到我想要的东西。
答案 0 :(得分: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);
}
}
然后调用thePurchaseStateChanged函数。应该通过调用服务器来替换此功能,以便为内容交付创建会话。应将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文件中的服务器端。