SlideShare a Scribd company logo
@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 Grossing
is dominated
    by IAB
Freemium
 Digital goods
Virtual currency
 Subscriptions
User experience
In-app billing terms

• Powered by Google Wallet
• 30% of the sale price
• No refunds (kinda)
• Only for digital goods
• Flexible pricing (unlike iOS)
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 subscriptions
  support
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
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_TRANSACTIONS
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
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);
}
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
Request bundle

protected 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;
}
Making a request


Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString(ITEM_ID, mProductId);
Bundle response = mService.sendBillingRequest(request);
IAB responses

• The IAB service responds to every request
  with a synchronous response
• Followed by 0..N asynchronous responses
  depending of the request type
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
Asynchronous
      responses
• Broadcast intents:
 • RESPONSE_CODE
 • IN_APP_NOTIFY
 • PURCHASE_STATE_CHANGED
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);
    }
  }
Check Billing
 Supported
Check Billing
               Supported
Parameters                     Shared
Sync response keys        RESPONSE_CODE
                             RESULT_OK
                     RESULT_BILLING_UNAVAILABLE
Response codes
                            RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
Async response            RESPONSE_CODE
Request Purchase
Request Purchase
                                Shared
                               ITEM_ID
Parameters
                             ITEM_TYPE
                       DEVELOPER_PAYLOAD
                         RESPONSE_CODE
Sync response keys      PURCHASE_INTENT
                            REQUEST_ID
                            RESULT_OK
Response codes             RESULT_ERROR
                     RESULT_DEVELOPER_ERROR
                         RESPONSE_CODE
Async response
                          IN_APP_NOTIFY
Get Purchase
             Information
                               Shared
Parameters                    NONCE
                             NOTIFY_IDS
                          RESPONSE_CODE
Sync response keys
                            REQUEST_ID
                             RESULT_OK
Response codes             RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
                          RESPONSE_CODE
Async response
                     PURCHASE_STATE_CHANGED
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" }]
}
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
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
Purchase states

• Purchased (0)
• Cancelled (1)
• Refunded (2)
• Expired (3): subscriptions only
Confirm Notifications
                              Shared
Parameters                   NONCE
                            NOTIFY_IDS
                         RESPONSE_CODE
Sync response keys
                           REQUEST_ID
                            RESULT_OK
Response codes            RESULT_ERROR
                     RESULT_DEVELOPER_ERROR
Async response           RESPONSE_CODE
Unsolicited In-app
       Notify
• Purchase when app is running in
  various devices
• Refunds
• Subscription expired (?)
Unsolicited In-app
     Notify
Restore Transactions
Restore Transactions
                                Basic
Parameters
                              NONCE
                          RESPONSE_CODE
Sync response keys
                            REQUEST_ID
                             RESULT_OK
Response codes             RESULT_ERROR
                      RESULT_DEVELOPER_ERROR
                          RESPONSE_CODE
Async response
                     PURCHASE_STATE_CHANGED
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
  Play public key to validate
IAB limitations

• No API for product details & price
• To fully test you need to pay for real
• Sometimes async messages are really async
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 best practices
• Half-decent unit testing coverage
Overview

• BillingController
• IBillingObserver
• BillingController.IConfiguration
• ISignatureValidator
Overview
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);
"   " }
"   }
Request Purchase
BillingController.requestPurchase(this, productId);


@Override
public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) {
	 BillingController.startPurchaseIntent(activity, purchaseIntent, null);
}

@Override
public void onRequestPurchaseResponse(String itemId, ResponseCode response) {

}

@Override
public void onPurchaseStateChanged(String itemId, Order order) {

}
Restore Transactions
if (!mBillingObserver.isTransactionsRestored()) {
	 BillingController.restoreTransactions(this);
	 Toast.makeText(this, R.string.restoring_transactions,
Toast.LENGTH_LONG).show();
}

@Override
public void onTransactionsRestored() {
	 final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(activity);
	 final Editor editor = preferences.edit();
	 editor.putBoolean(KEY_TRANSACTIONS_RESTORED, true);
	 editor.commit();
}
Suggested
implementation
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>
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";
	   	   	 }
	   	   });
	   }
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 validation
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?)
Obfuscate purchase data

 • Do not store purchase data plainly
 • Handled by ABL
 • Uses salt, installation id, device id and app id
   to perform obfuscation
Embedding public key


• Do not embed the public key plainly
• Only embed the public key if you can’t
  perform server-side signature validation
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
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
Thanks!

More Related Content

Similar to Android in-app billing @ Google DevFest Barcelona 2012

Android In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaAndroid In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaRobot Media
 
IAP auto renewable in practice
IAP auto renewable  in practiceIAP auto renewable  in practice
IAP auto renewable in practiceHokila Jan
 
2012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML52012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML5Jonathan LeBlanc
 
AdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemAdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemPlayFab, Inc.
 
HTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsHTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsJonathan LeBlanc
 
API Product Management and Strategy
API Product Management and StrategyAPI Product Management and Strategy
API Product Management and Strategyadritab
 
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILEINTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILERajesh Roky
 
iOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftiOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftKaz Yoshikawa
 
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Amazon Web Services
 
App Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionApp Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionMark Pavlidis
 
Big commerce app development
Big commerce app developmentBig commerce app development
Big commerce app developmentNascenia IT
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays SydneyBraintree
 
Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Todd Kaplinger
 

Similar to Android in-app billing @ Google DevFest Barcelona 2012 (20)

Android In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon MurciaAndroid In-app Billing @ Droidcon Murcia
Android In-app Billing @ Droidcon Murcia
 
IAP auto renewable in practice
IAP auto renewable  in practiceIAP auto renewable  in practice
IAP auto renewable in practice
 
2012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML52012 SVCodeCamp: In App Payments with HTML5
2012 SVCodeCamp: In App Payments with HTML5
 
AdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-MortemAdVenture Capitalist Post-Mortem
AdVenture Capitalist Post-Mortem
 
HTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsHTML5 Gaming Payment Platforms
HTML5 Gaming Payment Platforms
 
Samsung IAP SDK
Samsung IAP SDKSamsung IAP SDK
Samsung IAP SDK
 
API Product Management and Strategy
API Product Management and StrategyAPI Product Management and Strategy
API Product Management and Strategy
 
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILEINTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
INTEGRATED SHOPPING ASSISTANCE WITH FREDGE AND MOBILE
 
In App Purchases
In  App  PurchasesIn  App  Purchases
In App Purchases
 
iOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in SwiftiOS In-App-Purchase verifying receipt locally in Swift
iOS In-App-Purchase verifying receipt locally in Swift
 
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
Selling Physical GoodsThrough Apps & Other Monetization Strategies (MBL306) |...
 
Fire up your mobile app!
Fire up your mobile app!Fire up your mobile app!
Fire up your mobile app!
 
App Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed EditionApp Store Subscriptions - Condensed Edition
App Store Subscriptions - Condensed Edition
 
Shopify
ShopifyShopify
Shopify
 
Big commerce app development
Big commerce app developmentBig commerce app development
Big commerce app development
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays Sydney
 
APIDays Sydney
APIDays SydneyAPIDays Sydney
APIDays Sydney
 
In-App Purchase API
In-App Purchase APIIn-App Purchase API
In-App Purchase API
 
Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!Interconnect Mobile Application Development on Bluemix!!
Interconnect Mobile Application Development on Bluemix!!
 
Workshop CQRS and DDD
Workshop CQRS and DDDWorkshop CQRS and DDD
Workshop CQRS and DDD
 

Recently uploaded

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...Product School
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backElena Simperl
 
Optimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityOptimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityScyllaDB
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutesconfluent
 
UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1DianaGray10
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka DoktorováCzechDreamin
 
IESVE for Early Stage Design and Planning
IESVE for Early Stage Design and PlanningIESVE for Early Stage Design and Planning
IESVE for Early Stage Design and PlanningIES VE
 
In-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT ProfessionalsIn-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT ProfessionalsExpeed Software
 
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)Julian Hyde
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationZilliz
 
AI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekAI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekCzechDreamin
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesBhaskar Mitra
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxAbida Shariff
 
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...CzechDreamin
 
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...CzechDreamin
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Jeffrey Haguewood
 
IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoTAnalytics
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3DianaGray10
 
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀DianaGray10
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 

Recently uploaded (20)

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Optimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityOptimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through Observability
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutes
 
UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
 
IESVE for Early Stage Design and Planning
IESVE for Early Stage Design and PlanningIESVE for Early Stage Design and Planning
IESVE for Early Stage Design and Planning
 
In-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT ProfessionalsIn-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT Professionals
 
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG Evaluation
 
AI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekAI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří Karpíšek
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
 
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 

Android in-app billing @ Google DevFest Barcelona 2012

  • 2. Android In-app Billing Demystified Hermés Piqué @hpique
  • 3. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 5. Freemium Digital goods Virtual currency Subscriptions
  • 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
  • 11. Pre-requisites • Services • AIDL • BroadcastReceiver • PendingIntent
  • 12. Wait, there’s more • SQLite • Obfuscation • Signature validation • 57 pages of doc!
  • 13. Architecture overview app Android IAB Market requests Server
  • 14. IAB requests • CHECK_BILLING_SUPPORTED • REQUEST_PURCHASE • GET_PURCHASE_INFORMATION • CONFIRM_NOTIFICATIONS • RESTORE_TRANSACTIONS
  • 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); }
  • 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. Request bundle protected 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. 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
  • 22. Asynchronous responses • Broadcast intents: • RESPONSE_CODE • IN_APP_NOTIFY • PURCHASE_STATE_CHANGED
  • 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);     }   }
  • 25. Check Billing Supported Parameters Shared Sync response keys RESPONSE_CODE RESULT_OK RESULT_BILLING_UNAVAILABLE Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR Async response RESPONSE_CODE
  • 27. Request Purchase Shared ITEM_ID Parameters ITEM_TYPE DEVELOPER_PAYLOAD RESPONSE_CODE Sync response keys PURCHASE_INTENT REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response IN_APP_NOTIFY
  • 28. Get Purchase Information Shared Parameters NONCE NOTIFY_IDS RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response PURCHASE_STATE_CHANGED
  • 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. 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
  • 32. Purchase states • Purchased (0) • Cancelled (1) • Refunded (2) • Expired (3): subscriptions only
  • 33. Confirm Notifications Shared Parameters NONCE NOTIFY_IDS RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR Async response RESPONSE_CODE
  • 34. Unsolicited In-app Notify • Purchase when app is running in various devices • Refunds • Subscription expired (?)
  • 37. Restore Transactions Basic Parameters NONCE RESPONSE_CODE Sync response keys REQUEST_ID RESULT_OK Response codes RESULT_ERROR RESULT_DEVELOPER_ERROR RESPONSE_CODE Async response PURCHASE_STATE_CHANGED
  • 38. Security Controls • Signed purchase data • In-app notify nonces
  • 39. Purchase State Changed Extras • inapp_signed_data: Signed JSON string (unencrypted) • inapp_signature: Use the Google Play public key to validate
  • 40.
  • 41. IAB limitations • No API for product details & price • To fully test you need to pay for real • Sometimes async messages are really async
  • 42. Obligatory image of Justin Bieber to wake you up
  • 43. Agenda • In-app Billing Overview • Google Play Billing Service • Android Billing Library • Security Best Practices
  • 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
  • 47. Overview • BillingController • IBillingObserver • BillingController.IConfiguration • ISignatureValidator
  • 49. 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); " " } " }
  • 50. Request Purchase BillingController.requestPurchase(this, productId); @Override public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) { BillingController.startPurchaseIntent(activity, purchaseIntent, null); } @Override public void onRequestPurchaseResponse(String itemId, ResponseCode response) { } @Override public void onPurchaseStateChanged(String itemId, Order order) { }
  • 51. Restore Transactions if (!mBillingObserver.isTransactionsRestored()) { BillingController.restoreTransactions(this); Toast.makeText(this, R.string.restoring_transactions, Toast.LENGTH_LONG).show(); } @Override public void onTransactionsRestored() { final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); final Editor editor = preferences.edit(); editor.putBoolean(KEY_TRANSACTIONS_RESTORED, true); editor.commit(); }
  • 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

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n