android amazon payment access

process:

Apply for an Amazon developer account ---> Add an application in the Amazon console ---> Add in-app products (consumable products, authorized products, subscription products) ---> Export JSON file ---> Integrate Amazon payment ---> Copy the exported JSON file to the /mnt/sdcard/ directory ---> Test payment in Shahe mode ---> Upload and publish

Note: Amazon currently uses V1 signature; 2.targetSdkVersion version must be less than or equal to 29

There are three SDK operating modes :

①: SANDBOX Shahe mode, used for testing, interacting with the Amazon App Tester testing tool

②: PRODUCTION must be submitted to the Amazon App Store before testing

③: UNKNOWN verifyLicense()The SDK has not been initialized by calling.
 

Step 1: Integrate Amazon In-Purchase SDK

    implementation 'com.amazon.device:amazon-appstore-sdk:3.0.4'

Step 2:  Add  the application targetSdkVersion in the AndroidManifest.xml ResponseReceiver 配置,如果 file and set it to 31 or higher. You must explicitly set  android :exported ResponseReceiver  in the android:exported  setting  true.

<receiver android:name="com.amazon.device.iap.ResponseReceiver" android:exported="true"
            android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY" >
            <intent-filter>
                <action
                    android:name="com.amazon.inapp.purchasing.NOTIFY" />
            </intent-filter>
 </receiver>

Step 3: Implement and register PurchasingListener (called in the onCreate life cycle method)

 purchasingListener = new PurchasingListener() {
            /**
             * 确定当前登录用户的UserId和marketplace。
             * @param response
             */
            @Override
            public void onUserDataResponse(final UserDataResponse response) {
                Log.d(LOG_TAG, "onUserDataResponse: requestId (" + response.getRequestId()
                        + ") userIdRequestStatus: "
                        + response.getRequestStatus()
                        + ")");
                //当前用户相关信息(用户ID和市场
                final UserDataResponse.RequestStatus status = response.getRequestStatus();
                switch (status) {
                    case SUCCESSFUL:
                        Log.d(LOG_TAG, "onUserDataResponse: get user id " + response.getUserData().getUserId()
                                + ", marketplace "
                                + response.getUserData().getMarketplace());
                        currentUserId = response.getUserData().getUserId();
                        currentMarketplace = response.getUserData().getMarketplace();
                        break;

                    case FAILED:
                        Log.d(LOG_TAG, "onUserDataResponse FAILED failed, status code is " + status);
                    case NOT_SUPPORTED:
                        Log.d(LOG_TAG, "onUserDataResponse NOT_SUPPORTED failed, status code is " + status);
                        break;
                }
            }

            /**
             * 检索应用中销售的SKU的信息
             * 使用来自ProductDataResponse对象的有效SKU。
             *
             * @param response
             */
            @Override
            public void onProductDataResponse(final ProductDataResponse response) {
                final ProductDataResponse.RequestStatus status = response.getRequestStatus();
                Log.d(LOG_TAG, "onProductDataResponse: RequestStatus (" + status + ")");

                switch (status) {
                    case SUCCESSFUL:
                        Log.d(LOG_TAG, "onProductDataResponse: successful.  The item data map in this response includes the valid SKUs");
                        final Set<String> unavailableSkus = response.getUnavailableSkus();
                        for (final String s : response.getUnavailableSkus()) {
                            Log.v(LOG_TAG, unavailableSkus.size() + " 不可用SKU:" + s);
                        }
                        final Map<String, Product> products = response.getProductData();
                        for (final String key : products.keySet()) {
                            Product product = products.get(key);
                            Log.v(LOG_TAG, String.format("可购买的产品:%s\n 类型:%s\n SKU:%s\n 价格:%s\n 描述:%s\n", product.getTitle(), product.getProductType(), product.getSku(), product.getPrice(), product.getDescription()));
                            // 处理产品
                        }
                        break;
                    case FAILED:
                    case NOT_SUPPORTED:
                        Log.d(LOG_TAG, "onProductDataResponse: failed, should retry request");
                        break;
                }
            }

            /**
             * 检索自上次调用该方法之后用户完成的所有购买交易
             * 仅可检索未履行和已取消的消费品购买
             * @param response
             */
            @Override
            public void onPurchaseUpdatesResponse(final PurchaseUpdatesResponse response) {

                Log.d(LOG_TAG, "PurchaseUpdatesResponse: requestId (" + response.getRequestId()
                        + ") Status ("
                        + response.getRequestStatus()
                        + ") userId ("
                        + response.getUserData().getUserId()
                        + ")");
                //获取请求状态
                final PurchaseUpdatesResponse.RequestStatus status = response.getRequestStatus();
                switch (status) {
                    case SUCCESSFUL:
                        Log.e(LOG_TAG, "========no consumeProduct==========" + response.getReceipts());
                        //PurchasingService.getProductData
                        for (final Receipt receipt : response.getReceipts()) {
                            LogD("购买收据 + receipt " + receipt.isCanceled() + "\n" + "收据:" + receipt.getReceiptId());
                            if (!receipt.isCanceled()) {
                                String localReceipt = SharedPreferencesUtil.getString(mContext, receipt.getReceiptId(), "");
                                Gson gson = new Gson();
                                Type type = new TypeToken<Hashtable<String, String>>(){}.getType();
                                Hashtable<String, String> localPurchase= gson.fromJson(localReceipt, type);
                                if(null!=localPurchase){
                                    myProductInfo = localPurchase;
                                }
                                receiptID = receipt.getReceiptId();
                                Log.e(LOG_TAG, "----------myProductInfo------------: " + myProductInfo);
                                consumeProduct(receipt,"2");
                            }
                        }

//                        if (response.hasMore()) {
//                            //如果不启用“待定购买”,则在每次getPurchaseUpdates(false)调用中只返回未履行的消费品收据
//                            PurchasingService.getPurchaseUpdates(false);
//                            return;
//                        }
                        break;
                    case NOT_SUPPORTED:
                        Log.d(LOG_TAG, "onProductDataResponse: failed, should retry request");
                        break;
                }
            }

            /**
             * purchase()用户拉起支付后,用于确定购买状态。
             *
             * @param response
             */
            @Override
            public void onPurchaseResponse(final PurchaseResponse response) {
                final String requestId = response.getRequestId().toString();
                final String userId = response.getUserData().getUserId();
                final PurchaseResponse.RequestStatus status = response.getRequestStatus();
                Log.d(LOG_TAG, "支付成功回调 onPurchaseResponse: requestId (" + requestId
                        + ") userId ("
                        + userId
                        + ") purchaseRequestStatus ("
                        + status
                        + ")");

                switch (status) {
                    case SUCCESSFUL:
                        //交易成功
                        final Receipt receipt = response.getReceipt();
                        Log.d(LOG_TAG, "onPurchaseResponse: receipt json:" + receipt.toJSON());
                        receiptID = receipt.getReceiptId();
                        Log.d(LOG_TAG, "onPurchaseResponse: receipt receiptID:" + receipt.getReceiptId());

                       //请求服务端跟amazon校验
                       //校验成功去消耗
                        
                          PurchasingService.notifyFulfillment(receiptID, FulfillmentResult.FULFILLED);

                        break;
//                    case PENDING:
//                        Log.d(LOG_TAG, "onPurchaseResponse: 等待远程批准——如果获得批准,购买将在 getPurchaseUpdates 中返回");
//                        break;
                    case ALREADY_PURCHASED:
                        //已经授权过的,属于成功,此时将道具给玩家即可
                        Log.d(LOG_TAG, "onPurchaseResponse: 已经授权过的,属于成功,此时将道具给玩家即可");
                        break;
                    case INVALID_SKU:
                        Log.d(LOG_TAG, "onPurchaseResponse: invalid SKU!无效SKU,无法识别");
                        break;
                    case FAILED:
                    case NOT_SUPPORTED:
                        Log.e(LOG_TAG, "支付失败 用户在完成之前取消了购买");
                        break;
                }
            }
        };

Step 4: Register the listener (called in the onCreate life cycle method)

PurchasingService.registerListener(mContext, purchasingListener);

Step 5: 通过 getUserData() Current user related (user ID and market), I put it in the onCreate life cycle method 

PurchasingService.getUserData(); (called in onCreate life cycle method)

Step 6: Retrieve all purchases completed by the user since the last time this method was called to ensure that the latest updates are obtained

PurchasingService.getPurchaseUpdates(true); (called in onCreate life cycle method)
  • false - Returns getPurchaseUpdates()a paginated response of purchase records since the last call. Retrieve receipts for a user's outstanding consumer goods, entitlements, and subscription purchases. The Amazon Appstore recommends using this method in most cases.

     Note:  If your app has pending purchases enabled , the Amazon Appstore getPurchaseUpdates(false)returns all unfulfilled purchase and entitlement receipts to the user on every call until your app calls it notifyFulfillment(). If "Pending Purchases" is not enabled, getPurchaseUpdates(false)only unfulfilled consumer product receipts are returned on each call.

  • true - Retrieve the user's complete purchase history. Either the data needs to be stored somewhere (such as a server-side data cache), or all data needs to be kept in memory.

Step 7: Verify the SKU. The purchase will not fail unexpectedly due to invalid SKU.

 Set<String> productSkus = new HashSet<>();
                productSkus.add("skus1");
                productSkus.add("skus12");
                productSkus.add("skus3");
                ....
                PurchasingService.getProductData(productSkus);// 触发PurchasingListener.onProductDataResponse()

Step 8: Pull up the payment popup to pay

            final RequestId requestId =  PurchasingService.purchase("Product_Id");

Note: Before consuming goods, first complete the back-end server verification through Amazon's Receipt Verification Service (RVS) receiptIdto verify the receipt generated by the purchase. Consumption after verification.

Test process :

1: Download Amazon App Tester from the Amazon App Store to your phone. App Tester simulates production environment, download link

2: Download the amazon.sdktester.json file in the background and copy it to /sdcard/the folder on your phone. Find the IAP items in JSON File in the Amazon App Tester application and see if there is data.

       adb push F:/download/amazon.sdktester.json /mnt/sdcard/

3: adb shell setprop debug.amazon.sandboxmode debug is set to sandbox mode

//Check if the app is in test mode

  Log.d(TAG, "Appstore SDK Mode: " + LicensingService.getAppstoreSDKMode()); 

  The above is the Amazon payment access process. Official payment can be made only after it is published to Amazon, but the display effect of formal payment and test payment is the same.

Guess you like

Origin blog.csdn.net/u010207898/article/details/132457595