Purchasely
4.4
4.4
  • Welcome page
  • General
    • Presentation
    • Release notes
  • Quick start
    • Console Configuration
    • SDK Implementation
    • Testing
    • Sample
  • Basic configuration
    • Console Configuration
      • Creating a new application
      • Creating your Products
        • App Store
        • Play Store
        • Huawei App Gallery
        • Amazon App Store
        • Products & Plans
      • Design your Paywalls
      • Design your Paywalls-Latest
        • Carousel
        • Carousel Flow
        • Features List
        • Features List & Plan Picker with 2 & 3 columns
        • Feature list overlay
        • Plan picker horizontal
        • Plan picker with 2 and 3 Column
    • SDK installation
      • iOS SDK
      • Android SDK
      • React Native SDK
      • Cordova SDK
      • Flutter SDK
      • Unity SDK
    • SDK configurations
      • Paywall observer mode
      • Full mode
      • StoreKit 2
      • Appendices
        • Start the SDK
        • Set User Id
        • Notify when the app is ready
        • Present paywalls
        • Unlock content / service
        • Close SDK (Android only)
    • Stripe
    • Purchasely with RevenueCat
  • S2S notifications
    • Server-to-server notifications ?
    • Apple App Store
    • Google Play Store
    • Huawei App Gallery
  • Analytics
    • Dashboards
      • Introduction
      • Live
      • Subscriptions
      • Cohorts
      • Trials
      • Events
    • Events
      • Webhook events
        • Subscription events
        • Subscription events attributes
      • SDK events
        • UI events
        • UI attributes
  • Integrations
    • Webhook
      • Receiving and understanding messages
      • Managing entitlements
      • Detailed sequence diagrams
    • Airship
    • Amplitude
    • AppsFlyer
    • Adjust
    • Piano analytics(ex AT Internet)
    • Batch
    • Branch
    • Braze
    • Clevertap
    • Customer.io
    • Firebase
    • Iterable
    • Mixpanel
    • MoEngage
    • OneSignal
    • Segment
    • Brevo(ex Sendinblue)
  • Advanced Features
    • Asynchronous paywalls
    • NEW: Promotional offers
    • Anonymous user
    • Associating content
    • Audiences
    • Customising UI
      • Errors & alerts
      • Controllers (iOS) / Fragments (Android)
    • Deeplinks automations
    • Disable placements
    • Displaying users subscriptions
    • Localization
    • Lottie animations
    • Non-subscription products
    • Paywall action interceptor
    • Promoting your products
      • Self-promotion
      • Promoting In-App Purchases
    • Purchase manually
    • Subscription status
    • Use your own paywall
  • Others
    • Frequently Asked Questions
    • Migration guides
      • Migrate to Purchasely
      • Webhook
        • Migrate to Webhook v3.0
      • SDK
        • Migrate to SDK v3.0
          • v2.2.0
          • v2.1.3
        • Migrate to SDK v3.1
        • Migrate to SDK v3.2
        • Migrate to SDK v4.0.0
  • TESTING
    • Testing Cycle Durations
Powered by GitBook

© Purchasely 2020-2023

On this page
  • Configuration
  • Display a placement
  • Unlock content

Was this helpful?

Edit on GitHub
  1. Quick start

SDK Implementation

The only required steps to get started with Purchasely

PreviousConsole ConfigurationNextTesting

Last updated 1 year ago

Was this helpful?

This is a simplified overview of our SDK implementation, you can find a more detailed one in section

Configuration

The start method must be called as soon as possible to catch every purchase / renewal.

import Purchasely

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    Purchasely.start(withAPIKey: "API_KEY,
                         appUserId: nil,
			 runningMode: .full,
			 eventDelegate: nil,
			 storekitSettings: .storeKit1, // Set your StoreKit version
			 logLevel: .debug) { (success, error) in
		print(success)
        }
	return true
}
#import <Purchasely/Purchasely-Swift.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
	// Override point for customization after application launch.

	[Purchasely startWithAPIKey:@"API_KEY"
			  appUserId:@"USER_ID"
			runningMode: PLYRunningModeFull
	              eventDelegate:nil
			 uiDelegate:nil
			storekitSettings: [StorekitSettings .storekit1]
	  paywallActionsInterceptor:nil
		           logLevel: LogLevelInfo
			initialized: nil];
	return YES;
}
import io.purchasely.ext.Purchasely

Purchasely.Builder(applicationContext)
    .apiKey("API_KEY")
    .logLevel(LogLevel.DEBUG) // set to warning or error for release
    .userId("USER_ID")
    .runningMode(PLYRunningMode.Full)
    .stores(listOf(GoogleStore(), HuaweiStore()))
    .build()

// When you are ready for Purchasely to initialize,
// you must call start() method that will grab configuration and products
// from the selected stores.
Purchasely.start { isConfigured ->
}
List<Store> stores = new ArrayList();
stores.add(new GoogleStore(), new HuaweiStore());

new Purchasely.Builder(getApplicationContext())
    .apiKey("API_KEY")
    .logLevel(LogLevel.DEBUG) // set to warning or error for release
    .userId("USER_ID")
    .runningMode(PLYRunningMode.Full.INSTANCE)
    .stores(stores)
    .build();

// When you are ready for Purchasely to initialize,
// you must call start() method that will grab configuration and products
// from the selected stores.
Purchasely.start(isConfigured -> {
    null;
});
import Purchasely from 'react-native-purchasely';

// Everything is optional except apiKey and storeKit1
// Example with default values
try {
    const configured = await Purchasely.start({
        apiKey: 'YOUR_API_KEY',
        storeKit1: false, // set to false to use StoreKit2, true to use StoreKit1,
        logLevel: LogLevels.ERROR, // set to debug in development mode to see logs
        userId: null, // if you know your user id, set it here
        runningMode: RunningMode.FULL, // select between full and paywallObserver
        androidStores: ['Google'] // default is Google, don't forget to add the dependency to the same version
     });
} catch (e) {
     console.log("Purchasely SDK not configured properly");
}
// Everything is optional except apiKey and storeKit1
// Example with default values
bool configured = await Purchasely.start(
        apiKey: 'YOUR_API_KEY',
        androidStores: ['Google'], // default is Google, don't forget to add the dependency to the same version
        storeKit1: false, // set to false to use StoreKit2, true to use StoreKit1
        logLevel: PLYLogLevel.error, // set to debug in development mode to see logs
        runningMode: PLYRunningMode.full, // select between full and paywallObserver
        userId: null, // set a user id if you have one
      );
    
if (!configured) {
        print('Purchasely SDK not configured');
        return;
}
/**
* @params String apiKey
* @params StringArray stores : may be Google, Amazon and Huawei
* @params Boolean storekit1
* @params String userId
* @params Purchasley.LogLevel logLevel
* @params Purchasely.RunningMode runningMode
**/
Purchasely.start(
    'API_KEY',                     // set your own api key
    ['Google'],                    // list of stores for Android, accepted values: Google, Huawei and Amazon
    false,                         // set to false to use StoreKit2, true to use StoreKit1
    null,                          // set your user id
    Purchasely.LogLevel.DEBUG,     // log level, should be warning or error in production
    Purchasely.RunningMode.full,   // running mode, can be paywallObserver or full
    (isConfigured) => {
        if(isConfigured) {
            // Purchasely is ready, you can display paywalls, set user attributes, start a purchase flow etc.
        }
    },
    (error) => {
        console.log(error);
    }
);
...
private PurchaselyRuntime.Purchasely _purchasely;

_purchasely = new PurchaselyRuntime.Purchasely("USER_ID",
			false, // true for StoreKit 1, false for StoreKit 2
			LogLevel.Debug,
			RunningMode.Full,
			OnPurchaselyStart,
			OnPurchaselyEvent);

The userID parameter is optional and allows you to associate the purchase to a user instead of a device.

If you want to use StoreKit 2, please make sure that you have followed first

Display a placement

Paywalls are displayed by calling a Placement.

A Placement represents a specific location in your user journey inside your app (e.g. Onboarding, Settings, Home page, Article). A placement is linked to a paywall and a single paywall can be used for different Placements. You can create as many Placements as you want, and this is the only thing that ties the app developer to the marketer.

Once the placements are defined and called from the app, you can change the displayed paywall remotely without any developer action.

let placementId = "ONBOARDING"
paywallCtrl = Purchasely.presentationController(for: placementId, contentId: contentId, loaded: { _, _, _ in
            }, completion: completion)
UIViewController *paywallCtrl = [Purchasely presentationControllerFor:@"my_placement_id"
						            contentId:@"my_content_id"
                                                            completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
}];
val paywallView = Purchasely.presentationViewForPlacement(
    context,
    placementId = "onboarding",
    onClose = {
        //TODO remove view from layout hierarchy
    },
)
        
//TODO add paywallView to layout hierarchy
Purchasely.presentationViewForPlacement(
        context,
        "onboarding",
        "content_id", //optional
        isLoaded -> null, //optional if you want to handle the onLoaded state
        () -> {
            // TODO remove view
            return null;
        },
        null
);
await Purchasely.presentPresentationForPlacement({
    placementVendorId: 'onboarding',
    contentId: 'my_content_id',
    isFullscreen: true,
});
Purchasely.presentPresentationForPlacement('onboarding');
await Purchasely.presentPresentationForPlacement('onboarding');
...
private PurchaselyRuntime.Purchasely _purchasely;

_purchasely.PresentPresentationForPlacement('placementId',
			OnPresentationResult,
			OnPresentationContentLoaded,
			OnPresentationContentClosed,
			'contentId');

Unlock content

With the method to display a placement, you get the result of the user action on the paywall.

  • Cancelled: User did not purchase a plan

  • Restored: User restored a previous purchased plan

  • Purchased: User purchased a plan which was validated by the store and your webhook

You also have as a second argument the plan bought or restored by the user, it is set to nil if no purchase was made.

let paywallCtrl = Purchasely.presentationController(
   for: "my_placement_id",
   contentId: "my_content_id",
   completion: { (result, plan) in
	switch result {
                case .purchased:
                    print("User purchased: \(plan?.name)")
                    break
                case .restored:
                    print("User restored: \(plan?.name)")
                    break
                case .cancelled:
                    break
                @unknown default:
                    break
	}												
})
UIViewController *paywallCtrl = [Purchasely presentationControllerWith:@"my_presentation_id"
															 contentId:@"my_content_id"
															completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {

}];
[self presentViewController:paywallCtrl animated:YES completion:nil];
val paywallView = Purchasely.presentationViewForPlacement(
    context,
    placementId = "onboarding",
    onClose = {
        //TODO remove view from layout hierarchy
    },
) { result, plan ->
    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}")
    }
}

//TODO add paywallView to layout hierarchy
Purchasely.presentationViewForPlacement(
        context,
        "onboarding",
        "content_id", //optional
        isLoaded -> null, //optional if you want to handle the onLoaded state
        () -> {
            // TODO remove view
            return null;
        },
        (result, plan) -> {
            switch (result) {
                case PURCHASED:
                    Log.d("Purchasely", "User purchased" + plan.getName());
                    break;
                case RESTORED:
                    Log.d("Purchasely", "User restored" + plan.getName());
                    break;
                case CANCELLED:
                    Log.d("Purchasely", "User cancelled purchase");
                    break;
            }
            return null;
        }
);
try {
  const result = await Purchasely.presentPresentationForPlacement({
    placementVendorId: 'onboarding',
    isFullscreen: true,
  });

  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:
      break;
  }
} catch (e) {
  console.error(e);
}
Purchasely.presentPresentationForPlacement(
	'onboarding', //placementId
	null, //contentId
	true, //fullscreen
	(callback) => {
		if(callback.result == Purchasely.PurchaseResult.PURCHASED) {
			console.log("User purchased " + callback.plan.name);
		} else if(callback.result == Purchasely.PurchaseResult.RESTORED) {
			console.log("User restored " + callback.plan.name);
		} else if(callback.result == Purchasely.PurchaseResult.CANCELLED) {
			console.log("User cancelled purchased");
		}
	},
	(error) => {
		console.log("Error with purchase : " + error);
	}
);
try {
  var result = await Purchasely.presentPresentationForPlacement(
      "onboarding",
      isFullscreen: true);

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

You can also preload paywalls using fetchPresentation method

SDK configurations
all required steps
asynchronously