This document provides an overview and summary of in-app billing on Android platforms. It begins with an agenda that covers in-app billing overview, the Google Play billing service, the Android billing library, and security best practices. It then delves into details about the Google Play billing service API, including request and response parameters and types. It also discusses the Android billing library, which provides a wrapper for interacting with the Google Play billing service. It concludes with a brief discussion of security controls and limitations of the in-app billing system.
7. In-app billing terms
• Powered by Google Wallet
• 30% of the sale price
• No refunds (kinda)
• Only for digital goods
• Flexible pricing (unlike iOS)
8. Agenda
• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
9. Google Play Billing
Service
• Google Play only
• Android 1.6 upwards (API level 4)
• Now at version 2 with subscriptions
support
10. Product types
• In-app products
• Managed (per user account): premium, digital
content
• Unmanaged: virtual currency, consumable virtual
goods
• Subscriptions
• Monthly & yearly with free trials support
15. IAB requests
• MarketBillingService interface defined in an
Android Interface Definition Language file
(IMarketBillingService.aidl)
• IAB requests sent by single IPC method
(sendBillingRequest()) of the interface
• Request type and parameters are sent as a
Bundle
16. Binding to
MarketBillingService
try {
boolean bindResult = mContext.bindService(
new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
Context.BIND_AUTO_CREATE);
if (bindResult) {
Log.i(TAG, "Service bind successful.");
} else {
Log.e(TAG, "Could not bind to the MarketBillingService.");
}
} catch (SecurityException e) {
Log.e(TAG, "Security exception: " + e);
}
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "MarketBillingService connected.");
mService = IMarketBillingService.Stub.asInterface(service);
}
19. Making a request
Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString(ITEM_ID, mProductId);
Bundle response = mService.sendBillingRequest(request);
20. IAB responses
• The IAB service responds to every request
with a synchronous response
• Followed by 0..N asynchronous responses
depending of the request type
21. Synchronous responses
• RESPONSE_CODE: status information and
error information about a request
• REQUEST_ID: used to match
asynchronous responses with requests
• PURCHASE_INTENT: PendingIntent, which
you use to launch the checkout activity
• REQUEST_PURCHASE only
23. Receiving async
responses
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(INAPP_SIGNATURE);
// Do something with the signedData and the signature.
} else if (ACTION_NOTIFY.equals(action)) {
String notifyId = intent.getStringExtra(NOTIFICATION_ID);
// Do something with the notifyId.
} else if (ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
// Do something with the requestId and the responseCodeIndex.
} else {
Log.w(TAG, "unexpected action: " + action);
}
}
30. JSON fields (1)
• nonce: to verify the integrity of the
message
• notificationId: to match with
IN_APP_NOTIFY
• orderId: Google Wallet order id
• packageName: your app package
31. JSON fields (2)
• productId: set in the Developer Console
• purchaseTime: time of purchase
• purchaseState: purchased, cancelled,
refunded or expired
• purchaseToken: subscriptionId
• developerPayload: optional value
provided in REQUEST_PURCHASE
45. Android Billing Library
tiny.cc/android-billing
• Open-source on github
• “Better than starting from scratch”™
46. Features
• Full Android IAB Service implementation
• Auto-confirmations
• Obfuscated purchase database
• Implements security best practices
• Half-decent unit testing coverage
53. AndroidManifest.xml
<!-- Add this permission to your manifest -->
<uses-permission android:name="com.android.vending.BILLING" />
<application>
<!-- Add this service and receiver to your application -->
<service android:name="net.robotmedia.billing.BillingService" />
<receiver android:name="net.robotmedia.billing.BillingReceiver">
<intent-filter>
<action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
<action android:name="com.android.vending.billing.RESPONSE_CODE" />
<action
android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
</intent-filter>
</receiver>
</application>
54. Set Configuration
public void onCreate() {
super.onCreate();
BillingController.setDebug(true);
BillingController.setConfiguration(new BillingController.IConfiguration() {
@Override
public byte[] getObfuscationSalt() {
return new byte[] {41, -90, -116, -41, 66, -53, 122, -110, -127, -96, -88, 77, 127
}
@Override
public String getPublicKey() {
return "your public key here";
}
});
}
55. Agenda
• In-app Billing Overview
• Google Play Billing Service
• Android Billing Library
• Security Best Practices
56. Best Practices
• Random nonces
• Obfuscate purchase data
• Embedding public key
• Code obfuscation
• Server-side signature validation
57. Random nonces
• Sent with
GET_PURCHASE_INFORMATION and
RESTORE_TRANSACTION requests
• Handled by ABL
• Server-side nonce generation & verification
not supported by ABL (but really?)
58. Obfuscate purchase data
• Do not store purchase data plainly
• Handled by ABL
• Uses salt, installation id, device id and app id
to perform obfuscation
59. Embedding public key
• Do not embed the public key plainly
• Only embed the public key if you can’t
perform server-side signature validation
60. Code obfuscation
• Obfuscate your app code to make it harder
to hack
• Problem: ABL is open-source!
• Use ProGuard and consider making
changes to the ABL code
61. Server-side validation
• Perform the signature validation on a
server
• Supported by ABL
• Provide your own ISignatureValidator;
validation is performed with AsyncTask
• Return null on IConfiguration.getKey