Java 谷歌安卓应用程序内购买”;“内容交付”;如何正确交付内容?
我目前正在尝试对应用内购买进行编码。我在寻找一些谷歌无法处理的文档、信息和最佳实践教程 到目前为止我所做的: 我有一个正在运行的计费服务,可以处理与Google Play的通话。此服务可以完成“示例”交易,我的应用程序将接收消息 我现在要将内容传送到设备。我认为接下来需要做的是:Java 谷歌安卓应用程序内购买”;“内容交付”;如何正确交付内容?,java,android,in-app-purchase,Java,Android,In App Purchase,我目前正在尝试对应用内购买进行编码。我在寻找一些谷歌无法处理的文档、信息和最佳实践教程 到目前为止我所做的: 我有一个正在运行的计费服务,可以处理与Google Play的通话。此服务可以完成“示例”交易,我的应用程序将接收消息 我现在要将内容传送到设备。我认为接下来需要做的是: 我的应用程序需要联系我的服务器,并显示一些交易成功的证据。做一些肯定的握手或诸如此类的胡说八道 然后我将下载内容并将其放入数据库。我可能应该使用某种设备唯一加密来加密数据库 我希望学习如何做上述两件事以及其他需要做的事
我希望学习如何做上述两件事以及其他需要做的事情。我想要合理数量的安全/加密。任何文档/教程/示例项目都很好,我已经尝试搜索过这些内容,但还没有找到我要找的内容。您必须对示例中的计费服务客户端代码进行一些更改 首先,您应该调用服务器获取用于恢复事务或进行购买的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);
}
}
/**
*验证数据是否已使用给定签名签名签名,并调用
*{@link ResponseHandler#purchaseResponse(上下文,PurchaseState,字符串,字符串,长)}
*对于每一次验证的购买。
*@param startId此服务调用实例的标识符
*@param signedData已签名的JSON字符串(已签名,未加密)
*@param signature数据的签名,使用私钥签名
*/
私有void purchaseStateChanged(int startId、字符串签名数据、字符串签名){
ArrayList购买;
购买=证券。验证购买(签名数据,签名);
如果(购买==null){
返回;
}
ArrayList notifyList=新建ArrayList();
用于(验证采购副总裁:采购){
如果(vp.notificationId!=null){
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(此,vp.purchaseState,vp.productId,
vp.orderId、vp.purchaseTime、vp.developerPayload);
}
如果(!notifyList.isEmpty()){
字符串[]notifyId=notifyList.toArray(新字符串[notifyList.size()]);
确认通知(startId、notifyid);
}
}
确保将您的公钥放在服务器端的ported Security.java文件中。谢谢!其他几个问题:我是否只是将BillingSecurity.java转储到某个服务器上?然后我如何连接到它来获得名词和比较公钥,等等?我以前在AppEngine实例中做过介绍,这就是我的经验。您应该调用服务器将nonce保存到数据库中(在服务器端),并将其与手头的事务关联。我通常使用时间戳和我从手机上获得的一些数据的组合,比如安卓ID。然后,这个nonce被发送到计费客户端。java模块包含基于开发者仪表板中的公钥验证签名的代码。谢谢,我还有一些工作要做。这会有很大帮助。如果我先购买一个项目,然后过一段时间我想下载它(应用程序未重新安装),会怎么样?是的,我可以在我的应用程序中触发该项目已购买,并且只有当该项目标记为已购买时,应用程序才允许下载该内容。但它看起来并不安全,因为“购买”状态存储在客户端。