Paywall is popping up infrequently
complete
Kaidul Islam
Following is part of my 
InAppPurchaseManager
 class with logic of checking subscription / free trial, updating profile etc:object InAppPurchaseManager {
  private var adaptyProfile = AtomicReference<AdaptyProfile?>()
  fun initialize(context: Context) {
    val fallbackPaywallLocation = FileLocation.fromAsset(
      ADAPTY_FALLBACK_PAYWALL_FILE
    )
    Adapty.apply {
      activate(
        context,
        AdaptyConfig.Builder(apiKey = ADAPTY_API_PUBLIC_KEY)
          .build()
      )
      logShowOnboarding(
        name = ADAPTY_PAYWALL_PLACEMENT_ID,
        screenName = "first_screen",
        screenOrder = 1
      )
      setFallbackPaywalls(fallbackPaywallLocation)
      getProfile { result ->
        when (result) {
          is AdaptyResult.Success -> {
            adaptyProfile.set(result.value)
            Timber.d(adaptyProfile.toString())
          }
          is AdaptyResult.Error -> {
            val error = result.error
            Timber.d("Failed to get profile: ${error.message}")
          }
        }
      }
      setOnProfileUpdatedListener { updatedProfile ->
        adaptyProfile.set(updatedProfile)
        Timber.d("Profile updated: $adaptyProfile.")
      }
    }
  }
  fun hasPremiumOrFreeTrialAccess(): Boolean {
    return hasPremiumAccess() || hasFreeTrial()
  }
  fun hasPremiumAccess(): Boolean {
    return withProfile { profile ->
      val premiumAccess = profile.accessLevels[ADAPTY_PREMIUM_ACCESS_LEVEL_ID]
      premiumAccess?.isActive == true
    } ?: true
  }
  private fun hasFreeTrial(): Boolean {
    return withProfile { profile ->
      val premiumAccess = profile.accessLevels[ADAPTY_PREMIUM_ACCESS_LEVEL_ID]
      premiumAccess?.vendorProductId?.contains("trial", ignoreCase = true) == true
    } ?: true
  }
  private inline fun <T> withProfile(action: (profile: AdaptyProfile) -> T): T? {
    return adaptyProfile.get()?.let { profile ->
      action(profile)
    } ?: run {
      Timber.w("Profile is either not initialized yet or can't be loaded at this moment.")
      null
    }
  }
  const val ADAPTY_PAYWALL_PLACEMENT_ID = "onboarding_screen"
}
object AdaptyConstants {
  const val ADAPTY_API_PUBLIC_KEY = "<public key>"
  const val ADAPTY_PREMIUM_ACCESS_LEVEL_ID = "premium"
  const val ADAPTY_FALLBACK_PAYWALL_FILE = "android_2_11.0_fallback.json"
}
And this is how I'm checking the subscription status on the 
onResume()
 of my MainActivity
:override fun onResume() {
    super.onResume()
    if (!InAppPurchaseManager.hasPremiumOrFreeTrialAccess()) {
        val intent = Intent(this, PaywallContainerActivity::class.java).apply {
          putExtra(PaywallContainerActivity.SUBSCRIPTION_EXPIRED, true)
        }
        startActivity(intent)
      }
  }
}
I'm currently using Adapty v2.x with legacy builder:
implementation("io.adapty:android-sdk:2.11.3")
implementation("io.adapty:android-ui:2.11.1")
The issue is sometimes the 
hasPremiumOrFreeTrialAccess()
 is returning false
 which is launching the paywall activity, even though the subscription is not expired. And when I try to re-subscribe, the Google playstore is returning that I'm already subscribed (which is working as expected). My question is why the hasPremiumOrFreeTrialAccess()
 is returning false
 infrequently even though I have active subscription? Note that, the app is currently on a "closed testing" phase on Play store. My device is not added as a testing device on Adapty app settings.This is hard to reproduce as this is infrequent and I'm not sure exactly why this is happening. Please advice! Thanks in advance.
Kaidul Islam
I think I solved the problem. The issue was I was caching the AdaptyProfile instance, which was probably causing this unexpected issues. Now, I'm not holding any AdaptyProfile instance, as Adapty implicitly cache it:
object InAppPurchaseManager {
  fun initialize(context: Context) {
    val fallbackPaywallLocation = FileLocation.fromAsset(
      ADAPTY_FALLBACK_PAYWALL_FILE
    )
    Adapty.apply {
      activate(
        context,
        AdaptyConfig.Builder(apiKey = ADAPTY_API_PUBLIC_KEY)
          .build()
      )
      logShowOnboarding(
        name = ADAPTY_PAYWALL_PLACEMENT_ID,
        screenName = "first_screen",
        screenOrder = 1
      )
      setFallbackPaywalls(fallbackPaywallLocation)
      getProfile { result ->
        when (result) {
          is AdaptyResult.Success -> {
            val profile = result.value
            Timber.d("Profile fetched: $profile.")
            checkSubscription(context, profile)
          }
          is AdaptyResult.Error -> {
            val error = result.error
            Timber.d("Error fetching profile: ${error.message}")
          }
        }
      }
      setOnProfileUpdatedListener { updatedProfile ->
        Timber.d("Profile updated: $updatedProfile.")
        checkSubscription(context, updatedProfile)
      }
    }
  }
  private fun checkSubscription(context: Context, profile: AdaptyProfile) {
    if (!hasPremiumAccess(profile)) {
      val intent = Intent(context, PaywallContainerActivity::class.java).apply {
        flags =
          Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
      }
      try {
        context.startActivity(intent)
      } catch (e: Exception) {
        Timber.e("Failed to start activity: ${e.localizedMessage}")
      }
    }
  }
  fun hasPremiumAccess(profile: AdaptyProfile): Boolean { // either active subscription of free trial
    val premiumAccess = profile.accessLevels[ADAPTY_PREMIUM_ACCESS_LEVEL_ID]
    return premiumAccess?.isActive ?: false
  }
}
Adapty Support
marked this post as
complete
Kaidul Islam
I think I solved the problem. The issue was I was caching the AdaptyProfile instance, which was probably causing this unexpected issues. Now, I'm not holding any AdaptyProfile instance, as Adapty implicitly cache it:
object InAppPurchaseManager {
  fun initialize(context: Context) {
    val fallbackPaywallLocation = FileLocation.fromAsset(
      ADAPTY_FALLBACK_PAYWALL_FILE
    )
    Adapty.apply {
      activate(
        context,
        AdaptyConfig.Builder(apiKey = ADAPTY_API_PUBLIC_KEY)
          .build()
      )
      logShowOnboarding(
        name = ADAPTY_PAYWALL_PLACEMENT_ID,
        screenName = "first_screen",
        screenOrder = 1
      )
      setFallbackPaywalls(fallbackPaywallLocation)
      getProfile { result ->
        when (result) {
          is AdaptyResult.Success -> {
            val profile = result.value
            Timber.d("Profile fetched: $profile.")
            checkSubscription(context, profile)
          }
          is AdaptyResult.Error -> {
            val error = result.error
            Timber.d("Error fetching profile: ${error.message}")
          }
        }
      }
      setOnProfileUpdatedListener { updatedProfile ->
        Timber.d("Profile updated: $updatedProfile.")
        checkSubscription(context, updatedProfile)
      }
    }
  }
  private fun checkSubscription(context: Context, profile: AdaptyProfile) {
    if (!hasPremiumAccess(profile)) {
      val intent = Intent(context, PaywallContainerActivity::class.java).apply {
        flags =
          Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
      }
      try {
        context.startActivity(intent)
      } catch (e: Exception) {
        Timber.e("Failed to start activity: ${e.localizedMessage}")
      }
    }
  }
  fun hasPremiumAccess(profile: AdaptyProfile): Boolean { // either active subscription of free trial
    val premiumAccess = profile.accessLevels[ADAPTY_PREMIUM_ACCESS_LEVEL_ID]
    return premiumAccess?.isActive ?: false
  }
}
Kaidul Islam
Could you prioritize this? This is currently the only blocker for me to go to production.
Kaidul Islam
Additional detail: I'm calling 
initialize()
 at application level, as adviced on your documentation:@HiltAndroidApp
class App : Application() {
  override fun onCreate() {
    super.onCreate()
    InAppPurchaseManager.initialize(applicationContext)
  }
}
