@hpique
Android In-app Billing        Demystified       Hermés Piqué         @hpique
Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
Top Grossingis dominated    by IAB
Freemium Digital goodsVirtual currency Subscriptions
User experience
In-app billing terms• Powered by Google Wallet• 30% of the sale price• No refunds (kinda)• Only for digital goods• Flexibl...
Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
Google Play Billing       Service• Google Play only• Android 1.6 upwards (API level 4)• Now at version 2 with subscription...
Product types• In-app products •   Managed (per user account): premium, digital     content •   Unmanaged: virtual currenc...
Pre-requisites• Services• AIDL• BroadcastReceiver• PendingIntent
Wait, there’s more• SQLite• Obfuscation• Signature validation• 57 pages of doc!
Architecture overview  app                Android    IAB         Market  requests                 Server
IAB requests• CHECK_BILLING_SUPPORTED• REQUEST_PURCHASE• GET_PURCHASE_INFORMATION• CONFIRM_NOTIFICATIONS• RESTORE_TRANSACT...
IAB requests• MarketBillingService interface defined in an  Android Interface Definition Language file  (IMarketBillingServic...
Binding to          MarketBillingServicetry {  boolean bindResult = mContext.bindService(    new Intent("com.android.vendi...
Request bundle           parameters•   Shared    •   BILLING_REQUEST: request type    •   API_VERSION: “1” for in-app prod...
Request bundleprotected Bundle makeRequestBundle(String method) {  Bundle request = new Bundle();  request.putString(BILLI...
Making a requestBundle request = makeRequestBundle("REQUEST_PURCHASE");request.putString(ITEM_ID, mProductId);Bundle respo...
IAB responses• The IAB service responds to every request  with a synchronous response• Followed by 0..N asynchronous respo...
Synchronous responses• RESPONSE_CODE: status information and  error information about a request• REQUEST_ID: used to match...
Asynchronous      responses• Broadcast intents: • RESPONSE_CODE • IN_APP_NOTIFY • PURCHASE_STATE_CHANGED
Receiving async                  responses public void onReceive(Context context, Intent intent) {    String action = inte...
Check Billing Supported
Check Billing               SupportedParameters                     SharedSync response keys        RESPONSE_CODE         ...
Request Purchase
Request Purchase                                Shared                               ITEM_IDParameters                    ...
Get Purchase             Information                               SharedParameters                    NONCE              ...
Purchase State Changed          JSON{ "nonce" : 1836535032137741465,  "orders" :    [{ "notificationId" : "android.test.pu...
JSON fields (1)• nonce: to verify the integrity of the  message• notificationId: to match with  IN_APP_NOTIFY• orderId: Goog...
JSON fields (2)• productId: set in the Developer Console• purchaseTime: time of purchase• purchaseState: purchased, cancell...
Purchase states• Purchased (0)• Cancelled (1)• Refunded (2)• Expired (3): subscriptions only
Confirm Notifications                              SharedParameters                   NONCE                            NOTIF...
Unsolicited In-app       Notify• Purchase when app is running in  various devices• Refunds• Subscription expired (?)
Unsolicited In-app     Notify
Restore Transactions
Restore Transactions                                BasicParameters                              NONCE                    ...
Security Controls• Signed purchase data• In-app notify nonces
Purchase State   Changed Extras• inapp_signed_data: Signed JSON  string (unencrypted)• inapp_signature: Use the Google  Pl...
IAB limitations• No API for product details & price• To fully test you need to pay for real• Sometimes async messages are ...
Obligatory image of Justin Bieber to wake you up
Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
requestPurchase("com.example.item");
Android Billing Library     tiny.cc/android-billing• Open-source on github• “Better than starting from scratch”™
Features• Full Android IAB Service implementation• Auto-confirmations• Obfuscated purchase database• Implements security be...
Overview• BillingController• IBillingObserver• BillingController.IConfiguration• ISignatureValidator
Overview
Check Billing                Supported"   @Override"   public void onCreate(Bundle savedInstanceState) {"   " // ..."   " ...
Request PurchaseBillingController.requestPurchase(this, productId);@Overridepublic void onPurchaseIntent(String itemId, Pe...
Restore Transactionsif (!mBillingObserver.isTransactionsRestored()) {	 BillingController.restoreTransactions(this);	 Toast...
Suggestedimplementation
AndroidManifest.xml    <!-- Add this permission to your manifest -->    <uses-permission android:name="com.android.vending...
Set Configuration	   public void onCreate() {	   	 super.onCreate();	   	 BillingController.setDebug(true);	   	 BillingCon...
Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
Best Practices• Random nonces• Obfuscate purchase data• Embedding public key• Code obfuscation• Server-side signature vali...
Random nonces• Sent with  GET_PURCHASE_INFORMATION and  RESTORE_TRANSACTION requests• Handled by ABL• Server-side nonce ge...
Obfuscate purchase data • Do not store purchase data plainly • Handled by ABL • Uses salt, installation id, device id and ...
Embedding public key• Do not embed the public key plainly• Only embed the public key if you can’t  perform server-side sig...
Code obfuscation• Obfuscate your app code to make it harder  to hack• Problem: ABL is open-source!• Use ProGuard and consi...
Server-side validation• Perform the signature validation on a  server• Supported by ABL• Provide your own ISignatureValida...
Thanks!
Android in-app billing @ Google DevFest Barcelona 2012
Upcoming SlideShare
Loading in …5
×

Android in-app billing @ Google DevFest Barcelona 2012

1,807 views

Published on

Published in: Technology
1 Comment
2 Likes
Statistics
Notes
  • POR FAVOR ESTA PROPUESTA DE NEGOCIO, ESCRIBA EN MI ESPALDA ID si está interesado.
    ------------------------------------

    Feliz mes nuevo abundante de noviembre,

    Hola.

    ¿Cómo estás hoy?
    Espero que estés bien y que todo está bien con usted? gracias God.My nombre es jenifer PETERSON. (estoy buscando una buena relación y además que tenga propuesta de negocios con usted) si lo desea. por favor, escríbeme mensaje a mi buzón de correo electrónico
    Thanks,>

    jeniferpeterson1 en / yh / dt / cum
    ---------------------

    PLEASE THIS BUSINESS PROPOSAL, WRITE ON MY ID BACK IF INTERESTED.
    ------------------------------------

    Happy abundant new month of November,

    Hello.

    how are you today?
    I hope you are fine and all is well with you ? thank God.My name is JENIFER PETERSON .(i am looking for a good relationship and also to have business proposal with you )if you want. please write me message to my email box
    THANKS,>

    jeniferpeterson1 at / yh / dt / cum
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
1,807
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
54
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Android in-app billing @ Google DevFest Barcelona 2012

    1. 1. @hpique
    2. 2. Android In-app Billing Demystified Hermés Piqué @hpique
    3. 3. Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
    4. 4. Top Grossingis dominated by IAB
    5. 5. Freemium Digital goodsVirtual currency Subscriptions
    6. 6. User experience
    7. 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. 8. Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
    9. 9. Google Play Billing Service• Google Play only• Android 1.6 upwards (API level 4)• Now at version 2 with subscriptions support
    10. 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
    11. 11. Pre-requisites• Services• AIDL• BroadcastReceiver• PendingIntent
    12. 12. Wait, there’s more• SQLite• Obfuscation• Signature validation• 57 pages of doc!
    13. 13. Architecture overview app Android IAB Market requests Server
    14. 14. IAB requests• CHECK_BILLING_SUPPORTED• REQUEST_PURCHASE• GET_PURCHASE_INFORMATION• CONFIRM_NOTIFICATIONS• RESTORE_TRANSACTIONS
    15. 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. 16. Binding to MarketBillingServicetry {  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);}
    17. 17. Request bundle parameters• Shared • BILLING_REQUEST: request type • API_VERSION: “1” for in-app products, “2” for subscriptions • PACKAGE_NAME: app package• Specific • ITEM_ID, ITEM_TYPE, NONCE, NOTIFY_ID, DEVELOPER_PAYLOAD
    18. 18. Request bundleprotected Bundle makeRequestBundle(String method) {  Bundle request = new Bundle();  request.putString(BILLING_REQUEST, method);  request.putInt(API_VERSION, 1);  request.putString(PACKAGE_NAME, getPackageName());  return request;}
    19. 19. Making a requestBundle request = makeRequestBundle("REQUEST_PURCHASE");request.putString(ITEM_ID, mProductId);Bundle response = mService.sendBillingRequest(request);
    20. 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. 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
    22. 22. Asynchronous responses• Broadcast intents: • RESPONSE_CODE • IN_APP_NOTIFY • PURCHASE_STATE_CHANGED
    23. 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);    }  }
    24. 24. Check Billing Supported
    25. 25. Check Billing SupportedParameters SharedSync response keys RESPONSE_CODE RESULT_OK RESULT_BILLING_UNAVAILABLEResponse codes RESULT_ERROR RESULT_DEVELOPER_ERRORAsync response RESPONSE_CODE
    26. 26. Request Purchase
    27. 27. Request Purchase Shared ITEM_IDParameters ITEM_TYPE DEVELOPER_PAYLOAD RESPONSE_CODESync response keys PURCHASE_INTENT REQUEST_ID RESULT_OKResponse codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODEAsync response IN_APP_NOTIFY
    28. 28. Get Purchase Information SharedParameters NONCE NOTIFY_IDS RESPONSE_CODESync response keys REQUEST_ID RESULT_OKResponse codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODEAsync response PURCHASE_STATE_CHANGED
    29. 29. Purchase State Changed JSON{ "nonce" : 1836535032137741465, "orders" : [{ "notificationId" : "android.test.purchased", "orderId" : "transactionId.android.test.purchased", "packageName" : "com.example.dungeons", "productId" : "android.test.purchased", "developerPayload" : "bGoa+V7g/yqDXvKRq", "purchaseTime" : 1290114783411, "purchaseState" : 0, "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }]}
    30. 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. 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
    32. 32. Purchase states• Purchased (0)• Cancelled (1)• Refunded (2)• Expired (3): subscriptions only
    33. 33. Confirm Notifications SharedParameters NONCE NOTIFY_IDS RESPONSE_CODESync response keys REQUEST_ID RESULT_OKResponse codes RESULT_ERROR RESULT_DEVELOPER_ERRORAsync response RESPONSE_CODE
    34. 34. Unsolicited In-app Notify• Purchase when app is running in various devices• Refunds• Subscription expired (?)
    35. 35. Unsolicited In-app Notify
    36. 36. Restore Transactions
    37. 37. Restore Transactions BasicParameters NONCE RESPONSE_CODESync response keys REQUEST_ID RESULT_OKResponse codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODEAsync response PURCHASE_STATE_CHANGED
    38. 38. Security Controls• Signed purchase data• In-app notify nonces
    39. 39. Purchase State Changed Extras• inapp_signed_data: Signed JSON string (unencrypted)• inapp_signature: Use the Google Play public key to validate
    40. 40. IAB limitations• No API for product details & price• To fully test you need to pay for real• Sometimes async messages are really async
    41. 41. Obligatory image of Justin Bieber to wake you up
    42. 42. Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
    43. 43. requestPurchase("com.example.item");
    44. 44. Android Billing Library tiny.cc/android-billing• Open-source on github• “Better than starting from scratch”™
    45. 45. Features• Full Android IAB Service implementation• Auto-confirmations• Obfuscated purchase database• Implements security best practices• Half-decent unit testing coverage
    46. 46. Overview• BillingController• IBillingObserver• BillingController.IConfiguration• ISignatureValidator
    47. 47. Overview
    48. 48. Check Billing Supported" @Override" public void onCreate(Bundle savedInstanceState) {" " // ..." " BillingController.registerObserver(mBillingObserver);" " BillingController.checkBillingSupported(this);" " // ..." }" public void onBillingChecked(boolean supported) {" " if (!supported) {" " " showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);" " }" }
    49. 49. Request PurchaseBillingController.requestPurchase(this, productId);@Overridepublic void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) { BillingController.startPurchaseIntent(activity, purchaseIntent, null);}@Overridepublic void onRequestPurchaseResponse(String itemId, ResponseCode response) {}@Overridepublic void onPurchaseStateChanged(String itemId, Order order) {}
    50. 50. Restore Transactionsif (!mBillingObserver.isTransactionsRestored()) { BillingController.restoreTransactions(this); Toast.makeText(this, R.string.restoring_transactions,Toast.LENGTH_LONG).show();}@Overridepublic void onTransactionsRestored() { final SharedPreferences preferences =PreferenceManager.getDefaultSharedPreferences(activity); final Editor editor = preferences.edit(); editor.putBoolean(KEY_TRANSACTIONS_RESTORED, true); editor.commit();}
    51. 51. Suggestedimplementation
    52. 52. 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" /> <actionandroid:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" /> </intent-filter> </receiver> </application>
    53. 53. 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"; } }); }
    54. 54. Agenda• In-app Billing Overview• Google Play Billing Service• Android Billing Library• Security Best Practices
    55. 55. Best Practices• Random nonces• Obfuscate purchase data• Embedding public key• Code obfuscation• Server-side signature validation
    56. 56. 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?)
    57. 57. Obfuscate purchase data • Do not store purchase data plainly • Handled by ABL • Uses salt, installation id, device id and app id to perform obfuscation
    58. 58. Embedding public key• Do not embed the public key plainly• Only embed the public key if you can’t perform server-side signature validation
    59. 59. 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
    60. 60. 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
    61. 61. Thanks!

    ×