qonversion / android-sdk

Android SDK for cross-platform in-app purchase and subscription infrastructure, revenue analytics, engagement automation, and integrations
124 stars 21 forks source link

Qonversion.shared.offerings not giving any callback at all. #549

Open michaldrabik opened 10 months ago

michaldrabik commented 10 months ago

Hi team. So we wanted to try out your product. We have set up everything according to docs but encountering a problem when trying the most simple thing which is getting offerings.

I think this pic is fastest way to showcase it. setupQuonversion() is called after App super.onCreate()

You can observe the LogCat and notice that neither callback is being triggered. Any ideas on how to even check what might be wrong?

image

Regards

SpertsyanKM commented 10 months ago

Hello, @michaldrabik! Do you have any offerings set up on the Qonversion dashboard?

michaldrabik commented 10 months ago

@SpertsyanKM Yep, all there. Also just double checked that the project key is valid. Still a no go. Basically method is called and nothing happens.

image

SpertsyanKM commented 10 months ago

I've checked your scenario and everything worked fine for our sample app. To dig deeper into your concrete case could you please contact us via the support (a chat icon at the bottom right angle of our main page), as we'll need some sensitive information about your project.

michaldrabik commented 10 months ago

OK, just to confirm - also played with sample app and it seemed to be working all right too for me.

michaldrabik commented 10 months ago

Closed accidentally

SpertsyanKM commented 10 months ago

For the history:

the problem was caused by the conflict with the Hilt library. It requires disabling the default initializer in Android WorkManager that in turn stops ProcessLifecycleOwner working, which is used in Qonversion SDK, including initialization.

<!-- If you want to disable android.startup completely. -->
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove">
</provider>

That's why Qonversion initialization gets stuck and no offerings callback is executed (neither any other callbacks would).

The solution, provided by @michaldrabik :

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <!-- If you are using androidx.startup to initialize other components -->
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>
astuetz commented 3 months ago

Hey there, I'm running into the exact same problem. Our setup already does what's mentioned on the comment above (regarding androidx.startup) but still Qonversion.shared.offerings never calls any of the onSuccess or onError callbacks.

I'm actually trying to get the offerings inside a WorkManager CoroutineWorker. The app was fully terminated before the worker is called, but I can see that our Application gets created and also initializes Qonversion before Qonversion.shared.offerings is called.

If the Worker runs while the app is active (e.g. in foreground), everything works as expected.

edit: mentioning @SpertsyanKM directly so this will hopefully get seen, I didn't want to open another Issue as it's the same problem (but probably different cause)

Any ideas on what could cause this? Thanks!

SpertsyanKM commented 3 months ago

Hello, @astuetz. Is it possible to provide a kind of minimal reproducible example of the issue? The mentioned kind of problem needs step-by-step reproduction to be able to find any issues in code, so the example would be very appreciated.

You can send it directly to my email - kamo@qonversion.io.

astuetz commented 3 months ago

Hi @SpertsyanKM, I uploaded a minimal sample project on GitHub: https://github.com/astuetz/qonversion-workmanager-sample

See the readme for steps to reproduce. Our use case for getting the offerings inside a Worker would be to show a notification to the user including some price info.

SpertsyanKM commented 3 months ago

Great, thank you for the provided information! I'll try everything today and come back as soon as I have any news

SpertsyanKM commented 3 months ago

Thanks again for the reproducible example - it helps so much!

I've tried the provided steps and here is what I see. When I kick the app after clicking the button, it doesn't complete the background task at all - doesn't even call offerings (or doesn't type anything in logs which is closer to the truth, I guess). After the app relaunch and clicking again the button (without clicking - nothing but Qonversion initialization happens), I receive the result instantly, without delay. Meanwhile, another job starts right after the delay.

To check if this behavior is somehow related to Qonversion or not I removed the offerings call from the worker and nothing changed - it still behaves the same way (of course without receiving offerings). So I think that is how CoroutineWorker behaves.

astuetz commented 3 months ago

Hey!

Strange that it behaves differently for you. I'm running this on a Pixel 6 Pro with Android 14. Did you wait long enough after kicking the app? You might also have to interact with the device a bit while waiting, so WorkManager will actually fire off the Worker.

Here's what I see on the logs (removed a few to make it simpler):

---------------------------- PROCESS STARTED (9048) for package com.astuetz.qonversionworkmanager ----------------------------
12:38:04.100  9048-9048  astuetz                 com.astuetz.qonversionworkmanager    D  Initializing Qonversion
12:38:04.236  9048-9048                                                               D  Finished initializing Qonversion
12:38:09.585  9048-9048                                                               D  Enqueuing GetOfferingsWorker for 1722940704582
---------------------------- PROCESS ENDED (9048) for package com.astuetz.qonversionworkmanager ----------------------------
---> APP WAS KICKED HERE RIGHT AFTER CLICKING THE BUTTON

---> WORKER STARTS
---------------------------- PROCESS STARTED (9164) for package com.astuetz.qonversionworkmanager ----------------------------
12:38:36.471  9164-9164                          com.astuetz.qonversionworkmanager    D  Initializing Qonversion
12:38:36.702  9164-9164                                                               D  Finished initializing Qonversion
12:38:38.050  9164-9206                                                               D  GetOfferingsWorker::doWork
12:38:38.050  9164-9206                                                               D  Calling Qonversion.shared.offerings
---> offerings is not returning, Worker is stuck waiting.

---> APP WAS RE-LAUNCHED HERE (almost 1 minute later) 
12:39:27.163  9164-9164                                                               D  QonversionOfferingsCallback::onSuccess

I was actually using a BroadcastReceiver before trying the CoroutineWorker and had the exact same issue there, the receiver gets invoked but then Qonversion.shared.offerings does not complete until the app is in foreground again.

Since your SDK is heavily relying on the app lifecycle, I feel like something is off related to that.

SpertsyanKM commented 3 months ago

Really strange... I'm using Pixel 7 with Android 14, so it seems to be pretty similar. Do you use an emulator or a real device?

SpertsyanKM commented 3 months ago

Here is what I receive:

2024-08-06 14:13:10.371 11513-11513 astuetz                 com.astuetz.qonversionworkmanager    D  Enqueuing GetOfferingsWorker for 1722942805366
---------------------------- PROCESS ENDED (11513) for package com.astuetz.qonversionworkmanager ----------------------------
----> APP WAS KICKED HERE RIGHT AFTER CLICKING THE BUTTON
----> NOTHING HAPPENS UNTIL I MANUALLY RELAUNCH THE APP EVEN AFTER A MINUTE
---------------------------- PROCESS STARTED (11675) for package com.astuetz.qonversionworkmanager ----------------------------
2024-08-06 14:14:50.633 11675-11675 astuetz                 com.astuetz.qonversionworkmanager    D  Initializing Qonversion
2024-08-06 14:14:50.768 11675-11675 astuetz                 com.astuetz.qonversionworkmanager    D  Finished initializing Qonversion
----> HERE I TAP THE BUTTON AGAIN
2024-08-06 14:14:54.180 11675-11675 astuetz                 com.astuetz.qonversionworkmanager    D  Enqueuing GetOfferingsWorker for 1722942909152
----> INSTANT RESULT
2024-08-06 14:14:54.258 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  GetOfferingsWorker::doWork
2024-08-06 14:14:54.258 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  Calling Qonversion.shared.offerings
2024-08-06 14:14:54.964 11675-11675 astuetz                 com.astuetz.qonversionworkmanager    D  QonversionOfferingsCallback::onSuccess
2024-08-06 14:14:54.965 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  getOfferings success, main offering: QOffering(...)
----> ENQUEUED RESULT (button was clicked only once)
2024-08-06 14:15:09.270 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  GetOfferingsWorker::doWork
2024-08-06 14:15:09.270 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  Calling Qonversion.shared.offerings
2024-08-06 14:15:09.993 11675-11675 astuetz                 com.astuetz.qonversionworkmanager    D  QonversionOfferingsCallback::onSuccess
2024-08-06 14:15:09.993 11675-11762 astuetz                 com.astuetz.qonversionworkmanager    D  getOfferings success, main offering: QOffering(...)
SpertsyanKM commented 3 months ago

Kind of magic, but somehow now it reproduced as you described. I'll continue investigating

SpertsyanKM commented 3 months ago

Hi, I checked everything, and here is what happens in your case.

First of all, the problem with reproducing is caused by a longer delay before starting the background task as expected - even if set to 15 seconds it can start a minute after you close the app — just a note for history.

Speaking of the problem itself - after the background task begins, the Qonversion initialization starts and doesn't finish as we have a block in code for background initialization - it won't finish until the app goes to the foreground. Each SDK request (including offerings) waits for initialization to finish and only then processes - this is why you are stuck with getting a response.

Now I want to understand your use-case better to create a feature request if necessary, to support background mode for the SDK. Could you please explain it to me?

astuetz commented 3 months ago

Hey! I mentioned it briefly on a previous comment. I need to show a "discount" notification (x hours before the discount runs out) to a user and wanted to get the correct price at the time of showing the notification. I'm wondering if there's any technical limitation on your side to not fully initilize while the app is not in foregound? Esp. having no callback being invoked at all is a very strange and highly unexpected behavior and this cost me quite a lot of time already to even find.

SpertsyanKM commented 3 months ago

Thank you for the details. I've created a feature request for your case. We will discuss and implement the possible solutions with the team.

I'm wondering if there's any technical limitation on your side to not fully initilize while the app is not in foregound?

It's done to prevent spamming initialization requests from the apps where there is no need in Qonversion in the background. The most popular case is push notifications - the app launches in the background when receives the message and usually initializes Qonversion on each launch. But your case is clear so we're going to discuss probably a better solution or any workaround.

astuetz commented 1 month ago

👋🏻 It's been a while, are thee any updates on this?

SpertsyanKM commented 1 month ago

Hi @astuetz ,

Thank you for reaching out about your feature request. I understand how important this is to you. Currently, there are no updates, as your request is still in our backlog. We appreciate your patience and will keep you posted as soon as there’s any progress.

If you have any other questions or need further assistance, feel free to ask!