Android Question Problem in GooglePlayBilling with subscriptions when call LaunchBillingFlow

Mr.Coder

Member
Licensed User
Longtime User
Hi,

Problem in GooglePlayBilling with subscriptions when call LaunchBillingFlowthe Billing_PurchasesUpdated event called two times in log there is two of this "sending message to waiting queue (billing_purchasesupdated)" and when I click on the subscription button and after the subscription information window disappears this "running waiting messages (2)" appears in the log the event is called twice, causing a fatal error when the event is called for the second time.

B4X:
Logger connected to:  HUAWEI INE-LX1
--------- beginning of main
--------- beginning of system
*** Receiver (httputils2service) Receive (first time) ***
(Http client initialized with accept all option.)
Panel size is unknown. Layout may not be loaded correctly.
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (billing_purchasesupdated)
sending message to waiting queue (billing_purchasesupdated)
running waiting messages (2)
main$ResumeMessagerun (java line: 340)
java.lang.Exception: Sub billing_purchasesupdated was not found.
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:227)
    at anywheresoftware.b4a.BA$2.run(BA.java:395)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:467)
    at com.moderndigitals.fakegps.main$ResumeMessage.run(main.java:340)
    at android.os.Handler.handleCallback(Handler.java:907)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7625)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
java.lang.Exception: Sub billing_purchasesupdated was not found.
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **

The code I use :

B4X:
                 Dim Offers As List = SkuDetails.Get(0).As(JavaObject).RunMethod("getSubscriptionOfferDetails", Null)
                 Dim Offer As JavaObject = Offers.Get(0)
                 Dim OfferToken As String = Offer.RunMethod("getOfferToken", Null)

                 Dim lResult As BillingResult = LaunchBillingFlow2(Billing, SkuDetails.Get(0), OfferToken)

B4X:
Private Sub LaunchBillingFlow2 (Client As BillingClient, Sku As SkuDetails, OfferToken As String) As BillingResult

    Try
  
        Dim oContext As JavaObject
        Dim JustForError As BillingResult
        Dim ProductDetailsParamsBuilder As JavaObject
        Dim ProductDetails As List
        Dim BillingFlowParamsBuilder As JavaObject
      
        oContext.InitializeContext
      
        ProductDetailsParamsBuilder = ProductDetailsParamsBuilder.InitializeStatic("com.android.billingclient.api.BillingFlowParams.ProductDetailsParams").RunMethod("newBuilder", Null)
        ProductDetailsParamsBuilder.RunMethod("setProductDetails", Array(Sku))
        ProductDetailsParamsBuilder.RunMethod("setOfferToken", Array(OfferToken))
        ProductDetails = Array(ProductDetailsParamsBuilder.RunMethod("build", Null))
              
        BillingFlowParamsBuilder = BillingFlowParamsBuilder.InitializeStatic("com.android.billingclient.api.BillingFlowParams").RunMethod("newBuilder", Null)
        BillingFlowParamsBuilder.RunMethod("setProductDetailsParamsList", Array(ProductDetails))
      
        Return Client.As(JavaObject).GetFieldJO("client").RunMethod("launchBillingFlow", Array(oContext, BillingFlowParamsBuilder.RunMethod("build", Null)))

    Catch
      
        Log(LastException)
      
        Return JustForError
      
    End Try
  
End Sub

I have tried these versions v7.01 and v7.02 and v8.00 from the GooglePlayBilling library and the same problem and fatal error occurs in all of them, I don't know what the problem is, thank you.
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Do you add the script in manifest editor?
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
Try remove the try-catch.
Use the original code provided by Erel here.
 
Upvote 0

Mr.Coder

Member
Licensed User
Longtime User
I removed it and used the sub as is, the same problem and the same error appears, but I noticed that the error appears because I use the BillingClient in class, and in class I call this Billing.ConnectIfNeeded and in Billing_Connected event I use Billing.QueryPurchases("subs") for querying about subscriptions every specific period, then I check their expiration date on my website server, and when I canceled the use of the class completely, the repeating of calling the "sending message to waiting queue (billing_purchasesupdated)" event disappears, and the error disappears. The problem was from the class but why billing_purchasesupdated event called when I use this LaunchBillingFlow from main module!.
 
Upvote 0

Mr.Coder

Member
Licensed User
Longtime User
Thank you aeric for your help, I solved the problem when I use BillingClient in a class and also use it in Main module by using inline java inside the class. Here is the class code in case anyone needs it :

B4X:
#Event: Done


Sub Class_Globals
    
    Private mCallback As Object
    Private mEventName As String
    Private oBillingClient As JavaObject
    Private lSubscriptionID As String = "TheSubscriptionIDHere"
 
End Sub


Public Sub Initialize (Callback As Object, EventName As String)
 
    mCallback = Callback
    mEventName = EventName

    Dim oContext As JavaObject
    oContext.InitializeContext
    oBillingClient.InitializeNewInstance("<Your App PackageName Here>.<Your Class Name Here>.BillingManager", Array(oContext, Me))
 
End Sub


Public Sub StartCheckingSubscriptionValidity
 
    Try
    
        oBillingClient.RunMethod("connectIfNeeded", Null)
    
        Return
    
    Catch
    
        Log(LastException)
    
        RaiseDone
    
    End Try
 
End Sub


Private Sub VerifySubscriptionOnServer (Purchase As Purchase) As ResumableSub
 
    Try
              
          'Verifying the subscription
      
        Return 1
    
    Catch
    
        Log(LastException)
    
        Return -1
    
    End Try
    
End Sub


Private Sub BillingManager_Connected (Result As BillingResult)
 
    Try
    
        Dim VerifyingResult As Int
    
        If Result.IsSuccess Then
      
           oBillingClient.RunMethod("queryPurchases", Array("subs"))
      
           Wait For BillingManager_PurchasesQueryCompleted (Result As BillingResult, Purchases As List)
      
           Log("Cls Result.IsSuccess=" & Result.IsSuccess)
              
           If Result.IsSuccess Then
          
              Log("Cls Purchases.Size=" & Purchases.Size)
          
              For Each Purchase As Purchase In Purchases

                  If Purchase.Sku = lSubscriptionID And Purchase.PurchaseState = Purchase.STATE_PURCHASED Then
              
                     Log("Cls Purchase.OrderId=" & Purchase.OrderId)
                     Log("Cls Purchase.OriginalJson=" & Purchase.OriginalJson)
                     Log("Cls Purchase.PurchaseState=" & Purchase.PurchaseState)
                     Log("Cls Purchase.PurchaseTime=" & Purchase.PurchaseTime)
                     Log("Cls Purchase.PurchaseToken=" & Purchase.PurchaseToken)
                     Log("Cls Purchase.Signature=" & Purchase.Signature)
                     Log("Cls Purchase.Sku=" & Purchase.Sku)
                     Log("Cls Purchase.IsAcknowledged=" & Purchase.IsAcknowledged)
                     Log("Cls Purchase.IsAutoRenewing=" & Purchase.IsAutoRenewing)                 
            
                      Wait For (VerifySubscriptionOnServer(Purchase)) Complete (VTS As Int)
                
                     VerifyingResult = VTS
                
                     Exit                   
                
                  End If
            
              Next                                                   
                                  
           End If
                                            
        End If
    
        If VerifyingResult = 1 Then
           'Verifying OK
        End If
    
        RaiseDone
          
        Return
      
    Catch
    
        Log(LastException)
    
        RaiseDone
    
        Return
    
    End Try
    
End Sub


Private Sub RaiseDone
    If SubExists(mCallback, mEventName & "_Done") Then
       CallSub(mCallback, mEventName & "_Done")
    End If
End Sub


#If Java

    import com.android.billingclient.api.AcknowledgePurchaseParams;
    import com.android.billingclient.api.BillingClient;
    import com.android.billingclient.api.BillingClientStateListener;
    import com.android.billingclient.api.BillingFlowParams;
    import com.android.billingclient.api.BillingResult;
    import com.android.billingclient.api.ConsumeParams;
    import com.android.billingclient.api.PendingPurchasesParams;
    import com.android.billingclient.api.ProductDetails;
    import com.android.billingclient.api.ProductDetailsResponseListener;
    import com.android.billingclient.api.Purchase;
    import com.android.billingclient.api.PurchasesUpdatedListener;
    import com.android.billingclient.api.QueryProductDetailsParams;
    import com.android.billingclient.api.QueryPurchasesParams;
    import com.android.billingclient.api.QueryProductDetailsResult;
 
    import anywheresoftware.b4a.objects.BillingClientWrapper.*;
    import anywheresoftware.b4a.AbsObjectWrapper;

    import androidx.annotation.NonNull;
    import android.app.Activity;
    
    import java.util.ArrayList;
    import java.util.List;

    public static class BillingManager implements PurchasesUpdatedListener {

        private BillingClient billingClient;
        private Activity activity;
        private B4AClass target;

        /* ================= CONSTRUCTOR ================= */
    
        public BillingManager(Activity activity, B4AClass target) {
            this.activity = activity;
            this.target = target;
            initializeBilling();
        }
    
        /* ================= INIT ================= */

        public void initializeBilling() {
        
            PendingPurchasesParams pendingParams =
                    PendingPurchasesParams.newBuilder()
                            .enableOneTimeProducts()
                            .build();

            billingClient = BillingClient.newBuilder(activity)
                    .setListener(this)
                    .enablePendingPurchases(pendingParams)
                    .build();
        
        }
    
        public void connectIfNeeded() {

            if (billingClient.getConnectionState() != BillingClient.ConnectionState.CONNECTING) {
            
                if (billingClient.getConnectionState() != BillingClient.ConnectionState.CONNECTED) {

                    billingClient.startConnection(new BillingClientStateListener() {
        
                        @Override
                        public void onBillingSetupFinished(
                                @NonNull BillingResult billingResult) {
                        
                            target.getBA().raiseEventFromDifferentThread(target, null, 0, "billingmanager_connected", false, new Object[] {AbsObjectWrapper.ConvertToWrapper(new BillingResultWrapper(), billingResult)});
                        
                        }

                        @Override
                        public void onBillingServiceDisconnected() {
                    
                        }
                    
                    });
                        
                } else {

                    BillingResult billingResult = BillingResult.newBuilder()
                                    .setDebugMessage("Already Connected.")
                                    .setResponseCode(BillingClient.BillingResponseCode.OK)
                                    .build();

                    target.getBA().raiseEventFromDifferentThread(target, null, 0, "billingmanager_connected", false, new Object[] {AbsObjectWrapper.ConvertToWrapper(new BillingResultWrapper(), billingResult)});
            
                }
            
            } else {
        
                return;
            }

        }
    
        /* ================= PURCHASE RESULT ================= */

        @Override
        public void onPurchasesUpdated(
                @NonNull BillingResult billingResult,
                List<Purchase> purchases) {

            anywheresoftware.b4a.objects.collections.List lPurchases = new anywheresoftware.b4a.objects.collections.List();
        
            if (purchases != null) {
                lPurchases.setObject((List)purchases);
            }
                        
            //target.getBA().raiseEventFromDifferentThread(target, null, 0, "billingmanager_onpurchasesupdated", false, new Object[] {AbsObjectWrapper.ConvertToWrapper(new BillingResultWrapper(), billingResult), lPurchases});
        
        }

        /* ================= RESTORE ================= */

        public void queryPurchases(String productType) {

            QueryPurchasesParams params =
                    QueryPurchasesParams.newBuilder()
                            .setProductType(productType)
                            .build();

            billingClient.queryPurchasesAsync(
                    params,
                    new com.android.billingclient.api.PurchasesResponseListener() {

                        @Override
                        public void onQueryPurchasesResponse(
                                @NonNull BillingResult billingResult,
                                @NonNull List<Purchase> purchases) {
                        
                            anywheresoftware.b4a.objects.collections.List lPurchases = new anywheresoftware.b4a.objects.collections.List();
                        
                            if (purchases != null) {
                                lPurchases.setObject((List)purchases);
                            }
                        
                            target.getBA().raiseEventFromDifferentThread(target, null, 0, "billingmanager_purchasesquerycompleted", false, new Object[] {AbsObjectWrapper.ConvertToWrapper(new BillingResultWrapper(), billingResult), lPurchases});

                        }
                    }
            );

        }

        public boolean isBillingReady() {
    
            return (billingClient != null && billingClient.isReady());

        }
        
        /* ================= RELEASE ================= */

        public void release() {
            if (billingClient != null
                    && billingClient.isReady()) {

                billingClient.endConnection();
            }
        }
    
    }
 
#End If
 
Last edited:
Upvote 0
Top