Pre-fetching Screens

This section provides details on how to pre-fetch Screens and display them later

🚧

Minimum SDK versions

  • iOS: 3.5.0
  • Android: 3.5.0
  • ReactNative: 2.5.0
  • Cordova: 2.5.0
  • Flutter: 1.5.0
  • Unity: 4.1.0

Purchasely, by default, shows the Screen with a loading indicator while fetching the Screen from the network and preparing it for display.

Using Purchasely.fetchPresentation() method, you can pre-fetch the Screen from the network before displaying it. This provides the following benefits:

  • Display the Screen only after it has been loaded from the network
  • Handle network errors gracefully
  • Show a custom loading screen
  • Pre-load the Screen while users navigate through your app, such as during onboarding screens
  • Choose not to display a Screen for a specific placement
  • Display your own Screen

Implementation

Call Purchasely.fetchPresentation for a placement or with a presentation id

  1. An error may be returned if the presentation could not be fetched from the network.
  2. If successful, you will have a PLYPresentation instance containing the following properties:
public class PLYSubscription: NSObject {
	
  public var product: PLYProduct
  public var plan: PLYPlan
  public var subscriptionSource: PLYSubscriptionSource
  public var nextRenewalDate: Date?
  public var cancelledDate: Date?
  public var originalPurchasedDate: Date?
  public var purchasedDate: Date?
  public var offerType: PLYSubscriptionOfferType
  public var status: PLYSubscriptionStatus
  public var environment: PLYSubscriptionEnvironment
  public var storeCountry: String?
  public var isFamilyShared: Bool
  public var contentId: String?
  public var offerIdentifier: String?

}
class PLYSubscriptionData(
    val data: PLYSubscription,
    val plan: PLYPlan,
    val product: PLYProduct
)

class PLYSubscription(
    val id: String? = null,
    val storeType: StoreType? = null,
    val purchaseToken: String? = null,
    val planId: String? = null,
    val cancelledAt: String? = null,
    val nextRenewalAt: String? = null,
    val originalPurchasedAt: String? = null,
    val purchasedAt: String? = null,
    val offerType: PLYOfferType? = PLYOfferType.NONE,
    val environment: PLYEnvironment? = null,
    val storeCountry: String? = null,
    val isFamilyShared: Boolean? = null,
    val contentId: String? = null,
    val offerIdentifier: String? = null,
    val subscriptionStatus: PLYSubscriptionStatus? = null,
    val cumulatedRevenuesInUSD: Double? = null,
    val subscriptionDurationInDays: Int? = null,
    val subscriptionDurationInWeeks: Int? = null,
    val subscriptionDurationInMonths: Int? = null,
)
type PurchaselySubscription = {
  purchaseToken: string;
  subscriptionSource: SubscriptionSource;
  nextRenewalDate: string;
  cancelledDate: string;
  plan: PurchaselyPlan;
  product: PurchaselyProduct;
};
class PLYSubscription {
  String? purchaseToken;
  PLYSubscriptionSource? subscriptionSource;
  String? nextRenewalDate;
  String? cancelledDate;
  PLYPlan? plan;
  PLYProduct? product;
}
public class SubscriptionData
{
  public Plan plan;
  public Product product;
  public string contentId;
  public string environment;
  public string id;
  public bool isFamilyShared;
  public string offerIdentifier;
  public SubscriptionOfferType offerType;
  public string originalPurchasedAt;
  public string purchaseToken;
  public string purchasedDate;
  public string nextRenewalDate;
  public string cancelledDate;
  public string storeCountry;
  public StoreType storeType;
  public SubscriptionStatus status;
}
subscription.id;
subscription.storeType;
subscription.purchaseToken;
subscription.planId;
subscription.cancelledAt;
subscription.nextRenewalAt;
subscription.originalPurchasedAt;
subscription.purchasedAt;
subscription.plans
subscription.offerType;
subscription.environment;
subscription.storeCountry;
subscription.isFamilyShared;
subscription.contentId;
subscription.offerIdentifier;
subscription.subscriptionStatus;
subscription.cumulatedRevenuesInUSD;
subscription.subscriptionDurationInDays;
subscription.subscriptionDurationInWeeks;
subscription.subscriptionDurationInMonths;

A presentation can be one of the following types:

  • Normal: The default behavior, a Purchasely Screen created from our console.
  • Fallback: A Purchasely Screen, but not the one you requested, as it could not be found.
  • Deactivated: No Screen associated with that placement, possibly for a specific A/B test or an audience.
  • Client: You declared your own Screen in our console and should display it. Use the list of plans to determine which offers to display to your users.
// fetch presentation for placement
Purchasely.fetchPresentation(
    for: "onboarding",
    fetchCompletion: { presentation, error in
         // closure to get presentation and display it
         guard let presentation = presentation, error == nil else {
             print("Error while fetching presentation: \(error?.localizedDescription ?? "unknown")")
             return
         }
         
         if presentation.type == .normal || presentation.type == .fallback {
             let screenController = presentation.controller
             
             // display controller.
             
         } else if presentation.type == .deactivated {
             
             // nothing to display
             
         } else if presentation.type == .client {
             let presentationId = presentation.id
             let planIds = presentation.plans
             
             // display your own Screen
             
         }
    },
    completion: { result, plan in
        // closure when presentation controller is closed to get result
        switch result {
            case .purchased:
                print("User purchased: \(plan?.name)")
                break
            case .restored:
                print("User restored: \(plan?.name)")
                break
            case .cancelled:
                break
            @unknown default:
                break
        }
    }
)
Purchasely.fetchPresentationForPlacement("onboarding") { presentation, error ->
    if(error != null) {
        Log.d("Purchasely", "Error fetching Screen", error)
        return@fetchPresentationForPlacement
    }

    when(presentation?.type) {
        PLYPresentationType.NORMAL,
        PLYPresentationType.FALLBACK -> {
            val screenView = presentation.buildView(
                context = this@MainActivity,
                viewProperties = PLYPresentationViewProperties(
                    onClose = {
                        // TODO remove view from your layout
                    }
                )
            ) { result, plan ->
                // Screen is closed, check result to know if a purchase happened
                when(result) {
                    PLYProductViewResult.PURCHASED -> Log.d("Purchasely", "User purchased ${plan?.name}")
                    PLYProductViewResult.CANCELLED -> Log.d("Purchasely", "User cancelled purchased")
                    PLYProductViewResult.RESTORED -> Log.d("Purchasely", "User restored ${plan?.name}")
                }
            }
            
            // Display Purchasely Screen by adding screenView to your layout
        }
        PLYPresentationType.DEACTIVATED -> {
            // Nothing to display
        }
        PLYPresentationType.CLIENT -> {
            val paywallId = presentation.id
            val planIds = presentation.plans
            // Display your own Screen
        }
        else -> {
            //No Screen, it means an error was triggered
        }
    }
}
try {
  // Fetch presentation to display
  const presentation = await Purchasely.fetchPresentation({
      placementId: 'onboarding'
  })

  if(presentation.type == PLYPresentationType.DEACTIVATED) {
    // No Screen to display
    return
  }

  if(presentation.type == PLYPresentationType.CLIENT) {
    // Display my own Screen
    return
  }

  //Display Purchasely Screen
  const result = await Purchasely.presentPresentation({
    presentation: presentation
  })
  
  switch (result.result) {
    case ProductResult.PRODUCT_RESULT_PURCHASED:
    case ProductResult.PRODUCT_RESULT_RESTORED:
      if (result.plan != null) {
        console.log('User purchased ' + result.plan.name);
      }

      break;
    case ProductResult.PRODUCT_RESULT_CANCELLED:
      console.log('User cancelled');
      break;
  }

} catch (e) {
  console.error(e);
}
try {
  var presentation = await Purchasely.fetchPresentation("ONBOARDING");

  if (presentation == null) {
    print("No presentation found");
    return;
  }

  if (presentation.type == PLYPresentationType.deactivated) {
    // No Screen to display
    return;
  }

  if (presentation.type == PLYPresentationType.client) {
    // Display my own Screen
    return;
  }

  //Display Purchasely Screen

  var presentResult = await Purchasely.presentPresentation(presentation,
      isFullscreen: false);

  switch (presentResult.result) {
    case PLYPurchaseResult.cancelled:
      {
        print("User cancelled purchased");
      }
      break;
    case PLYPurchaseResult.purchased:
      {
        print("User purchased ${presentResult.plan?.name}");
      }
      break;
    case PLYPurchaseResult.restored:
      {
        print("User restored ${presentResult.plan?.name}");
      }
      break;
  }
} catch (e) {
  print(e);
}
private PurchaselyRuntime.Purchasely _purchasely;

...
_purchasely.FetchPresentation("presentationId",
			OnFetchPresentationSuccess,
			Log,
			"contentId");		
...

private void OnFetchPresentationSuccess(Presentation presentation)
{
	Log("Fetch Presentation Success.");
	LogPresentation(presentation);

	switch (presentation.presentationType)
	{
		case PresentationType.Normal:
		case PresentationType.Fallback:
				_purchasely.PresentContentForPresentation(
          	presentation,
						OnPresentationResult,
						OnPresentationContentLoaded,
						OnPresentationContentClosed,
						true
				);
			break;
		case PresentationType.Unknown:
		case PresentationType.Deactivated:
			Log($"Fetched presentation with type: {presentation.presentationType}. Will not show content.");
			break;
		case PresentationType.Client:
			paywall.Show(presentation);
			break;
	}
}