Android Question GooglePlayBilling - In App Purchases

AllanH

Member
Licensed User
Longtime User
I appear to have successfully managed to get InApp billing working and even got some money!
However, Crashlytics is showing a fatal error that appears to be related to billing that I can't explain:

In com.android.billingclient.api.ProxyBillingActivity.onCreate (com.android.billingclient:billing@@3.0.1:13)

Caused by java.lang.NullPointerException
Attempt to invoke virtual method 'android.content.IntentSender android.app.PendingIntent.getIntentSender()' on a null object reference


Looking at my code, which I copied from the Billing example, I wonder whether the code

Private Sub HandleAdsPurchase (p As Purchase):
If p.Sku.StartsWith("android.test") = False And billing.VerifyPurchase(p, BILLING_KEY) = False Then

Should instead be

Private Sub HandleAdsPurchase (p As Purchase):
If (p.Sku.StartsWith("android.test") = False) Or (billing.VerifyPurchase(p, BILLING_KEY) = False) Then

I have changed the "android.test" to the correct InApp text.

Thanks
 

AllanH

Member
Licensed User
Longtime User
Fatal Exception: java.lang.RuntimeException
Unable to start activity ComponentInfo{bse.echocalc/com.android.billingclient.api.ProxyBillingActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.IntentSender android.app.PendingIntent.getIntentSender()' on a null object reference

android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2778)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2856)
android.app.ActivityThread.-wrap11
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1589)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loop (Looper.java:164)
android.app.ActivityThread.main (ActivityThread.java:6494)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:438)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:807)

Caused by java.lang.NullPointerException
Attempt to invoke virtual method 'android.content.IntentSender android.app.PendingIntent.getIntentSender()' on a null object reference

com.android.billingclient.api.ProxyBillingActivity.onCreate (com.android.billingclient:billing@@3.0.1:13)
android.app.Activity.performCreate (Activity.java:7009)
android.app.Activity.performCreate (Activity.java:7000)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1214)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2731)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2856)
android.app.ActivityThread.-wrap11
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1589)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loop (Looper.java:164)
android.app.ActivityThread.main (ActivityThread.java:6494)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:438)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:807)

B4XMainPage:
Private Sub B4XPage_Created (Root1 As B4XView)
...
RestorePurchases
...
End Sub

Private Sub RestorePurchases
    Wait For (billing.ConnectIfNeeded) Billing_Connected (Result As BillingResult)
    If Result.IsSuccess Then
        Wait For (billing.QueryPurchases("inapp")) Billing_PurchasesQueryCompleted (Result As BillingResult, Purchases As List)
        Log("Query completed: " & Result.IsSuccess)
        If Result.IsSuccess Then
            For Each p As Purchase In Purchases
                If p.Sku.StartsWith("bse.echocalc.donate") Then HandleAdsPurchase(p)
            Next
        End If
    End If
End Sub

Public Sub PurchaseDonation (sProductID As String)
    ' called from a menu click on a page
    'make sure that the store service is connected
    Wait For (billing.ConnectIfNeeded) Billing_Connected (Result As BillingResult)
    If Result.IsSuccess Then
        'get the sku details
        Dim sf As Object = billing.QuerySkuDetails("inapp", Array(sProductID))
        Wait For (sf) Billing_SkuQueryCompleted (Result As BillingResult, SkuDetails As List)
        If Result.IsSuccess Then
            If SkuDetails.Size >= 1 Then
                Result = billing.LaunchBillingFlow(SkuDetails.Get(0))
                If Result.IsSuccess Then Return
            End If
        End If
    End If
    ToastMessageShow("Error starting billing process", True)
End Sub

Sub billing_PurchasesUpdated (Result As BillingResult, Purchases As List)
    'This event will be raised when the status of one or more of the purchases has changed.
    'It will usually happen as a result of calling LaunchBillingFlow however it can be called in other cases as well.
    If Result.IsSuccess Then
        For Each p As Purchase In Purchases
            If p.Sku.StartsWith("bse.echocalc.donate") Then
                HandleAdsPurchase(p)
            Else
                Log("Unexpected product: " & p.Sku)
            End If
        Next
    End If
End Sub

Private Sub HandleAdsPurchase (p As Purchase)
    Dim dDonated As Double
    Dim sValue As String
    If p.PurchaseState <> p.STATE_PURCHASED Then Return
    'Verify the purchase signature.
    'This cannot be done with the test id.
    If (p.Sku.StartsWith("bse.echocalc.donate") = False) And (billing.VerifyPurchase(p, BILLING_KEY) = False) Then
        Log("Invalid purchase")
        Return
    End If
    'we either acknowledge the product or consume it.
    'If p.IsAcknowledged = False Then
    'Wait For (billing.AcknowledgePurchase(p.PurchaseToken, "")) Billing_AcknowledgeCompleted (Result As BillingResult)
    'Log("Acknowledged: " & Result.IsSuccess)
    'End If
    'SKU = bse.echocalc.donate2 or bse.echocalc.donate5 or bse.echocalc.donate10
    sValue = p.Sku.SubString (19)
    If IsNumber (sValue) Then
        wait For (billing.Consume(p.PurchaseToken, "")) Billing_ConsumeCompleted (Result As BillingResult)
        Log("Consumed: " & Result.IsSuccess)
        dDonated = Assets.GetSetting ("Donated")
        dDonated = dDonated + sValue
        Assets.SetSetting ("Donated", dDonated)
        Log("Donation confirmed")
        Patient.UpdateDonationStatus
    Else
        Log("Error with purchase: " & p.Sku)
    End If
End Sub
 
Upvote 0

AllanH

Member
Licensed User
Longtime User
Yes. Last line of Manifest.
I have got the purchasing working using my test account and users are successfully purchasing the "donations".
I might be overzealous in squashing the bugs - it's only happened to one user (Nexus 5, Android 8.1) so far.
This latest app version replaces an old stable codebase (pre-B4XPages) and I'm trying to ensure all users are happy with the rather extensive upgrade.
Similarly, the codebase is shared with B4i and my Apple version replaces a well loved app used by 10's of thousands of users.

With regard to the example code, should an invalid purchase not be either "not my SKU" OR VerifyPurchase = False rather than both?

Thanks
 
Upvote 0
Top