We're an independent design & development agency.
In-app billing
IVAN MARIĆ
Average people earn money doing things they don’t like. Rich people follow their passion.
- STEVE SIEBOLD
GOOGLE PLAY
MONETIZE
Premium - simple and convient
Freemium - durable and consumable digital goods
Subscription - continuing revenue stream
AdMob Ads - easy way to earn revenue
Total revenue by model
https://support.google.com/googleplay/android-developer/table/3539140?hl=en&rd=1
MERCHANT ACCOUNT
Google Play Developer Console - Financial reports
Not supported in all countries
IMPLEMENTATION
Sample project https://github.com/googlesamples/android-play-billing
Consumable good
SubscriptionDurable good
ADD AIDL FILE
IInAppBillingService.aidl
<sdk>/extras/google/play_billing/
src/main/aidl/com.android.vending.billing
IInAppBillingService.java
ANDROID MANIFEST
<uses-permission android:name="com.android.vending.BILLING" />
Upload to Alpha/Beta channel
Intent serviceIntent = new Intent( “com.android.vending.billing.InAppBillingService.BIND"); serviceIntent.setPackage(“com.android.vending”); context.bindService(serviceIntent,
serviceConnection, Context.BIND_AUTO_CREATE);
context.unbindService(serviceConnection);
Service connection
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { billingService = IInAppBillingService.Stub.asInterface(service); int r = billingService.isBillingSupported(3, packageName, itemType); if (r == 0) { // Billing supported return; } }};
Service connection
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { billingService = IInAppBillingService.Stub.asInterface(service); int r = billingService.isBillingSupported(3, packageName, "inapp"); if (r == 0) { // Billing supported return; } }};
Service connection
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { billingService = IInAppBillingService.Stub.asInterface(service); int r = billingService.isBillingSupported(5, packageName, "subs"); if (r == 0) { // Billing supported return; } }};
Service connection
Response
GET DETAILS
Information about the item
Localised
Items are immutable
// Split the sku list in blocks of no more than 20 elements. Bundle querySkus = new Bundle(); querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList);
Bundle skuDetails = billingService.getSkuDetails( 3, packageName, itemType, querySkus);
Bundle skuDetails = billingService.getSkuDetails( 3, packageName, itemType, querySkus);
GET PURCHASES
User owned items
Use for restore
Bundle ownedItems = billingService.getPurchases( 3, packageName, itemType, continueToken);
BUY INTENT
Get PendingIntent to launch the purchase flow
Purchase flow is handle by Google Play
Response for purchase order received in onActivityResult
Bundle buyIntent = billingService.getBuyIntent( 3, packageName, sku, itemType, payload);
PendingIntent intent = buyIntent.getParcelable("BUY_INTENT"); activity.startIntentSenderForResult(intent.getIntentSender(), requestCode, new Intent(), 0, 0, 0);
Bundle buyIntent = billingService.getBuyIntentToReplaceSkus( 5, packageName, oldSku, sku, "subs", payload);
PendingIntent intent = buyIntent.getParcelable("BUY_INTENT"); activity.startIntentSenderForResult(intent.getIntentSender(), requestCode, new Intent(), 0, 0, 0);
Subscription upgrade/downgrade
CONSUME ITEM
Purchased item is owned by the user forever
Can not purchase an item more than once
Remove item from the owner to purchase again
// Don’t call this on UI thread billingService.consumePurchase(3, packageName, token);
TESTING
STATIC TEST
Used for testing response models
Verify signatures
android.test.purchased, android.test.canceled,
android.test.refunded, android.test.item_unavailable
REAL TEST
Setup test accounts in Google Developer Console
Real purchase without money transaction
All subscriptions last one day
Missing orderId property
SECURITY
SIGNED RESPONSES
Verify purchase JSON response
Licence key as public key portion
Best practice to do this on a server side
GOOGLE PLAY DEVELOPER API
Use www.googleapis.com for checking purchase status
Manage subscriptions
https://www.reddit.com/r/Piracy/comments/3eo8sj/antipiracy_measures_on_android_custom_roms/
HACKER APPS
Rooted devices
Change the behaviour of the system and apps
PROTECT YOUR CONTENT
Do not provide content with .apk
Encrypt content with device specific key
Recoverable data
DOCUMENTATION
http://developer.android.com/google/play/billing/index.html
GOOGLE SERVICE
Overview
Version 3 API
Security and Design
Testing In-app Billing
Administering In-app Billing
http://developer.android.com/training/in-app-billing/index.html
TRAINING
Preparing Your App
Establishing Products for Sale
Purchasing Products
Testing Your App
WATCH OUT FOR
Developer payload
Calling consume request on Main thread
Subscription downgrade/upgrade (v3 / v5)
AIDL file (https://github.com/googlesamples/android-play-billing/issues/3)
Limitations http://stackoverflow.com/questions/13717091/android-error-while-
retrieving-information-from-server-rpcs-5aec-0-in-google
HTTP://BLOG.GOFORYT.COM/VALIDATING-ANDROID-APP-PURCHASES-LARAVEL/
Any questions? [email protected] IVAN MARIĆ
Visit infinum.co or find us on social networks:
infinum.co infinumco infinumco infinum