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