DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Interrupt Testing: Bulletproof Your App for the Real World
  • Test Automation for Mobile Apps: Strategy for Improved Testing Results
  • Why You Need to Shift Left With Mobile Testing
  • Exploring Mobile Device Lab: Pros and Cons

Trending

  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • AI Speaks for the World... But Whose Humanity Does It Learn From?
  • The Human Side of Logs: What Unstructured Data Is Trying to Tell You
  • Four Essential Tips for Building a Robust REST API in Java
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Sandbox Testing and Product Redelivery for In-Game Purchases

Sandbox Testing and Product Redelivery for In-Game Purchases

An example of implementing sandbox testing and consumable redelivery for in-app purchases. Game monetization, hit me!

By 
Jackson Jiang user avatar
Jackson Jiang
DZone Core CORE ·
Jan. 16, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
1.8K Views

Join the DZone community and get the full member experience.

Join For Free

Hey, guys! I'm still working on my mobile multiplayer survival game. In my article titled Build a Game That Features Local In-App Purchases, I shared my experience of configuring in-app product information in the language and currency of the country or region where the user's account is located, which streamlines the purchase journey for users and boosts monetization.

Some new challenges have arisen, though. When an in-app product is configured, I need to test its purchase process before it can be brought online. Hence, I need a virtual purchase environment that doesn't actually charge me real money. Sandbox testing it is.

Aside from this, network latency or abnormal process termination can sometimes cause data of the app and the in-app purchases server to be out of synchronization. In this case, my app won't deliver the virtual products users have just purchased. This same issue can be pretty tricky for many developers and operations personnel as we don't want to see a dreaded 1 star on the "About this app" screen of our app on app stores or users venting their anger about our apps on tech forums. Of course my app lets users request a refund by filing a ticket to start the process, but guess how they feel about the extra time they have to put into this?

So I wondered how to implement sandbox testing and ensure a successful product delivery for my app. That's where HMS Core In-App Purchases (IAP) comes to the rescue. I integrated its SDK to do the trick. Let's see how it works.

Sandbox Testing

Sandbox testing of IAP supports end-to-end testing without real payments for joint debugging.

Preparing for Sandbox Testing

I added a test account by going to Users and permissions > Sandbox > Test accounts. The test account needs to be a registered HUAWEI ID and will take effect between 30 minutes and an hour after it has been added.

As the app package I want to test hasn't been released in AppGallery Connect, its versionCode should exceed 0. For an app package once released in AppGallery Connect, the versionCode should be greater than that of the released one.

If you fail to access the sandbox when trying out the function, use the IapClient.isSandboxActivated (for Android) or HMSIAP.isSandboxActivated API (for HarmonyOS) in your app for troubleshooting.

Testing Non-Subscription Payments

I signed in with the test account and installed the app to be tested on my phone. When a request was initiated to purchase a one-time product (stealth skill card), IAP detected that I was a test user, so it skipped the payment step and displayed a message indicating that the payment was successful.

It was impressively smooth. The purchase process in the sandbox testing environment accurately reflected what would happen in reality. I noticed that the purchaseType field on the receipt generated in IAP had a value of 0, indicating that the purchase was a sandbox test record.

Let's try out a non-consumable product — the chance to unlock a special game character. In the sandbox testing environment, I purchased it and consumed it, and then I could purchase this character again.

Sandbox testing for a one-time product on a phone.

Testing Subscription Renewal

The purchase process of subscriptions is similar to that of one-time products but subscriptions have more details to consider, such as the subscription renewal result (success or failure) and subscription period. Test subscriptions renew much faster than actual subscriptions. For example, the actual subscription period is 1 week, while the test subscription renews every 3 minutes.

Sandbox testing for a subscription on a phone.

Sandbox testing helps me test new products before I launch them in my app.

Consumable Product Redelivery

When a user purchased a consumable such as a holiday costume, my app would call an API to consume it. However, if an exception occurred, the app would fail to determine whether the payment was successful, so the purchased product might not be delivered as expected. 

Note: A non-consumable or subscription will not experience such a delivery failure because they don't need to be consumed.

I turned to IAP to implement consumable redelivery. The process is as follows.

Consumable Redelivery Process

Here's my development process.

1. Call obtainOwnedPurchases to obtain the purchase data of the consumable that has been purchased but not delivered. Specify priceType as 0 in OwnedPurchasesReq.

If this API is successfully called, IAP will return an OwnedPurchasesResult object, which contains the purchase data and signature data of all products purchased but not delivered. Use the public key allocated by AppGallery Connect to verify the signature.

The data of each purchase is a character string in JSON format and contains the parameters listed in InAppPurchaseData. Parse the purchaseState field from the InAppPurchaseData character string. If purchaseState of a purchase is 0, the purchase is successful. Deliver the required product for this purchase again.

Java
 
// Construct an OwnedPurchasesReq object.
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// priceType: 0: consumable; 1: non-consumable; 2: subscription
ownedPurchasesReq.setPriceType(0);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainOwnedPurchases API to obtain the order information about all consumable products that have been purchased but not delivered.
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
    @Override
    public void onSuccess(OwnedPurchasesResult result) {
        // Obtain the execution result if the request is successful.
        if (result != null && result.getInAppPurchaseDataList() != null) {
            for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
                String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
                String inAppSignature = result.getInAppSignature().get(i);
                // Use the IAP public key to verify the signature of inAppPurchaseData.
                // Check the purchase status of each product if the verification is successful. When the payment has been made, deliver the required product. After a successful delivery, consume the product.
                try {
                    InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
                    int purchaseState = inAppPurchaseDataBean.getPurchaseState();
                } catch (JSONException e) {
                }
            }
        }
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(Exception e) {
        if (e instanceof IapApiException) {
            IapApiException apiException = (IapApiException) e;
            Status status = apiException.getStatus();
            int returnCode = apiException.getStatusCode();
        } else {
            // Other external errors.
        }
    }
});

2. Call the consumeOwnedPurchase API to consume a delivered product.

Conduct a delivery confirmation for all products queried through the obtainOwnedPurchases API. If a product is already delivered, call the consumeOwnedPurchase API to consume the product and instruct the IAP server to update the delivery status. After the consumption is complete, the server resets the product status to available for purchase. Then the product can be purchased again.

Conclusion

A 1-star app rating is an unwelcome sight for any developer. For game developers in particular, one of the major barriers to their app achieving a 5-star rating is a failed virtual product delivery.

I integrated HMS Core In-App Purchases into my mobile game to implement the consumable redelivery function, so now my users can smoothly make in-app purchases. Furthermore, when I need to launch a new skill card in the game, I can perform tests without having to fork out real money thanks to the kit.

I hope this practice helps you guys tackle similar challenges. If you have any other tips about game development that you'd like to share, please leave a comment.

mobile app Sandbox (software development) Testing

Published at DZone with permission of Jackson Jiang. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Interrupt Testing: Bulletproof Your App for the Real World
  • Test Automation for Mobile Apps: Strategy for Improved Testing Results
  • Why You Need to Shift Left With Mobile Testing
  • Exploring Mobile Device Lab: Pros and Cons

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: