Thoughts about OpenIAB architecture

200 views
Skip to first unread message

Vassili Philippov

unread,
Apr 8, 2013, 1:52:55 PM4/8/13
to opf_o...@googlegroups.com
What do you think about the following approach to OpenIAB architecture:

* We create a service IOpenInAppBillingService which is as close to IInAppBillingService as possible, may be we even inherit it from IInAppBillingService. We may need to extend it to provide additional functionality like getting information about which store will handle our requests

* We take IabHelper and create a very similar class OpenIabHelper that encapsulates IOpenInAppBillingService instead of IInAppBillingService. It seems that minimum changes in IabHelper source code will be needed if we managed to create IOpenInAppBillingService very similar to IInAppBillingService

* May be it is even better to call our class IabHelper too, to reduce changes in game source code needed to migrate from Google Play IAB to OpenIAB. What do you think?

* Question: getBuyIntent returns result via async call of onActivityResult, should we just call onActivityResult from other listeners?

* We create a class implementing IOpenInAppBillingService interface that 
  a. Encapsulated a member with type IOpenInAppBillingServiceAdaptor - an interface representing in-app billing implementation for a particular store
  b. Detects which store was used to download this app
  c. Create corresponding adaptor
  d. Passes all the calls to the encapsulated IOpenInAppBillingServiceAdaptor

* Each store is represented by two classes:
  1. One lightweight class that could just detects if this store was used to download the app
  2. The second that extends IOpenInAppBillingServiceAdaptor and implements all in-app billing logic
  3. There are also listener classes that work as callbacks and marshal the results 

What do you think?

Best regards,
Vassili




Boris Minaev

unread,
Apr 10, 2013, 5:02:55 PM4/10/13
to Vassili Philippov, opf_o...@googlegroups.com
I don't really understand reasons to implement IOpenInAppBillingService. If we do so, we will need to implement in each marketAdaptor a lot of methods like this: http://pastebin.com/7zmW2UTW. I don't think writing such "low-level" code is very good. I think we should make a procedure of adding a new InAppAPI support as simple as we can.

So, I think we need to create OpenIabHelper class which has all public methods, which IabHelper has (and all interfaces). Plus method "getMarketDownloadedFrom" (do you know better name?). We also create an interface MarketAdaptor (better name?). It contains method "isDownloadFromThisMarket"/"isBillingSupported" and some methods from OpenIabHelper (e.g. we implement only async methods, only one method for "queryInventoryAsync", when OpenIabHelper has three copies of it, etc). For each market we need to implement class like "SamsungMaketAdaptor" which implements MarketAdaptor.

Now some thoughts about implementation... 

Each marketAdaptor encapsulates connection with a market. It returns results of working with market as we working with Google Play Market. E. g. SamsungMarketAdaptor in function "onPurchaseItemFinished" should create OpenIabResult and OpenPurchase (#) objects and execute listener (with these objects), which it saved when "launchPurchaseFlow" method was executed. Implementation of market adaptor can be divided into several classes, but it isn't very important.

# - I think it's much easier to create such objects and execute listener than sent data from service to application (in a way similar to code from pastebin.com above). Don't you agree?

About OpenIabHelper. In the constructor we create 4 (more?) Market Adaptors and trying to find the market, application was download from. In each method of this class we need to do something like that. If same method exists in MarketAdaptor interface, we just call currentMarket.methodName(...). Otherwise we call similar method in currentMarket, previously add some information (e. g. we have 3 methods queryInventoryAsync in OpenIabHelper, but only one in marketAdaptor).

About name of main class ("OpenIabHelper" or "IabHelper"). I think we should call it OpenIabHelper. It isn't very hard for developer to rename classname (just a few clicks in IDE). But in GoogleMarketAdaptor we will probably want to use IabHelper (by Google). If so, we will have in the project two different classes with same name (our IabHelper & IabHelper by Google) and that's not very good. 

Do you have any suggestions? Or maybe do you know some weak points in this architecture?

2013/4/8 Vassili Philippov <vassilip...@onepf.org>



--
Best regards, Boris Minaev

Vassili Philippov

unread,
Apr 11, 2013, 3:24:10 AM4/11/13
to opf_o...@googlegroups.com

 

First of all just to avoid misunderstanding I do not suggest making separate services for appstore adaptors. I just suggested to make adaptors as Java classes implementing interface which is very similar to IInAppBillingService interface.
 
>MarketAdaptor (better name?)
 
I think the interface name should just describe what it is doing. In our case it wraps In-App Billing interface of a particular appstore. So I suggest to call it IAppstoreInAppBillingAdaptor (from my point of view "appstore" is a better term then "market").
 
>If we do so, we will need to implement in each marketAdaptor a lot of method like this
 
What other methods we would need to implement? I agree with your general approach that we need to simplify interface of MarketAdaptor. Could you please write down what would be MarketAdaptor interface in your case? Just to compare here is how the adaptor interface could look like if we try to make it close to 
 
interface IAppstoreInAppBillingAdaptor {
    int isBillingSupported(int apiVersion, String packageName, String type);
    Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
    Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, String developerPayload);
    Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
    int consumePurchase(int apiVersion, String packageName, String purchaseToken);
}
 
> SamsungMarketAdaptor in function "onPurchaseItemFinished" should create
> OpenIabResult and OpenPurchase (#) objects and execute listener (with
> these objects), which it saved when "launchPurchaseFlow" method was executed.
> Implementation of market adaptor can be divided into several classes, but
> it isn't very important.
 
Will OpenIabResult and OpenPurchase be inherited from IabResult and Purchase? What is difference between OpenIabResult and IabResult? Why not just use IabResult?
 
> # - I think it's much easier to create such objects and execute listener
> than sent data from service to application (in a way similar to code from
> pastebin.com above). Don't you agree?
 
I do not suggest to create a service for each adaptor. I just advocated that adaptor has interface similar to IInAppBillingService rather than similar to IabHelper (for example to use JSON not Java classes for results).
 
> About OpenIabHelper. In the constructor we create 4 (more?) Market
> Adaptors
> and trying to find the market, application was download from. In each
> method of this class we need to do something like that. If same method
> exists in MarketAdaptor interface, we just call
> currentMarket.methodName(...). Otherwise we call similar method in
> currentMarket, previously add some information (e. g. we have 3
> methods queryInventoryAsync in OpenIabHelper, but only one in
> marketAdaptor).
 
May be creating all market adaptors even if they are not needed could be too big overhead (it will link big JAR files). I thought about creating additional "checker" classes that could just check if the application was downloaded from the corresponding store. Something like
 
interface IAppstoreInAppBillingChecker {
    boolean wasStoreUsedToInstall(String packageName);
}
 
class SamsungInAppBillingChecker implements IAppstoreInAppBillingChecker {
    ...    
}
 
....
 
 
> About name of main class ("OpenIabHelper" or "IabHelper"). I think we
> should call it OpenIabHelper. It isn't very hard for developer to rename
> classname (just a few clicks in IDE). But in GoogleMarketAdaptor we will
> probably want to use IabHelper (by Google). If so, we will have in the
> project two different classes with same name (our IabHelper & IabHelper by
> Google) and that's not very good.
 
Why do we need Google's IabHelper at all? Our IabHelper will include all needed code from IabHelper. So our IabHelper will just *replace* Google's IabHelper (Google's IabHelper is distributed under Apache 2 license so we have no problems just copy/paste code from it to our IabHelper).
 
> Do you have any suggestions? Or maybe do you know some weak points in this
> architecture?
 
Another small reason to make adaptor's interface close to IInAppBillingService rather than to IabHelper is that some developers (although I do not think that many) could work with IInAppBillingService directly. Using IabHelper is optional.
 
Best regards,
Vassili
 
============

Boris Minaev

unread,
Apr 11, 2013, 4:50:13 AM4/11/13
to Vassili Philippov, opf_o...@googlegroups.com
>> Using IabHelper is optional.
Is it really true? If we look for example in method "
launchPurchaseFlow" in IabHelpr we will see code "act.startIntentSenderForResult(pendingIntent.getIntentSender(),
                    requestCode, new Intent(),
                    Integer.valueOf(0), Integer.valueOf(0),
                    Integer.valueOf(0));"
As I understood, this code shows a window (what is correct word?) to a user, where user need to confirm a purchase. This code is strongly connected with Google Play Market and we don't need to execute it, when we work with other markets. There are also some things about security in IabHelper, which is different for different markets. So creating OpenIabHelper isn't just copy-paste all code from IabHelper. I don't think somebody uses GoogleIAB without IabHelper. Am I wrong?

>> May be creating all market adaptors even if they are not needed could be too big overhead (it will link big JAR files).
Yes, I agree. We can divide it, and create a part which "
check if the application was downloaded from the corresponding store".

>> 
I just advocated that adaptor has interface similar to IInAppBillingService rather than similar to IabHelper (for example to use JSON not Java classes for results).
Why do JSON better than Java classes?

>> 
Will OpenIabResult and OpenPurchase be inherited from IabResult and Purchase? What is difference between OpenIabResult and IabResult? Why not just use IabResult?
Ok, there are no difference, we can use IabResult and Purchase.

>> 
What other methods we would need to implement? I agree with your general approach that we need to simplify interface of MarketAdaptor. Could you please write down what would be MarketAdaptor interface in your case?
I don't understand what will methods return in your case? As I wrote above some methods returns intent, which is strongly connected to Google Market, what should other markets return in such methods?

In my case MarketAdapter have more methods:
  public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException;
  public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData);
  public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData);
  public boolean handleActivityResult(int requestCode, int resultCode, Intent data);
  public void queryInventoryAsync(final boolean querySkuDetails, final List<String> moreSkus, final QueryInventoryFinishedListener listener);
  public void consumeAsync(List<Purchase> purchases, OnConsumeMultiFinishedListener listener);

Maybe I forgot something...

>> I think the interface name should just describe what it is doing. In our case it wraps In-App Billing interface of a particular appstore. So I suggest to call it IAppstoreInAppBillingAdaptor (from my point of view "appstore" is a better term then "market").
Yes, maybe it's better name.



2013/4/11 Vassili Philippov <vassilip...@onepf.org>

Vassili Philippov

unread,
Apr 11, 2013, 5:33:30 AM4/11/13
to opf_o...@googlegroups.com

> Is it really true? If we look for example in method "launchPurchaseFlow" in
> IabHelpr we will see code 
> act.startIntentSenderForResult(pendingIntent.getIntentSender(),

I agree. You are right. May be IInAppBillingService interface is not abstract enough, like it hardcodes that purchase flow is divided in two parts where the second is opening intent handler.

Could you please write down your suggestion for appstore adaptor interface? Please try to make sure you include everything needed.

Best regards,
Vassili

Boris Minaev

unread,
Apr 11, 2013, 6:10:40 AM4/11/13
to Vassili Philippov, opf_o...@googlegroups.com
If we move "wasStoreUsedToInstall" to another interface, IAppstoreInAppBillingAdaptor will have such structure:

interface IAppstoreInAppBillingAdaptor {
  void startSetup(final OnIabSetupFinishedListener listener);
  void launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode, OnIabPurchaseFinishedListener listener, String extraData);
  boolean handleActivityResult(int requestCode, int resultCode, Intent data);
  Inventory queryInventory(boolean querySkuDetails, List<String> moreItemSkus, List<String> moreSubsSkus);
  void consume(Purchase itemInfo);
}

All other public methods of OpenIabHelper we can implement using this 5 methods (it will be very similar to IabHelper, e.g. you can see how async methods is implemented in IabHelper, they just create a new thread and start not async methods, so we can do the same).

I think I include everything we need. But if I forget about something, please, tell me.
 


2013/4/11 Vassili Philippov <vassilip...@onepf.org>

Vassili Philippov

unread,
Apr 11, 2013, 11:33:35 AM4/11/13
to opf_o...@googlegroups.com

We need at least a method that returns appstore name ;)

Let's start, could you please create interface and appstore classes in GitHub project for that?

 

Best regards,
Vassili

Vassili Philippov

unread,
Apr 11, 2013, 5:55:45 PM4/11/13
to opf_o...@googlegroups.com

Let's clone the current sample to a new folder like "life_openiab" and refactor it step-by-step from the current state until we extract all store-specific  code to store adaptors while keeping it working.

Best regards,
Vassili

>
>
> 2013/4/11 Vassili Philippov <vassilip...@onepf.org>

Vassili Philippov

unread,
Apr 12, 2013, 2:07:36 AM4/12/13
to opf_o...@googlegroups.com

Here is a public issue list tracker for Google IAB sample:

https://code.google.com/p/marketbilling/issues/list

I think it could be useful to check it to know better what kind of problems people have with IAP.

Best regards,
Vassili

Reply all
Reply to author
Forward
0 new messages