RVS Production Setup for Appstore Billing Compatibility
After you publish your app, you can set up your app server to communicate with the RVS production server. HAQM recommends calling RVS from a secure server because it hosts the shared secret. Don't call RVS from your app. Set up your app server using your preferred language and technology. The server must communicate with RVS using a secure protocol such as HTTPS. Your server sends validation requests to RVS and then processes the responses it receives.
Client-side setup
On the client side, the onPurchaseUpdated()
method of the Appstore Billing Compatibility SDK gets invoked for new purchases. The following Android sample code performs the these tasks:
- Listens for the new purchases by overriding
onPurchaseUpdated()
method. - If purchase list is not null, verifies each of the purchases by passing the purchase token to your server.
- If purchase is valid, grants the items, or else logs the validation error.
private void processPurchaseList(List<Purchase> purchases, List<String> skusToUpdate) {
if (null != purchases) {
for (final Purchase purchase : purchases) {
// Verify the receipt using receipt verification service
final String purchaseToken = purchase.getPurchaseToken();
// Send purchase token to your secure backend for verification
if(verifyInAppItemReceipt(purchaseToken, productType, packageName)) {
// Process the purchase, grant the items
} else {
Log.d("Purchase is not valid")
}
}
}
}
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
switch (billingResult.getResponseCode()) {
case BillingClient.BillingResponseCode.OK:
if(list != null) {
processPurchaseList(list, null);
return;
}
else {
Log.d(TAG, "Null Purchase List Returned from OK response!");
}
break;
case BillingClient.BillingResponseCode.USER_CANCELED:
case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED:
case BillingClient.BillingResponseCode.DEVELOPER_ERROR:
// Handle these cases
break;
default:
// Handle default case
break;
}
}
Server-side setup
The following sample code is for a generic Java server. This code calls the purchases.products.get and purchases.subscriptionsv2.get APIs to perform the following tasks:
- Create a URL string with the appropriate developer and transaction information.
- Connect to the HAQM RVS server and pass the transaction URL to the server.
- Retrieve the response from the HAQM RVS server.
- Pass the response to the app.
// Verify entitlement or consumable receipt
public static void verifyInAppItemReceipt(final String developerSecret, final String packageName, final String token) {
// Call purchases.products.get API to validate inApp item purchase
String url = "http://appstore-sdk.haqm.com/version/1.0/" +
"developer/" + developerSecret + "/applications/" + packageName + "/purchases/subscriptionsv2/tokens/" + token
JSONObject responseJson = verifyReceipt(url);
JSONObject canceledStateContext = responseJson.getJSONObject("CanceledStateContext");
String purchaseToken = responseJson.getString("purchaseToken");
long purchaseTimeMillis = responseJson.getString("purchaseTimeMillis");
long cancelDate = responseJson.optLong("cancelDate");
boolean testTransaction = responseJson.optBoolean("testTransaction");
}
// Verify Subscription receipt
public static void verifySubscriptionReceipt(final String developerSecret, final String packageName, final String productId, final String token) {
// Call purchases.subscriptionsv2.get API to validate subscription item purchase.
String url = "http://appstore-sdk.haqm.com/version/1.0/" +
"developer/" + developerSecret + "/applications/" + packageName + "/purchases/products/" + productId + "/tokens/" + token
JSONObject responseJson = verifyReceipt(url);
String purchaseToken = responseJson.getString("purchaseToken");
String productType = responseJson.getString("productType");
String productId = responseJson.getString("productId");
long purchaseTimeMillis = responseJson.getString("purchaseTimeMillis");
long cancelDate = responseJson.optLong("cancelDate");
boolean testTransaction = responseJson.optBoolean("testTransaction");
}
private static void verifyReceipt(final String url) {
System.out.println("Start Receipt Validation");
System.out.println("HAQM Receipt Validation URL: " + url);
JSONObject responseJson = null;
try {
System.out.println("Open HTTP connection to HAQM RVS");
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
int responseCode = con.getResponseCode();
System.out.println("HAQM RVS Response Code: " + responseCode);
switch (responseCode)
{
case 400:
System.out.println("HAQM RVS Error: Invalid purchase token or productId");
// Process Response Data locally
// Respond to app
break;
case 401:
System.out.println("HAQM RVS Error: Invalid developerSecret");
// Process Response Data locally
// Respond to app
break;
case 404:
System.out.println("HAQM RVS Error: Invalid packageName");
// Process Response Data locally
// Respond to app
break;
case 500:
System.out.println("HAQM RVS Error: Internal Server Error");
// Process Response Data locally
// Respond to app
break;
case 200:
//Retrieve HAQM RVS Response
BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//Log HAQM RVS Response
System.out.println("HAQM RVS Response: " + response.toString()());
//Create JSONObject for RVS Response
JSONObject responseJson = new JSONObject(response.toString());
//Parse RVS Response
responseJson = new JSONObject(response.toString());
break;
default:
System.out.println("HAQM RVS Error: Undefined Response Code From HAQM RVS");
// Process Response Data locally
// Respond to app
break;
}
} catch (MalformedURLException e) {
// As a best practice, replace the following logic with logic for logging.
System.out.println("HAQM RVS MalformedURLException");
e.printStackTrace();
// Process Response Data locally
// Respond to app
} catch (IOException e) {
// As a best practice, replace the following logic with logic for logging.
System.out.println("HAQM RVS IOException");
e.printStackTrace();
// Process Response Data locally
// Respond to app
}
return responseJson;
}
Related topics
- RVS for Consumables and Entitlements
- RVS for Subscriptions
- RVS Examples for Appstore Billing Compatibility
Last updated: Dec 12, 2024