Android Question Need help with getting subscription prices

tsteward

Well-Known Member
Licensed User
Longtime User
My app keeps getting rejected by Google due to subscription price presented to the user being misleading.
What am I doing wrong or how can I fix this to show the correct local price.

"sprice" is supposed to contain the price of the subscription

Attached is the image from google that the user in some country somewhere sees.
US, Aus and many others see the correct price.

B4X:
Dim sf As Object = Starter.billing.QuerySkuDetails("subs", Array(Starter.ADS_SDK_ID4,Starter.ADS_SDK_ID5))
        Wait For (sf) Billing_SkuQueryCompleted (Result As BillingResult, SkuDetailsList As List)
        Starter.myLog.Add($"(GetAllProductPrice) Info received from PS Result - ${Result.ResponseCodeString}"$)
        If Result.IsSuccess And SkuDetailsList.Size > 0 Then
            clvSubscribe.Clear
            For Each Sku As SkuDetails In SkuDetailsList
                Dim sPrice As String
                If Sku.Price = "" Then
                    Dim offers As List = Sku.As(JavaObject).RunMethod("getSubscriptionOfferDetails", Null)
                    Dim offer As JavaObject = offers.Get(0)
                    Dim PricingPhases As JavaObject
                    PricingPhases = offer.RunMethod("getPricingPhases", Null)
                    Dim l As List = PricingPhases.RunMethod("getPricingPhaseList", Null)
                    Dim PricingPhase As JavaObject
                    PricingPhase = l.Get(0)
                    sPrice = PricingPhase.RunMethod("getFormattedPrice", Null)
                Else
                    sPrice = Sku.Price
                End If
                Dim p As B4XView = xui.CreatePanel("")
                p.SetLayoutAnimated(0, 0, 0, clvSubscribe.AsView.Width, 200dip)
                p.LoadLayout("subsrowlayout")
                Dim mydesc As String = ""
                If Sku.Sku = "lara202312" Then
                    clvSubsItemTitle.Text = B4XPages.MainPage.loc.Localize("LARA 12 Month Subscription")
                    mydesc = Sku.Description & CRLF & CRLF & "Free Trial - Cancel subscription withing 7 days and there will be no charge"
                End If
                If Sku.Sku = "lara202306" Then
                    clvSubsItemTitle.Text = B4XPages.MainPage.loc.Localize("LARA 6 Month Subscription")
                    mydesc = Sku.Description & CRLF & CRLF & "Free Trial - Cancel subscription withing 7 days and there will be no charge"
                End If
                If Starter.SKU_Purchased = Sku.Sku Then
                    clvSubsItemAmount.Text = B4XPages.MainPage.loc.Localize("Active")
                    clvSubsItemButton.Text = B4XPages.MainPage.loc.Localize("Cancel")
                    mydesc = Sku.Description & CRLF & CRLF & Starter.productID & CRLF & DateTime.Date(Starter.purchaseTime) & " - " & DateTime.Time(Starter.purchaseTime)
                Else
                    clvSubsItemAmount.Text = sPrice
                    clvSubsItemButton.Tag = Sku.Sku
                    clvSubsItemButton.Text = B4XPages.MainPage.loc.Localize("Buy")
                    If Main.AppSubscriptionActive = True Then
                        clvSubsItemButton.Enabled = False
                    End If
                End If
                clvSubsItemDesc.Text = mydesc
                clvSubscribe.Add(p,Sku.Title)
            Next
            clvSubscribe.AsView.Visible = True
        else if Result.ResponseCodeString = "FEATURE_NOT_SUPPORTED" Then
            xui.MsgboxAsync($"Sorry your version of Google Play Store is not supported${CRLF}Result - ${Result.ResponseCodeString}"$, "Not Supported")
        End If
 

Attachments

  • IN_APP_EXPERIENCE-4524.png
    215.2 KB · Views: 144

asales

Expert
Licensed User
Longtime User
I think the problem is because you don't show the price on this screen:



Check out these paywall examples:

I follow these examples and I have no problem publishing apps, including showing prices in other currencies.
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
I have had no problem publishing for the last 15 years
I have followed the examples exactly (I thought) but sPrice = Sku.Price is returning Free instead of the price but not in all cases as per attached image from my phone

My inability to solve this is screwing me big time
Really need some help please
 

Attachments

  • 449083109_372541702514270_492780690780518753_n.jpg
    69.4 KB · Views: 66
Upvote 0

asales

Expert
Licensed User
Longtime User
I have had no problem publishing for the last 15 years
Google always change your policies and rules.
My app has 10 years in Play Store and now get a warning from Google.
You cannot assumes that your app it is always in agreement with the new policies.
I think the Google don't check all the content of the app and years later can find a problem in the app and does not allow the update.

I have followed the examples exactly (I thought) but sPrice = Sku.Price is returning Free instead of the price but not in all cases as per attached image from my phone

My inability to solve this is screwing me big time
Really need some help please
I don't think the "Free" word is returned in Sku.Price.
I think the problem is somewhere else.

Did you check if the labels in the Visual Designer has this word "Free" in the Text property?

Maybe, in some cases, when you open the screen with the subscription information, there is no time to load the online information, and it shows the content ("Free") of the Text field in the label.

Did you load the information and price of subscriptions when you open the app, in Starter or B4XMainPage modules?
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
I know "Free" is being returned where else is it coming from? I search my app and it is no where.
You can see my code above there is no Free

My app is screwed money going down the drain. It must be my fault but I just know how or where
 
Upvote 0

asales

Expert
Licensed User
Longtime User
You can see my code above there is no Free
I don't talk about the "Free" word in your code, I'm talking about the layout.

If possible, share the layout of this screen:



And you don't answered this question:
Did you load the information and price of subscriptions when you open the app, in Starter or B4XMainPage modules?
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
I have checked the labels but the layout is attached as requested.
I do not load at startup its in the b4xmainpage
After the app has loaded you can select Menu then Select subscriptions, it will then go to the routine attached in the first post here.

Your help is very much appreciated, I really need to get this sorted this weekend before I lose more clients
 

Attachments

  • subsrowlayout.bal
    3.7 KB · Views: 69
Upvote 0

asales

Expert
Licensed User
Longtime User
I have checked the labels but the layout is attached as requested.
My guess was wrong. I don't know were the Free word are from.
Did you check the plans in the Google Play Console? There are nothing about Free price?
I put my subscription routine in the Starter. There are a delay to load the informations.
When I open the screen to user made the subscription, I only check the values loaded when the app is opened.
Check this example, based in the original example from Erel. The informations are loaded in the B4XMainPage.
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
I have moved getting the price to the starter but still my app gets rejected.
This is hurting my livelihood, hurting my reputation. I can't fix this and need someone who can help me.

Here is google email

Here is my code
B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    'RestorePurchases
            Dim purchaseTime As Long
            Public billing As BillingClient
            Public const ADS_SDK_ID As String = "laraplus2018"
            Public const ADS_SDK_ID2 As String = "laraplus6mth"
            Public const ADS_SDK_ID3 As String = "laraplus1"
            Public const ADS_SDK_ID4 As String = "lara202312"
            Public const ADS_SDK_ID5 As String = "lara202306"
            Public ADS_SDK_Token As String = ""
            Public sixMonthPrice, twelveMonthPrice As String = ""
            
            Public productID, subsID, token As String = ""
            Public SKU_Purchased As String = ""
            Private purchList As List
            Public const BILLING_KEY As String = "MIIBIjANBgk....."
            Public myLog As List
End Sub

Sub Service_Create
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.
    myLog.Initialize
    purchList.Initialize
    billing.Initialize("billing")
    #if Full
    RestorePurchases
    #end if
End Sub

Sub Service_Start (StartingIntent As Intent)
    Service.StopAutomaticForeground 'Starter service can start in the foreground state in some edge cases.
End Sub

Sub Service_TaskRemoved
    'This event will be raised when the user removes the app from the recent apps list.
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy

End Sub

public Sub RestorePurchases
Wait For (billing.ConnectIfNeeded) Billing_Connected (Result As BillingResult)   
    If Result.IsSuccess Then
        Dim sf As Object = billing.QuerySkuDetails("subs", Array(ADS_SDK_ID4,ADS_SDK_ID5))
        Wait For (sf) Billing_SkuQueryCompleted (Result As BillingResult, SkuDetailsList As List)
        If Result.IsSuccess And SkuDetailsList.Size > 0 Then
            For Each Sku As SkuDetails In SkuDetailsList
                Dim sPrice As String
                If Sku.Price = "" Then
                    Dim offers As List = Sku.As(JavaObject).RunMethod("getSubscriptionOfferDetails", Null)
                    Dim offer As JavaObject = offers.Get(0)
                    Dim PricingPhases As JavaObject
                    PricingPhases = offer.RunMethod("getPricingPhases", Null)
                    Dim l As List = PricingPhases.RunMethod("getPricingPhaseList", Null)
                    Dim PricingPhase As JavaObject
                    PricingPhase = l.Get(0)
                    sPrice = PricingPhase.RunMethod("getFormattedPrice", Null)
                Else
                    sPrice = Sku.Price
                End If
                If Sku.Sku = "lara202312" Then
                    If sPrice.ToLowerCase = "free" Then
                            sPrice = "$65.99 AUD"
                    End If
                    twelveMonthPrice = sPrice
                else if Sku.Sku = "lara202306" Then
                    If sPrice.ToLowerCase = "free" Then
                        sPrice = "$43.99 AUD"
                    End If
                    sixMonthPrice = sPrice
                End If
            Next
        End If



        Wait For (billing.QueryPurchases("subs")) Billing_PurchasesQueryCompleted (Result As BillingResult, Purchases As List)
        If Result.IsSuccess Then
            myLog.Add("(RestorePurchases) Were In")
            For Each p As Purchase In Purchases
                productID = p.OrderId
                'Log(productID)
                purchaseTime = p.PurchaseTime
                SKU_Purchased = p.Sku
                token = p.PurchaseToken
                subsID = p.Sku
                myLog.Add($"(RestorePurchases) SKU received Result - ${p.Sku}"$)
                If p.Sku = "laraplus6mth" Or p.Sku = "laraplus1" Or p.Sku = "laraplus2018" Or p.Sku = "lara202312" Or p.Sku = "lara202306" Then
                    HandleAdsPurchase(p)
                Else
                    Main.AppSubscriptionActive = False
                End If
            Next
        Else
            myLog.Add($"(RestorePurchases) Info NOT received from PS Result - ${Result.ResponseCodeString}"$)
        End If
    End If
End Sub

public Sub HandleAdsPurchase (p As Purchase)
    If p.PurchaseState <> p.STATE_PURCHASED Then Return
    'Verify the purchase signature.
    'This cannot be done with the test id.
    If p.Sku.StartsWith("android.test") = False And billing.VerifyPurchase(p, BILLING_KEY) = False Then
        'Log("Invalid purchase")
        Return
    End If
    If p.IsAcknowledged = False Then
        'we either acknowledge the product or consume it.
        Wait For (billing.AcknowledgePurchase(p.PurchaseToken, "")) Billing_AcknowledgeCompleted (Result As BillingResult)
        If Result.IsSuccess Then
            Select p.Sku
                Case ADS_SDK_Token
                    Wait For (billing.QueryPurchases("inapp")) Billing_PurchasesQueryCompleted (Result As BillingResult, Purchases As List)
                    If Result.IsSuccess Then
                        B4XPages.MainPage.Pages.PageShop.SendEeprom(Purchases,p.Sku)
                    End If
                Case ADS_SDK_ID, ADS_SDK_ID2, ADS_SDK_ID3,ADS_SDK_ID4,ADS_SDK_ID5
                    productID = p.OrderId
                    purchaseTime = p.PurchaseTime
                    SKU_Purchased = p.Sku
                    token = p.PurchaseToken
                    subsID = p.Sku
                    Main.AppSubscriptionActive = True
            End Select
        End If
    Else
        If p.Sku = ADS_SDK_ID Or p.Sku = ADS_SDK_ID2 Or p.Sku = ADS_SDK_ID3 Or p.Sku = ADS_SDK_ID4 Or p.Sku = ADS_SDK_ID5 Then
            productID = p.OrderId
            purchaseTime = p.PurchaseTime
            SKU_Purchased = p.Sku
            token = p.PurchaseToken
            subsID = p.Sku
            Main.AppSubscriptionActive = True
            'Main.OKToPost = True
        Else
            productID = ""
            Main.AppSubscriptionActive = False
            'Main.OKToPost = False
        End If
    End If
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 abilling_PurchasesUpdatedresult of calling LaunchBillingFlow however it can be called in other cases as well.
    If Result.IsSuccess Then
        For Each p As Purchase In Purchases
                HandleAdsPurchase(p)
        Next
    Else
        If Result.ResponseCode = 7 Then 'Product has already been purchased
            Wait For (billing.QueryPurchases("inapp")) Billing_PurchasesQueryCompleted (Result As BillingResult, Purchases As List)
            For Each p As Purchase In Purchases
                If Result.IsSuccess Then
                    B4XPages.MainPage.Pages.PageShop.SendEeprom(Purchases,p.Sku)
                End If
            Next
        End If
    End If
End Sub

public Sub ConsumeAdsProduct(Purchases As List)
    For Each p As Purchase In Purchases
        Select p.Sku
            Case ADS_SDK_ID, ADS_SDK_ID2, ADS_SDK_ID3,ADS_SDK_ID4,ADS_SDK_ID5
                Wait For (billing.Consume(p.PurchaseToken, "")) Billing_ConsumeCompleted (Result As BillingResult)
                If Result.IsSuccess Then
                    'Log("consumed")
                    Main.AppSubscriptionActive = False
                Else
                    ToastMessageShow("Consumption incomplete",True)
                End If
            Case ADS_SDK_Token
                Wait For (billing.Consume(p.PurchaseToken, "")) Billing_ConsumeCompleted (Result As BillingResult)
                If Result.IsSuccess Then
                    'Log("consumed")
                End If
            Case Else
                ToastMessageShow("(ConsumeAdsProduct) Invalid SKU",True)
                Main.AppSubscriptionActive = False
        End Select
    Next
End Sub
 

Attachments

  • IN_APP_EXPERIENCE-2011.png
    157.6 KB · Views: 69
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
(Just my point of view)

On other software I have used with a free trial, there is usually a 'Start your Free Trial' button that explains that after xx Days it will convert to a paid subscription unless cancelled. Or you get a 'Buy Now' button which forgoes the trial and starts the subscription.

Maybe Google doesn't like a Purchase button for the free trial. As this could be misleading to people who want to purchase it outright, into a free trial.
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
I'll try anything at the moment. This has been going on for 2 weeks and I'm currently curled up in the corner in the fetal position
 
Upvote 0

asales

Expert
Licensed User
Longtime User

Issue found: Violation of Subscriptions policy​

Your app does not comply with the Subscriptions policy.
  • Your offer does not clearly and accurately describe the terms of your trial offer or introductory pricing, including when a free trial will convert to a paid subscription, how much the paid subscription will cost, and that a user can cancel if they do not want to convert to a paid subscription.

This is not about the code. It is about the informations and screen design.
I got the same message some weeks ago and I change all my screen - and removed the free trial option.
 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
Yeah removing free trial might be next on the list. I'll just add a shorted subscription for those that aren't sure.
Also looking at the image I'm saying 14 day trial and when you go to pay it says 7 day trial so that might be why.

I wish a human from google would actual reply with exactly what is wrong. I know I'm only a small fish but google have made thousands from me so I don't think it's too much to ask. I'd love not to have to use playstore.
 
Upvote 0

73Challenger

Active Member
Licensed User
Same issue the last time I updated. I can't say 100% what worked because Google won't tell us but... here are the changes I made that eventually got my apps approved. Screenshots below...

1. Originally, my users had to click purchase to be notified of free trial... I refactored so the app would be in "Trial state" when opened...trial automatically enabled. Basically, fully functional in trial on install/load. I basically had to allow limited use for the trial, in my case all buttons and all functionality works for 7 entries, then pop up a message that the free trial was for 7 entries only...please subscribe.

2. Made extensive changes to my message box text. I wrote it so a child could read. Very simple words very simple sentences. My thought is, it has to be approved for all languages, and maybe some words or phrasing doesn't translate well.

3. Explained very clearly that the subscription can be cancelled at any time. I despise this, we are trying to sell apps but we have to tell customers that .. hey, you can just drop us for any reason any time...stinks...but google requires it.

I don't know what the magic change was, if one or all of these changes were required...but it finally was approved.

But again, who knows they won't tell us for sure...so frustrating.
 

Attachments

  • Screenshot_20240707_200853.jpg
    481.8 KB · Views: 74
  • Screenshot_20240707_200859.jpg
    511.3 KB · Views: 69
Last edited:
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User
I know wehn I look at it I do not understand what is free and what isn't. I THINK you mean 7 day free trial but it really is not clear. And it is not a seven day free trial if I have to pay to get it.
 
Upvote 0

73Challenger

Active Member
Licensed User
Update: Google is getting almost un-workable with these requirements....at least for me. Just sharing my experience here and complaining about Google LOL... not looking for code/answers Nothing I can do about it but make changes and bellyache, either change or apps get removed.

For a month now, I've been "updating" to the new SDK and Billing Library requirements. The library/sdk was the easy part (thanks @Erel). But significant "experience" changes were required. All my apps use the exact same startup "framework" Splash screen, free trial and subscription code, wording (except for app name). Took two iterative rounds to figure out what the problem was and get 11 of the 12 approved....yes 11/12. Sigh

This past week, they gave me 5 days to update one of the 12 apps or they were going to remove it. So, even though all apps were using the same Startup/Subscription framework and code, except for 1 text string, the app name, Google WOULD NOT approve 1 of them and was threatened to removed 1 of the 12 W T F So finally after 3 tries, with absolutely no guidance from Google I got rid of my splash screen and the app got approved.

I Had to change the whole free trial "experience" and framework to get rid of the splash/popup (screenshot below). I moved the "free trial" text to a label that just says "this is a free trial, subscription required for full access." Users can immediately start entering data, I only do the popup after the "Free 7 hands" are entered.

So that got the 1 approved and it didn't get removed, thank goodness. Now of course, I have to re-re-re-re-re update all the other apps so the user experience is the same across all of them. Wouldn't have to, but I like presenting a consistent experience.

Honestly, I don't make that much from the apps, it's something, but not worth this level of engagement. Google is making it so difficult that I don't know how much longer I'll maintain the apps.

This is what it looked like before...I removed the splash screen and go right into the app now, but only allow 7 hands before subscription splash is popped up. Seems harmless enough but they would not approve 1 app with that splash screen there. The other apps, all good unbelieveable.

 
Upvote 0

tsteward

Well-Known Member
Licensed User
Longtime User
You also need to provide a link for them to unsubscribe and explain what happens with any remaining credit
here is what eventually worked for me. In full release it shows price per month etc $xx.xx/month
 

Attachments

  • Screenshot_20240802-064242.png
    192.9 KB · Views: 36
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…