Android Tutorial Android In-app Billing tutorial

For new projects it is recommended to use the more recent API (v3): http://www.b4x.com/forum/basic4andr...ls/29997-android-app-billing-v3-tutorial.html

Android market provides an in-app billing service which you can use to accept payments from your own application.

The code required to use this service is quite simple. However the actual process that is done in the background is pretty complicated. To better understand it you should read the official documentation: In-app Billing | Android Developers

This tutorial will cover the main concepts and the steps required to integrate in-app billing in your Basic4android project.

The billing service allows the user to purchase "products". Products are declared in the Android market developer console.
There are two types of products: managed and unmanaged products.

Differences between managed and unmanaged products:
- The user can only purchase a managed products once.
- You can later restore all the managed transactions.

For example, access to premium features should be a managed product.
Coins, potions and other "temporary" assets should be unmanaged products.

Developer console:

SS-2012-02-02_10.32.07.png


SS-2012-02-02_10.31.41.png


Basic4android code
The InAppBilling library includes one type of object which is BillingManager.
The BillingManager should belong to a Service module.

Typical code should look like:
B4X:
'Service module
Sub Process_Globals
   Dim Manager As BillingManager
   Dim PublicKey As String
   PublicKey = "xxxx" 'From the developer console
End Sub

Sub Service_Create
   Manager.Initialize("manager", PublicKey)
End Sub

Sub Service_Start (StartingIntent As Intent)
   Manager.HandleIntent(StartingIntent)
End Sub

Sub Manager_BillingSupported (Supported As Boolean)
   Log("BillingSupported: " & Supported)
End Sub

Sub Manager_PurchaseStateChange (PurchaseState As Int, ProductIdAs String, OrderId As String, PurchaseTime As Long, ExtraData As String)
   Log("PurchaseStateChange: " & PurchaseState & ", " & ProductId& ", " & OrderId & ", " & DateTime.Time(PurchaseTime) & ", " & ExtraData)
   If PurchaseState = Manager.PURCHASE_STATE_PURCHASED Then
      'Here you should store the purchase information
      'and then notify the activity about the purchase.
      'In most cases the activity will be running at this state. However it is possible that it will be paused.
      'In that case the following call will be ignored.
      CallSub2(Main, "ThankYouForPurchasing", ProductId)
   End If
End Sub

Sub Service_Destroy
   Manager.UnbindMarketService
End Sub
PublicKey is your developer public key as appears in the developer console under Edit Profile.
This string should be set in Process_Globals sub to allow it to be obfuscated.

The BillingManager is initialized in Service_Create. BillingManager processes the intents that are sent to the service (through the internal receiver).

BillingManager provides two events:
BillingSupported - This event is raised after initializing the manager. The parameter will tell you whether billing is supported. Note that the emulator doesn't support billing.

PurchaseStateChange - This event is raised when a product is purchased, refunded or cancelled.
PurchaseState will be one of the following values: PURCHASE_STATE_PURCHASED, PURCHASE_STATE_CANCELED, PURCHASE_STATE_REFUNDED or PURCHASE_STATE_NODATA.
ExtraData is an arbitrary string that you can send together with the purchase request.

When the service is destroyed you should call UnbindMarketService to free resources.

Activity code
B4X:
Sub Activity_Create(FirstTime As Boolean)
   If IsPaused(InAppBillingService) Then StartService(InAppBillingService)
   Activity.LoadLayout("1")
End Sub

Sub Button1_Click
   InAppBillingService.Manager.RequestPayment(Activity, "unmanaged_1", "extra data")
End Sub

Sub ThankYouForPurchasing (Product As String)
   Msgbox("Thank you for purchasing: " & Product, "")
End Sub

When the activity is created we start the service if necessary.
The following code sends a purchase request to the market for a product:
B4X:
'InAppBillingService is the name of the Service.
InAppBillingService.Manager.RequestPayment(Activity, "unmanaged_1", "extra data")

RestoreTransactions
Managed products are tracked by the market. It is possible to retrieve previous purchases of such products.
For example if the user has uninstalled the application and now installs it again, you can call RestoreTransactions to retrieve the previous products.

According to Google documentation you should not call RestoreTransactions each time your application starts.

When you call RestoreTransactions the PurchaseStateChange event will be raised for each purchase. If there are no previous transaction then PurchaseStateChange will be raised and PurchaseState parameter value will be PURCHASE_STATE_NODATA.

Manifest editor
The following code should be added to the manifest editor code (change InAppBillingService to your service name):
B4X:
'InAppBilling declarations - Start
AddReceiverText(InAppBillingService,  <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>)
'InAppBilling declarations - End

Testing your application

It is not so simple to test the payment process. A device set to the same account as the merchant account cannot be used, as you are not allowed to purchase from yourself.

From my experience this is the easiest way to test your application:
- Upload a draft application to the market. You do not need to publish it.
- Set some low cost ($0.01) products.
- Use a device with an account other than the merchant account.
- Add this account as a test account. This is done under Edit Profile page.
The account must be a gmail.com account.

You will now be able to develop and debug with this device. If you like you can also cancel the orders from the merchant console.

You may need to first publish the application and then unpublish it.
The application must be signed with the same signature and have the same version number as the uploaded one.

Tips
- Track the logs.
- When you cancel an order the purchase state will be PURCHASE_STATE_CANCEL. When you partially refund it the state will be PURCHASE_STATE_REFUND.

The library is available here: http://www.b4x.com/forum/additional...oid-market-app-billing-service.html#post82746
 

flyingbag

Member
Licensed User
Longtime User
One workaround to add subscription is as follows:

-Store the user's app install date in a database on your own server
-Your server can check when a certain time frame is done (such as a week or a month or whatever.
-Then you prompt an "In App Billing" for a "Managed" or "Unmanaged Product" that allows usage for "X" number of days
- The in-app billing library can be used as is for the above step
-Update your Database accordingly with new end date
- Use the server and database to check and repeat at your desired subscription interval

I have an app that uses the above workaround and is working fine

I could do a donation aswell, since a project that's 90+% finished will get cancelled if I can't add the subscription stuff (they requested it when it was already at this stage tho, so lesson learned... next time they can put it all on paper and if stuff change I can still decide if I want to add it or not and for what price)
 

flyingbag

Member
Licensed User
Longtime User
Hi Erel,
With the in-APP billing version 3 API
In-app Billing Overview | Android Developers there is a mention as follows:

Migration Considerations
If you have an existing In-app Billing implementation that uses Version 2 or earlier, it is strongly recommended that you migrate to In-app Billing Version 3 at your earliest convenience.

If you have published apps selling in-app products, note that:

Managed items and subscriptions that you have previously defined in the Developer Console will work with Version 3 as before.
Unmanaged items that you have defined for existing applications will be treated as managed products if you make a purchase request for these items using the Version 3 API. You do not need to create a new product entry in Developer Console for these items, and you can use the same product IDs to purchase these items. They will still continue to be treated as unmanaged items if you make a purchase request for them using the Version 2 or earlier API.

Question: I am currently using your in-app library for managing in-app purchases. Is this change something we should be worried about ?
 

jdiperla

Member
Licensed User
Longtime User
Is there an example project of how to use this flying around somewhere?

I would love to see how it would work in action with some 1 cent items to mess with.
 

NJDude

Expert
Licensed User
Longtime User
If you want to test without "paying" then change this line on the Main Activity:

From:
B4X:
InAppBillingService.Manager.RequestPayment(Activity, "unmanaged_1", "extra data")
To:
B4X:
InAppBilling.Manager.RequestPayment(Activity, "android.test.purchased", "extra data")
I'm assuming you already followed the steps on the tutorial.
 

Inman

Well-Known Member
Licensed User
Longtime User
According to Google documentation you should not call RestoreTransactions each time your application starts.

According to In-app API version 3, Google has implemented caching.

Because the Google Play client now caches In-app Billing information locally on the device, you can use the Version 3 API to query for this information more frequently, for example through a getPurchases call. Unlike with previous versions of the API, many Version 3 API calls will be serviced through cache lookups instead of through a network connection to Google Play, which significantly speeds up the API's response time.

Does that mean it is ok to call RestorePurchases each time the app starts?
 

Inman

Well-Known Member
Licensed User
Longtime User
Alright cool! I will cache the results myself with the current library.
 

ashrafidkaidek

Member
Licensed User
Longtime User
Sorry for the stupid question, but Erel mentioned “PublicKey is your developer public key as appears in the developer console under Edit Profile.”

It seems that Google has changed developer account user interface! Because I can’t find my developer PublicKey, even there is no “Edit Profile” option! Any idea how should I find my developer PublicKey?

Thank you
 

Inman

Well-Known Member
Licensed User
Longtime User
Sorry for the stupid question, but Erel mentioned “PublicKey is your developer public key as appears in the developer console under Edit Profile.”

It seems that Google has changed developer account user interface! Because I can’t find my developer PublicKey, even there is no “Edit Profile” option! Any idea how should I find my developer PublicKey?

Thank you

The PublicKey has been moved to Services & APIs page of an app. Checkout this page:

https://support.google.com/googleplay/android-developer/answer/186113?hl=en
 

ashrafidkaidek

Member
Licensed User
Longtime User
I have followed Erel original recommendations to test in app billing, so I have 100% new device with totally different Gmail account than my developer account, I have bridge this device to basic4android and installed my app in it, then directly built the apk and uploaded it to my Google developer account, and created the only managed service that my app has, then added the required app description / art work ... etc

Also I have added the test account to my “License Testing” list, under Account Details, and picked “Licensed” from License Test Response drop-box.

Now when I try to run the app and request to purchase the “managed service” I’m getting the error below:
“Signature does not match expected signature”
The above error show when "Manager_PurchaseStateChange" event is raised.

Erel also mentioned “The application must be signed with the same signature and have the same version number as the uploaded one.”

So can somebody please direct me on how to check and correct this signature issue!

Thank you all
 
Last edited:

ashrafidkaidek

Member
Licensed User
Longtime User
Yes Erel, i have created a new Signing key before building the apk and before installing the app in the new device, so both has exactly the same signing key.

I have even published the app then installed it to the device directly from the store, and got the same error! This does not make science to me … any ideas …
 
Last edited:
Top