In-App Billing within APK via Buildozer

242 views
Skip to first unread message

Horace Johnson

unread,
Dec 3, 2016, 9:29:35 PM12/3/16
to Kivy users support
"Sup!" everyone!

Assuming in-app billing is going to be confusing and hard, I started researching it early (no avail).  I understand Google has a v2 and v3 in-app billing methods.  Looking at the files that are produced by buildozer, it seems like v2 is implemented (or is it?).  Instead of IInAppBillingService.aidl, buildozer creates a(n) IMarketBillingService.aidl.

There's a "Helper" class file associated with the v3 process but none within buildozer files.

My question(s) is(are), if billing is already made available my buildozer, how would I invoke it within my main.py?  How can I add my 'public key' to 'security'?  The whole thing seems so confusing.

Horace Johnson

unread,
Dec 4, 2016, 2:22:25 AM12/4/16
to Kivy users support
Looks like jnius is used for handling java types.  Ok...found that out....

Alexander Taylor

unread,
Dec 4, 2016, 10:40:20 AM12/4/16
to Kivy users support
As far as I'm aware, the billing stuff in the old pygame bootstrap should be considered deprecated and not used.

To use billing, you probaly have to dig into the code to understand how and where to add the java stuff for it to work. I'm pretty sure people have done this, but I don't know if anyone has written it up. It may not ultimately be that complicated, but I don't know what changes it needs.

Horace Johnson

unread,
Dec 4, 2016, 2:08:31 PM12/4/16
to Kivy users support
Are java functions callable within the main.py amongst python code or do I have to import another module used for calling java functions?  PythonActivity is looks like the equivalent of MainActivity in tutorials by Google.



 billingServiceStart() {
        mActivity.billingServiceStart_();
    }

     billingServiceStop() {
        mActivity.billingServiceStop_();
    }

     billingBuy(String sku) {
        mActivity.billingBuy_(sku);
    }

     billingGetPurchasedItems() {
        return mActivity.billingGetPurchasedItems_();
    }

     billingGetPendingMessage() {
        if (mActivity.mBillingQueue.isEmpty())
            return null;
        return mActivity.mBillingQueue.remove(0);
    }

Horace Johnson

unread,
Dec 4, 2016, 9:41:58 PM12/4/16
to Kivy users support
from jnius import autoclass

PythonActivity = autoclass('org.renpy.android.PythonActivity')
PythonActivity.billingServiceStart()

??

Horace Johnson

unread,
Dec 5, 2016, 12:17:38 AM12/5/16
to Kivy users support
That's strange...  I did a print test within a test apk just to see if I can identify a PythonActivity method.

EE = open('PAclass.txt', 'w')
EE.write(str(self.PythonActivity.mActivity.billingServiceStart))
EE.close()

This raised an exception stating the class attribute 'billingServiceStart' did not exists.  In PythonActivity, billingServiceStart is a method that calls billingServiceStart_.

I did the same test using 'billingServiceStart_' and that method was identified (no errors).  Can someone explain to me why one method was identified and the other was not?

Horace Johnson

unread,
Dec 5, 2016, 4:17:37 AM12/5/16
to Kivy users support
KK = self.PythonActivity.mActivity.billingServiceStart_()
      
GetQMess = self.PythonActivity.mActivity.mBillingQueue
        try:
            FstMess = self.PythonActivity.mActivity.mBillingQueue.get(0)
            Evx = open('getmessageq.txt', 'w')
            Evx.write(str(FstMess))
            Evx.close()
        except:
            pass

FstMess returned, billingSupported | inapp | 1

Well at least I'm figuring out auto class a little but I know this can't be right.  For starters, I just wanted to see if the Queue would return anything and didn't bother decompiling the apk to add the following to manifest...

<uses-permission android:name="com.android.vending.BILLING" />

Without that, how could billingServiceStart_ return True?

Another thing, is everything suppose to be done completely silent in the background and the only way you know what's going on is to access some database of returned messages?

Horace Johnson

unread,
Dec 5, 2016, 10:56:50 PM12/5/16
to Kivy users support
How can I view the Log that's being added to in PythonActivity (Log.w(TAG, .......)?  I would like to write it out to a file if possible.  

Horace Johnson

unread,
Dec 9, 2016, 3:10:49 PM12/9/16
to Kivy users support
I got In-App Billing working.  It was a long road, going through p4a and back but I found the missing piece.

Added public key:
--with-billing $BILLING_PUBKEY
export BILLING_PUBKEY="billing key added to the bashrc file"

Then I used apktool to decompile the apk and modify the manifest (because I don't know of any other way to modify the manifest before buildozer build).
<uses-permission android:name="com.android.vending.BILLING" />

Recompiled the apk and signed/zaligned it.

During the install, I can now see, Network Communications Billing as a permission.  (great!)

Inside main.py I imported the mods as...
from android.billing import BillingService   (not android_billing!)

Here's the thing...  I don't think this code posted online is going to work.

=====================================================

Export your public key:

export BILLING_PUBKEY="Your public key here"
Setup some In-App product to buy. Let's say you've created a product with the id "org.kivy.gopremium"

In your application, you can use the billing module like this:

from android_billing import BillingService
from kivy.clock import Clock

class MyBillingService(object):

    def __init__(self):
        super(MyBillingService, self).__init__()

        # Start the billing service, and attach our callback
        self.service = BillingService(billing_callback)

        # Start a clock to check billing service message every seconds
        Clock.schedule_interval(self.service.check, 1)

    def billing_callback(self, action, *largs):
        '''Callback that will receive all the event from the Billing service
        '''
        if action == BillingService.BILLING_ACTION_ITEMSCHANGED:
            items = largs[0]
            if 'org.kivy.gopremium' in items:
                print 'Congratulation, you have a premium acess'
            else:
                print 'Unfortunately, you dont have premium access'

    def buy(self, sku):
        # Method to buy something.
        self.service.buy(sku)

    def get_purchased_items(self):
        # Return all the items purchased
        return self.service.get_purchased_items()
To initiate a in-app purchase, just call the buy method:

# Note: start the service at the start, and never twice!
bs = MyBillingService()
bs.buy('org.kivy.gopremium')

# Later, when you get the notification that items have been changed, you
# can still check all the items you bought:
print bs.get_purchased_items()
{'org.kivy.gopremium': {'qt: 1}}
You'll receive all the notification about the billing process in the callback.

Last step, create your application with --with-billing $BILLING_PUBKEY:

./build.py ... --with-billing $BILLING_PUBKEY

======================================================


Reason I think it won't work is because this code is calling "buy" to buy an item.  When looking inside the billing modules buildozer creates, there is no buy method for BillingService but there is a RequestPurchase method which takes three arguments I believe.  One being the item, one being the payload and I forgot the third argument.

Any thoughts/suggestions/code?


kded...@gmail.com

unread,
Jun 8, 2017, 9:24:32 AM6/8/17
to Kivy users support
Thanks a lot, man!

I'm trying to implement your solution and have an issue

I use buildozer and after I added export to my bashrc file:

export BILLING_PUBKEY="my pubkey"

I ran the following command in terminal

buildozer --with-billing $BILLING_PUBKEY android release

But buildozer fails with "Unknown command/target MIIBIj...(my pubkey)"

Do you know any solution to this?

Have you used p4a in your final solution?

Thank you in advance!

Horace Johnson

unread,
Jun 8, 2017, 9:14:55 PM6/8/17
to Kivy users support
Buildozer only supports the old in-app billing which is dead now.  Only in-app billing 3 is relevant.  You could try adding an in-app billing 3 set-up to your project root and import everything from there (although I doubt that it’ll work).

What I suggest is, create two versions of your app.  One version that’s free to play but with ads and another version that’s “paid”, without ads.  You may choose to have more features in the “paid” version of your app also but be careful not to give any advantages of free players versus “paid” players.

I’m assuming you’re making a game app, if not, two versions is still the best way to go building with Buildozer.

I would consider kivy a start for python programmers but if you have success with your first few apps and earn revenue, I would suggest moving on to something else like Unity, learn Java and C++.

chavarinbonbyn

unread,
Feb 24, 2020, 10:47:27 PM2/24/20
to Kivy users support
Hi Horace Johnson,

It's been a while since this issue was published, do you know if the current version of buildozer (V1.0) supports requested Google's in-app billing ?

Thanks in advance.

Surbhi Shrivastava

unread,
Apr 6, 2020, 1:27:40 PM4/6/20
to Kivy users support
hello 
hope you doing well
I am having one application in which I was using kivy buildozer for building but I am bit confuse of integrating inapp purchase for it can you guide me how can i run --with-billing with buildozer command 

Thanks and Regards
Surbhi S
Reply all
Reply to author
Forward
This conversation is locked
You cannot reply and perform actions on locked conversations.
0 new messages