Android Tutorial Android In-App Billing v3 Tutorial

Discussion in 'Tutorials & Examples' started by Erel, Jun 6, 2013.

  1. Erel

    Erel Administrator Staff Member Licensed User

    This tutorial covers the new API for in-app billing provided by Google.

    The main differences between v3 and the previous version are:
    - (v3) Is easier to implement.
    - Supports managed products and subscriptions. Unmanaged products are not supported.
    - Includes a method to retrieve all purchased items. This means that you do not need to manage the items yourself.
    - Allows you to "consume" managed products. For example if the user has bought a game add-on and then used it, the app consumes the product allowing the user to purchase the add-on again.

    The official documentation is available here: In-app Billing Version 3 | Android Developers

    Implementing in-app billing in your application

    The first step is to upload a draft APK to Google developer console. Note that you should use a private signing key to sign the app.

    Under Services & APIs you will find your license key. This key is also required for in-app billing:

    [​IMG]

    You should also add at least one item to the "In-app Products" list. The item's type should be Managed Product or Subscription.

    Basic4android code

    The first step is to initialize a BillingManager3 object:
    Code:
    Sub Process_Globals
       
    Dim manager As BillingManager3
       
    Private key As String = "MIIBIjANBgkqhkiG9w0BAQEFAA..."
    End Sub

    Sub Globals


    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    If FirstTime Then
          manager.Initialize(
    "manager", key)
          manager.DebugLogging = 
    True
       
    End If
       ...
    End Sub

    Sub Manager_BillingSupported (Supported As Boolean, Message As String)
       
    Log(Supported & ", " & Message)
       
    Log("Subscriptions supported: " & manager.SubscriptionsSupported)
    End Sub
    The BillingSupported event will be raised with the result. Note that all of the billing related actions happen in the background and raise events when the action is completed.

    Calling manager.GetOwnedProducts will raise the OwnedProducts event. The OwnedProducts event includes a Map that holds the user current purchases. The keys in the map are the products ids (or Skus) and the values are objects of type Purchase. These objects include more information about the purchase and are required for other actions, such as consuming a purchase.

    Code:
    Sub manager_OwnedProducts (Success As Boolean, purchases As Map)
       
    Log(Success)
       
    If Success Then
          
    Log(purchases)
          
    For Each p As Purchase In purchases.Values
             
    Log(p.ProductId & ", Purchased? " & (p.PurchaseState = p.STATE_PURCHASED))
          
    Next
       
    End If
    End Sub
    Purchasing a product is done by calling: manager.RequestPayment. The user will be asked to approve the payment. The PurchaseCompleted event will be raised when the operation completes.

    Note that managed products can only be purchased once. Only after you call ConsumeProduct will the user be able to purchase the same item again.

    Consuming purchased products is done by calling manager.ConsumeProduct.
    For example:
    Code:
    If ownedProducts.ContainsKey("test2"Then
       manager.ConsumeProduct(ownedProducts.Get(
    "test2"))
    End If
    The ProductConsumed event will be raised.

    Tips
    - See this tutorial for more information about the possible testing options: Testing In-app Billing | Android Developers
    - If you get a "signature verification error" when trying to make a purchase then you should make sure that the licensing key is correct. If it is correct then try to upload a new APK.
    - It is recommended to use a process global variable to hold the key. This way it will be obfuscated when you compile in obfuscated mode.
    - Only one background request can run at a time.

    The library is available here:
    http://www.basic4ppc.com/forum/addi.../29998-app-billing-v3-library.html#post174139
     
    Last edited: Oct 16, 2014
    toby and DaOel like this.
  2. Dieter Baumgartner

    Dieter Baumgartner Member Licensed User

    Purchasecompleted Event

    Tried the new IN-APP API, because with the old one where problems mostly on Samsung SIII. Does anyone know how is the definition of the purchasecompleted - Event that is raised after the purchase.

    Sub manager_Purchasecompleted(gekauftedatei As String)

    says "signature does not match expected signature" ??
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    See this guide for the best way to build the events subs: IDE Tips

    The correct sub is:
    Code:
    Sub manager_PurchaseCompleted (Success As Boolean, Product As Purchase)
     
  4. Dieter Baumgartner

    Dieter Baumgartner Member Licensed User

    Thank you

    Thank you Erel, until now i really didn't know the trick to write
    Sub followed by a blank and then press the TAB- key.

    This is perfect support for event-definitions, great help
     
  5. Firpas

    Firpas Active Member Licensed User

    InAppBilling 3 - error

    Hi Erel:

    I am testing the InAppBilling 3 lib and i have the attached error.

    Do I need to specify any permission in the manifest as in the previous version?

    Thanks in advance
     

    Attached Files:

    Duey likes this.
  6. Erel

    Erel Administrator Staff Member Licensed User

    No.

    Have you uploaded your app to the developer console and added a product?
     
  7. Firpas

    Firpas Active Member Licensed User

    Yes, App is published and also the integrated products Monthly subscription (andestest1) and anual subscription (andestest3).

    See the attacched image
     

    Attached Files:

  8. Erel

    Erel Administrator Staff Member Licensed User

    Do you get the same error for non-subscription purchases?

    Have you checked Manager.SubscriptionsSupported value?
     
  9. Firpas

    Firpas Active Member Licensed User

    It is solved.
    The problem was that the published application worked with the previous version of InAppBilling. Once updated, the problem was solved.

    Thanks for your cooperation.
     
  10. holdemadvantage

    holdemadvantage Active Member Licensed User

    Super noob question :sign0104::sign0013:!!
    I have to make an app for a client with in-app subscription (annual fee) and obviously cash must go to him.
    Do i have to open a new developer account on google playstore registered to the client with his own payment info and publish app with his developer account?
     
  11. Erel

    Erel Administrator Staff Member Licensed User

  12. holdemadvantage

    holdemadvantage Active Member Licensed User

    So yes, i have to signup with a new developer account. Thanks Erel
     
  13. zjhi

    zjhi New Member Licensed User

    java.lang.NoSuchMethodError

    Hi!

    For some reason i can't get the InApp Billing to work. I got BillingManager3 set up OK, was able to query for owned products and show the checkout window for 'android.test.purchased' item. However, after the app resumed from the checkout window, manager_PurchaseComplete function was not executed, but instead the app crashed. Any idea what i'm doing wrong?

    Code:
    Code:
    Sub Activity_Create(FirstTime As Boolean)
       
    'Do not forget to load the layout file created with the visual designer. For example:
       'Activity.LoadLayout("Layout1")
       If FirstTime Then
          manager.Initialize(
    "manager", key)
       
    End If
       manager.DebugLogging = 
    True
    End Sub

    Sub Activity_Resume

    End Sub

    Sub Activity_Pause (UserClosed As Boolean)

    End Sub
    Sub manager_BillingSupported (Supported As Boolean, Message As String)
        
    Log(Supported & ", " & Message)
        
    Log("Subscriptions supported: " & manager.SubscriptionsSupported)
       
       manager.GetOwnedProducts
    End Sub

    Sub manager_OwnedProducts (Success As Boolean, purchases As Map)
       
    Dim result As Int
       
    Dim strFree As String
        
    Log("rivi 840: manager_OwnedProducts, "&Success)
        
    If Success Then
            
    Log(purchases)
            
    For Each pu As Purchase In purchases.Values
                
    Log(pu.ProductId & ", Purchased? " & (pu.PurchaseState = pu.STATE_PURCHASED))
             
    ' Jos maksettu
             If pu.ProductId = "vuosimaksu" AND pu.PurchaseState = pu.STATE_PURCHASED Then
                strFree = 
    "0"
             
    End If
            
    Next
        
    End If
       
    ' Poistaa kaikki faket
       If purchases.ContainsKey("android.test.purchased"Then
          
    Log("poistetaan tuote 'android.test.purchased'")
          
    'manager.ConsumeProduct(purchases.Get("android.test.purchased"))
       End If
       
       
    ' Ei maksettu
       If strFree <> "0" Then
          result = 
    Msgbox2("Sinulla on ohjelman ilmaisversio. Haluatko siirtyä ostamaan täysversion?"  , "Maksullinen versio" ,"Kyllä""""En" ,Null)
          
    If result = DialogResponse.Positive Then
             
    'vuosimaksu, subs
             
             manager.RequestPayment(
    "android.test.purchased","inapp","")
          
    End If
       
    End If
    End Sub
    Public Sub manager_PurchaseCompleted (Success As Boolean, Product As Purchase)
       
    End Sub

    Sub manager_ProductConsumed (Success As Boolean, Product As Purchase)
       
    Log("tuote kulutettu: "&Product.ProductId)
    End Sub
    Logcat output:

    Code:
    Starting async operation: launchPurchaseFlow
    Constructing buy 
    intent for android.test.purchased, item type: inapp
    requestCode = 
    1
    ** 
    Activity (main) Pause, UserClosed = false **
    sending message 
    to waiting queue (OnActivityResult)
    running waiting messages (
    1)
    Arrived: 
    11
    Ending async operation: launchPurchaseFlow
    Successful resultcode from 
    purchase activity.
    Purchase data: {"packageName":"b4a.example","orderId":"transactionId.android.test.purchased","productId":"android.test.purchased","developerPayload":"","purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:b4a.example:android.test.purchased"}
    Data signature: 
    Extras: Bundle[{INAPP_PURCHASE_DATA={"packageName":"b4a.example","orderId":"transactionId.android.test.purchased","productId":"android.test.purchased","developerPayload":"","purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:b4a.example:android.test.purchased"}, INAPP_DATA_SIGNATURE=, RESPONSE_CODE=0}]
    Expected item type: inapp
    main$ResumeMessagerun (B4A line: 43)
    End Sub

    GC_FOR_ALLOC freed 240K, 
    7% free 9169K/9768K, paused 21ms, total 21ms
    java.lang.NoSuchMethodError: anywheresoftware.b4a.BA.LogError
       at anywheresoftware.b4a.objects.IbHelper.logError(IbHelper.java:
    974)
       at anywheresoftware.b4a.objects.IbHelper.handleActivityResult(IbHelper.java:
    478)
       at anywheresoftware.b4a.objects.IbHelper$
    2.ResultArrived(IbHelper.java:379)
       at anywheresoftware.b4a.BA$
    4.run(BA.java:461)
       at anywheresoftware.b4a.BA.setActivityPaused(BA.java:
    373)
       at b4a.example.main$ResumeMessage.run(main.java:
    215)
       at android.os.Handler.handleCallback(Handler.java:
    725)
       at android.os.Handler.dispatchMessage(Handler.java:
    92)
       at android.os.Looper.loop(Looper.java:
    137)
       at android.app.ActivityThread.main(ActivityThread.java:
    5039)
       at java.lang.reflect.Method.invokeNative(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:
    511)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    793)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    560)
       at dalvik.system.NativeStart.main(Native Method)
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    This library requires Basic4android v2.7+.
     
  15. JOANORSKY

    JOANORSKY Member Licensed User

    Ok.. this is getting a little confusing for my head.. (big head here.. but most of it is hard skull :BangHead:)

    So... this is what i've done :

    • I've uploaded a draft apk
    • Made a inapp billing item
    • Attached it to the apk
    • etc etc
    • ...

    My app is a very simple application with just one design view. Basically it sells license codes for a specific hardware device. The application is supposed to request the costumer 3 fields of data.. and in order to process his request he must pay a one time fee (this means that if he want the license code.. he must pay for it). The license is then sent by email and "attached-for-internal-licenses-purposes" also to his email (this means.. that a user can have multiple licenses as long as each license is request to a different email - which is one of the requested data fields). So.. this means that i must be able to sell the item multiple times..

    The problem comes.. due to my lack of understanding on how i can get the purchased items in a variable or array of strings.. or map.. etc.. :BangHead:

    I understand that this will request it...
    PHP:
    If ownedProducts.ContainsKey("test2"Then 
        manager
    .ConsumeProduct(ownedProducts.Get("test2"))
    End If
    but.. what is "ownedProducts" ? Is this an object... ? Where is it declared? How can i get (manipulate) the items within this so called "ownedProducts"?

    :sign0148:

    These are mostly noob questions i suppose.. but.. something that would really.. realllyyy... reallly help.. would be a ready made example... a working one. Learning by example is still my favorite kinda way to do it.. :eek:

    I do manage to make my tablet ask for the license fee with the inapp billing... but i seen to be unable to go further.

    Any good-willing-charitable-fellow-soul is willing to post a full working example here?

    [​IMG]

    ... please?
    (eheh... really hope the puss-in-the-boots look works out.. eheheh)
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    If you want to immediately consume the purchased product then you need to handle the PurchaseCompleted event and call ConsumeProduct there.

    Are you familiar with the events autocomplete feature? If not then see the IDE Tips link in my signature.

    [​IMG]
     
  17. JOANORSKY

    JOANORSKY Member Licensed User

    Thanks Erel.. i guess that i am not familiar with it. I check that and get back to you after I take a look on it.

    (eheheh... that photo reminded my own cat today. It's so hot here these days that he finds the most strange positions to take a nap.. :D)
     
  18. JOANORSKY

    JOANORSKY Member Licensed User

    Humm... some of the tips i already knew.. and some i didn't. Still the billing issue is still not very clear to me. So if an example could be posted.. i would be thankful.

    As per my understanding.. the OwnedProducts is Map type variable that is filled with the manager.GetOwnedProducts calling code.. right? (this means that i must declare the OwnedProducts as a Map on the main application so that it can be filled in with the data coming from the manager.GetOwnedProducts.. correct?)

    I am receiving this error when i am testing the purchase with a testing account : Error in obtaining informations from th server. [RPC:S-7:AEC-0]

    Why is this error appearing?
     
  19. Erel

    Erel Administrator Staff Member Licensed User

    It is difficult to provide a full working example, as for an example to work it must be connected to a real Google account.

    In the first post there is an example of handling the OwnedProducts event. You can store the Map received in this event in a global variable and use it later.

    Though if you want to consume the purchase immediately then you should handle the PurchaseCompleted event.

    See this discussion about this error message: Google Groups
     
  20. JOANORSKY

    JOANORSKY Member Licensed User

    Ohh.. ok... i understand now. Thanks for your patience and willingness to help. I will give some feedback in a while after i done this successfully.

    About the RPC:S-7:AEC-0 Error Code.. this comes from the CC company which is unable to correctly authenticate with PlayStore. Inputing the card directly on the wallet or using another "standard" card will solve the issue.. (here is the info.. just in case someone else is having this issue as well)
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice