Bug: PurchasingService.registerListener() throws “Resource already registered” in Appstore SDK 3.0.5+ on FlutterActivity-based apps; SDK 3.0.4 only works via partial state

Hello Amazon Appstore SDK team,

I am reporting what appears to be an SDK-internal listener registration regression in Amazon Appstore SDK 3.0.5 and later.

In a FlutterActivity-based Android app, PurchasingService.registerListener(applicationContext, listener) throws:

Resource already registered

After this exception, the PurchasingListener is not fully registered. In SDK 3.0.5 and later, subsequent calls to purchase() and getPurchaseUpdates() fail with:

You must register a PurchasingListener before invoking this operation

SDK 3.0.4 is the only tested version where the app can continue successfully, but log evidence suggests 3.0.4 may also throw the same internal resource-registration exception and then tolerate the partial registration state.

Environment:

  • App name: Beadwell

  • Package name: com.beadwell.app

  • Product ID: parent_toolkit_lifetime

  • Product type: one-time non-consumable / entitlement unlock

  • App type: Flutter Android app using FlutterActivity

  • Native bridge: Android/Kotlin wrapper around Amazon Appstore SDK IAP APIs

  • Android version tested: Android 13

  • Install source/signing: installed via Amazon Appstore / production signature

  • SDK versions tested: 3.0.4, 3.0.5, 3.0.6, 3.0.8, 3.0.9

Steps to reproduce:

  1. Create a Flutter Android app using FlutterActivity.

  2. Add Amazon Appstore SDK dependency com.amazon.device:amazon-appstore-sdk:3.0.5 or later.

  3. Register a PurchasingListener by calling:
    PurchasingService.registerListener(applicationContext, listener)

  4. Call registration from an early lifecycle point. We tested:

    • ContentProvider.onCreate() with android:initOrder="1000"

    • Application.onCreate()

    • Activity.onCreate()

    • deferred/lazy registration before first IAP call

  5. Build, install via Amazon Appstore using production signing, and launch the app.

  6. Observe logcat filtered to AmazonIapPlugin, Kiwi, ResourceManagerImpl, and PurchasingService.

Expected behavior:

PurchasingService.registerListener() should complete without throwing when called once from the app process before any IAP operation.

After successful listener registration, calls to PurchasingService.purchase(), getPurchaseUpdates(), and product/entitlement APIs should function normally.

Actual behavior:

PurchasingService.registerListener() throws internally:

Resource already registered: z2.g@a22d1cf
    at H1.b.a(SourceFile:87)
    at x1.a.<init>(SourceFile:180)
    at x1.a.b(SourceFile:24)
    at X1.a.b(SourceFile:1)

Kiwi resource logs show the SDK creating/registering two instances of the same adapter/resource class during a single registerListener() call:

ResourceManagerImpl: Registering resource: z2.g@f26eca9
ResourceManagerImpl: Registering resource: L1.e@364722e
ResourceManagerImpl: Registering resource: z2.g@a22d1cf

The second z2.g registration throws Resource already registered.

After this exception, SDK 3.0.5+ rejects later IAP operations with:

You must register a PurchasingListener before invoking this operation

Version matrix:

SDK version Result Notes
3.0.4 Works Registration path appears to hit the same internal exception, but later purchase() and getPurchaseUpdates() still accept the partial state.
3.0.5 Fails Same internal double-registration exception; later IAP calls reject the partial state.
3.0.6 Fails Same stack trace/source line pattern as 3.0.5.
3.0.8 Fails Same failure pattern.
3.0.9 Fails Same failure pattern; internal adapter class name changed in logs, but behavior is equivalent.

Isolation already performed:

  • Confirmed the app is not intentionally calling registerListener() twice.

  • Tested with only one app-side registration path enabled.

  • Disabled eager provider-based registration and tested Activity-only registration.

  • Tested earliest possible provider registration using android:initOrder="1000".

  • Tested Application, Activity, and deferred/lazy registration.

  • Failure occurs before product loading, purchase, restore, or entitlement checks.

  • The Flutter layer only affects lifecycle timing; the exception is thrown inside PurchasingService.registerListener() / Kiwi resource registration.

Current assessment:

The log evidence suggests PurchasingService.registerListener() internally creates/registers the same Kiwi adapter/resource class twice during a single call. Since the Kiwi ResourceManager appears to key resources by class/type, the second registration throws Resource already registered.

This appears to be SDK-internal behavior, not app-side duplicate listener registration.

Workaround:

Pinned to com.amazon.device:amazon-appstore-sdk:3.0.4.

This is not ideal because 3.0.4 is old and may eventually be deprecated or delisted.

Request:

  1. Please confirm whether this is a known issue in Appstore SDK 3.0.5+.

  2. Please confirm the recommended lifecycle point for PurchasingService.registerListener() in FlutterActivity-based Android apps.

  3. Please investigate why registerListener() appears to register the same Kiwi adapter/resource class twice during a single call.

  4. Please provide a supported workaround or fixed SDK version for FlutterActivity-based apps.

  5. If SDK 3.0.4 is currently the only safe workaround, please confirm whether it remains supported for production apps.

I can provide full logcat files, Gradle dependency tree, Fire tablet model, Fire OS version, APK/AAB build details, and a minimal reproduction project if needed.

Hi @Evgeny_Tkachenko,

Welcome to Amazon Developer Community !!
Thank you for this thorough report - your isolation steps and version matrix are very helpful.

I will need some time to investigate this internally.
The double-registration of the Kiwi resource during a single registerListener() call appears to be an SDK-side regression in 3.0.5+, not an app-side issue based on your evidence, though I cannot confirm that at the moment.

In the meantime:

  • SDK 3.0.4 remains supported for production apps - it is safe to continue using it while this is being investigated.
  • Could you please also share your Fire OS version and device model so we can attempt reproduction on our end?

We’ll update this thread once we have more clarity on this issue.

Warm regards,
Ivy

Hi Ivy,

Thank you for the quick response and for looking into this internally.

Here are the device details from my test device:

  • Device model: Fire 7, 12th generation

  • Fire OS version: 8.3.3.8

  • Build date: December 15, 2025, 2:41 PM

  • System update status: I checked for updates manually, and the device reports that it is already running the latest available version.

I am currently keeping the production build pinned to SDK 3.0.4 based on your guidance that it remains supported for production apps.

Please let me know if you would like me to provide any additional details, such as the full filtered logcat, Gradle dependency tree, install method, or a minimal reproduction project.

Thanks again,
Eugene

Hello @Evgeny_Tkachenko

Thank you for your response.
To investigate this further and identify the root cause, we’d need the following information from you:

  1. Full logcat output from a cold start of the app through the point of failure:
    adb logcat -v time > logcat_output.txt(Unfiltered - we need the complete initialization sequence)
  2. Device details & Environment:
  • Device model and OS version
  • Flutter version and engine version
  • Exact build.gradle dependency declaration for the Appstore SDK
  • Are there any other Amazon SDK dependencies in the project (DRM, Simple Sign-In, etc.)?
  • Is the app using any ContentProvider-based initialization libraries (e.g., AndroidX Startup, Firebase, or any Flutter plugin that auto-initializes via ContentProvider)?
  1. Repro:
  • Does this reproduce 100% of the time or intermittently?
  • Does it reproduce with a fresh install or only on upgrade?
  • If possible, a minimal Flutter project that reproduces the issue would help us expedite the investigation.

Once we have the above, we can trace the exact initialization path and determine next steps. In the meantime, pinning to SDK 3.0.4 is a valid approach to unblock the development.

Warm Regards,
Ivy

Hello Ivy,

Thank you for the follow-up. I’ll provide the requested details below.

1. Full logcat

I captured a full unfiltered cold-start logcat using:

adb logcat -v time > logcat_output.txt

I will attach the full logcat_output.txt file to this thread/support case (I was not allowed to upload attachments since I am a new member).

For quick reference, the key failure pattern observed in the filtered logs is:

ResourceManagerImpl: Registering resource: z2.g@f378470
ResourceManagerImpl: Registering resource: L1.e@39db3e9
ResourceManagerImpl: Registering resource: z2.g@62cc86e
register PurchasingListener: partial — send adapter active, receive adapter missing

After this partial registration state, subsequent IAP calls reject with:

You must register a PurchasingListener before invoking this operation

The important point is that this happens during a single PurchasingService.registerListener(...) call. The app is not intentionally calling registerListener(...) twice.

2. Device details and environment

  • Device model: Fire 7 (12th Generation)

  • Fire OS version: 8.3.3.8

  • Build date: December 15, 2025, 2:41 PM

  • Build number: 0030132734852

  • System update status: I checked for updates manually, and the device reports that it is already running the latest available version.

Flutter / Dart:

  • Flutter version: 3.41.6 stable

  • Flutter engine hash: 5cdd32777948fa7a648fac915f8da7120ac7e97a

  • Dart version: 3.11.4

Amazon Appstore SDK dependency:

implementation("com.amazon.device:amazon-appstore-sdk:3.0.5")

Other Amazon SDK dependencies:

  • None. The project is only using the Amazon Appstore SDK for IAP.

  • No Amazon DRM SDK.

  • No Simple Sign-In SDK.

  • No other Amazon SDK dependency.

ContentProvider / initialization libraries:

  • The app uses a custom AmazonIapInitProvider.

  • The provider is configured with android:initOrder="1000" so that it runs as early as possible.

  • The purpose of this provider is to call PurchasingService.registerListener(applicationContext, listener) before FlutterActivity startup and before any app-side purchase/product/restore calls.

  • No AndroidX Startup.

  • No Firebase.

  • No WorkManager.

  • No other known ContentProvider-based initialization library in this project.

3. Reproduction details

Reproduction status:

  • Reproduces 100% with SDK 3.0.5, 3.0.6, 3.0.8, and 3.0.9

  • Reproduces on fresh install.

  • Reproduces on release build.

  • This is not only an upgrade issue.

  • SDK 3.0.4 is the only version that allows the production purchase/restore flow to continue successfully.

Version matrix:

SDK version Result Notes
3.0.4 Works Purchase/restore flow works. Based on earlier testing, 3.0.4 appears more tolerant of the SDK’s partial registration state.
3.0.5 Fails registerListener() enters partial state; later IAP calls reject with “You must register a PurchasingListener.”
3.0.6 Fails Same pattern.
3.0.8 Fails Same pattern.
3.0.9 Fails Same pattern; internal class names differ in logs, but behavior appears equivalent.

Observed root cause from logcat:

Within one PurchasingService.registerListener(...) call, Kiwi appears to register the same resource/adapter type twice. In SDK 3.0.5–3.0.8 this appears as z2.g@...; in SDK 3.0.9 the equivalent class name appears different, such as T1.a@....

Example pattern:

ResourceManagerImpl: Registering resource: z2.g@f378470
ResourceManagerImpl: Registering resource: L1.e@39db3e9
ResourceManagerImpl: Registering resource: z2.g@62cc86e

The second registration of the same resource type results in Resource already registered, leaving the listener in a partial state. After that, calls such as getPurchaseUpdates() or purchase() fail with:

You must register a PurchasingListener before invoking this operation

4. Minimal reproduction

I do not have a minimal reproduction project ready yet, but I can prepare one if that would help the SDK team. The current app has isolated the registration path so that only the custom AmazonIapInitProvider is responsible for the initial listener registration.

Please let me know if the attached full logcat is enough to continue investigation, or if a minimal Flutter project would significantly speed up the process.

For now, I am keeping the production app pinned to SDK 3.0.4 based on your guidance that it remains supported.

Thank you again for investigating this.

Warm regards,
Eugene

Here is a link to the logs in my Google Drive https://drive.google.com/file/d/1FZJDlbDh4VhWW0f83YJecLMSdsIIjJr-/view?usp=sharing

Hello @Evgeny_Tkachenko

Thanks for the logs and environment details. We’ve tested with a basic Flutter app using SDK 3.0.5 and can confirm the issue is reproducible.

While we investigate the root cause further with the SDK team, here’s a workaround that should unblock you:

Add the following to your android/app/proguard-rules.pro:

-dontwarn com.amazon.**
-keep class com.amazon.** {*;}

And ensure your release build type references it:

buildTypes {
    release {
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
    }
}

This has been validated and should resolve the “Resource already registered” error on SDK 3.0.5+. Please let us know if this works on your end.

Note: We’re tracking the issue with the SDK team for a proper fix as well.

Warm Regards,
Ivy

Hi Ivy,

Thank you for confirming that the issue is reproducible on your side and for providing the workaround.

I’m traveling this week, so I may not be able to retest immediately, but I’ll apply the recommended ProGuard/R8 rules and try it early next week.

I’ll retest with a clean release build and report back whether the workaround resolves the Resource already registered issue and allows purchase/restore to work end-to-end.

Thanks again for investigating this and for escalating it to the SDK team for a proper fix.

Warm regards,
Eugene

The fix helped. Thank you