Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/218.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 谷歌安卓应用程序内购买”;“内容交付”;如何正确交付内容?_Java_Android_In App Purchase - Fatal编程技术网

Java 谷歌安卓应用程序内购买”;“内容交付”;如何正确交付内容?

Java 谷歌安卓应用程序内购买”;“内容交付”;如何正确交付内容?,java,android,in-app-purchase,Java,Android,In App Purchase,我目前正在尝试对应用内购买进行编码。我在寻找一些谷歌无法处理的文档、信息和最佳实践教程 到目前为止我所做的: 我有一个正在运行的计费服务,可以处理与Google Play的通话。此服务可以完成“示例”交易,我的应用程序将接收消息 我现在要将内容传送到设备。我认为接下来需要做的是: 我的应用程序需要联系我的服务器,并显示一些交易成功的证据。做一些肯定的握手或诸如此类的胡说八道 然后我将下载内容并将其放入数据库。我可能应该使用某种设备唯一加密来加密数据库 我希望学习如何做上述两件事以及其他需要做的事

我目前正在尝试对应用内购买进行编码。我在寻找一些谷歌无法处理的文档、信息和最佳实践教程

到目前为止我所做的:

我有一个正在运行的计费服务,可以处理与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模块包含基于开发者仪表板中的公钥验证签名的代码。谢谢,我还有一些工作要做。这会有很大帮助。如果我先购买一个项目,然后过一段时间我想下载它(应用程序未重新安装),会怎么样?是的,我可以在我的应用程序中触发该项目已购买,并且只有当该项目标记为已购买时,应用程序才允许下载该内容。但它看起来并不安全,因为“购买”状态存储在客户端。