# SDK configuration

## Initialising the SDK

The initialisation must be done as soon as possible to catch the purchase .\
On iOS, initialise the SDK in your `AppDelegate` method `didFinishLaunchingWithOptions` to allow promoted In-App Purchase and support PSD2.\
This initialisation will allow tyou to access producst prices instantly later in the app.&#x20;

{% hint style="info" %}
You will need an API Key that you can find in your App settings in the [Purchasely Console](https://purchasely.io).&#x20;
{% endhint %}

![](https://3348776246-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MHAzdlUVqKyZvwTnNIE%2F-Mb77ZrDJq3rQo1HHuRM%2F-Mb77hjNvTm8AAgYzVT7%2Fimage.png?alt=media\&token=b34e3563-7a9f-409a-b4a6-3ddd1a885898)

{% tabs %}
{% tab title="Swift" %}

```swift
import Purchasely

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    Purchasely.start(withAPIKey: "API_KEY", appUserId: "USER_ID")
	return true
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
#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" eventDelegate:nil uiDelegate:nil logLevel: LogLevelInfo];
	return YES;
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
import io.purchasely.ext.Purchasely

Purchasely.Builder(applicationContext)
    .apiKey("API_KEY")
    .logLevel(LogLevel.DEBUG) // set to warning or error for release
    .userId("USER_ID")
    .eventListener(eventListener)
    .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 ->
}
```

{% endtab %}

{% tab title="Java" %}

```java
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")
    .eventListener(this)
    .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;
});
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import Purchasely from 'react-native-purchasely';

/**
* @params String apiKey
* @params StringArray stores : may be Google, Amazon and Huawei
* @params String userId
* @params Purchasley.LogLevel logLevel
* @params boolean observerMode
**/
Purchasely.startWithAPIKey(
  'API_KEY',
  ['Google'],
  'USER_ID',
  Purchasely.logLevelDebug,
  false
);

```

{% endtab %}

{% tab title="Cordova" %}

```javascript
/**
* @params String apiKey
* @params StringArray stores : may be Google, Amazon and Huawei
* @params String userId
* @params Purchasley.LogLevel logLevel
* @params boolean observerMode
**/
Purchasely.startWithAPIKey('API_KEY', ['Google'], null, Purchasely.LogLevel.DEBUG, false);
```

{% endtab %}
{% endtabs %}

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

The `eventDelegate`/`eventListener` parameter is optional and allows you to listen to all purchases events. You should implement it at least to know when the purchase is successfull.

The `uiDelegate` / `uiListener` parameter is optional and allows you to override UI dialog presented to user in case of error or success.

The `logLevel` parameter is optional and will display logs from the SDK according to the level set. We advise you to set it to warning or error for production

The `stores` parameter (for Android apps) is optional but purchase won't work without it. You need to pass a list of stores that are enabled for your application. The first store available in the user device will be the store used to make a purchase. In this sample, Google Play Billing will be used if available in user device, Huawei Mobile Services will be used otherwise.

The `observerMode` parameter is optional and allows you to use Purchasely with another In-App purchase system to prepare a migration. More details in our dedicated [section](https://docs.purchasely.com/quick-start/observer-mode).

## Setting-up the User Id

Once your user is logged in and you can send us a userId, please do it otherwise the purchase will be tied to the device and your user won't be able to enjoy from another device. Setting it will allow you to tie a purchase to a user to use it on other devices.

This ID will be passed to the Webhook so that your backend can identify the user and unlock the access. \
If our backend made a migration of user purchases and notified your backend, we will set the refresh variable in the callback to true.

{% tabs %}
{% tab title="Swift" %}

```swift
Purchasely.userLogin(with: "123456789")
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[Purchasely userLoginWith:@"123456789"];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
Purchasely.userLogin("123456789") { refresh ->
    if (refresh) {
        //you can call your backend to refresh user information
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
Purchasely.userLogin("123456789", refresh -> {
    if(refresh) {
        //you can call your backend to refresh user information
    }
    return null;
});
```

{% endtab %}

{% tab title="React Native" %}

```javascript
Purchasely.userLogin('123456789').then((refresh) => {
  if (refresh) {
    //call your backend to refresh user information
  }
});
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
Purchasely.userLogin('user_id', refresh => { 
    if(refresh) {
        // You can call your back-end to refresh user information
    }  
});
```

{% endtab %}
{% endtabs %}

To remove the user (logged out) you can perform a :

{% tabs %}
{% tab title="Swift" %}

```swift
Purchasely.userLogout()
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[Purchasely userLogout];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
Purchasely.userLogout()
```

{% endtab %}

{% tab title="Java" %}

```java
Purchasely.userLogout();
```

{% endtab %}

{% tab title="React Native" %}

```javascript
Purchasely.userLogout();
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
Purchasely.userLogout()
```

{% endtab %}
{% endtabs %}

If your app allows anonymous purchases, keep the AppUserId to nil and have a look at [our article](https://purchasely.gitbook.io/purchasely/2.8/advanced-features/anonymous-user).

## Notifying the SDK when the app is ready / loaded

The SDK needs to display messages above your UI. It can be the continuation of a purchase started on the App Store, the result from a notification linking to our product, …

Your app needs to tell Purchasely SDK when it is ready to be covered by our UI.

This is done to handle cases like:

* a loading screen that dismisses upon completion
* an on boarding that needs to be displayed before purchasing
* a subscribe process mandatory for app usage

When your app is ready, call the following method and the SDK will handle the continuation of whatever was in progress (purchase, push message, …)

This is mandatory to be able to handle [**Promoted In-App Purchases**](https://purchasely.gitbook.io/purchasely/2.8/advanced-features/promoting-your-products/promoting-in-app-purchases) and [**Deeplinks automations**](https://purchasely.gitbook.io/purchasely/2.8/advanced-features/deeplinks-and-automations).

{% tabs %}
{% tab title="Swift" %}

```swift
// Call me in your viewDidAppear
Purchasely.isReadyToPurchase(true)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[Purchasely isReadyToPurchase: true];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
Purchasely.isReadyToPurchase = true
```

{% endtab %}

{% tab title="Java" %}

```java
Purchasely.setIsReadyToPurchase(true);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
Purchasely.isReadyToPurchase(true);
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
Purchasely.isReadyToPurchase(true);
```

{% endtab %}
{% endtabs %}

You can set it back to false when the app goes in the background when you have a screen that blocks UI in background mode and that is dismissed when the app is in foreground (like in banking apps).

## Presenting products

Purchasely handles all the presentation of your products (aka paywalls) which are configured in the back office.

You can ask for the SDK to give you the `UIViewController` / `androidx.fragment.app.Fragment`presenting the purchase by calling the following :

{% tabs %}
{% tab title="Swift" %}

```swift
let paywallCtrl = Purchasely.presentationController(with: "my_presentation_id"
                                                    completion: { (result, plan) in
    switch result {
        case .purchased:
            break
        case .restored:
            break
        case .cancelled:
            break
        @unknown default:
				    break
    }
})
present(paywallCtrl, animated: true)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
UIViewController *ctrl = [Purchasely presentationControllerWith:@"my_presentation_id"
											   completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
	switch (result) {
		case PLYProductViewControllerResultPurchased:
			break;
		case PLYProductViewControllerResultRestored:
			break;
		case PLYProductViewControllerResultCancelled:
			break;
		default:
			break;
	}
}];
[self presentViewController:ctrl animated:YES completion:nil];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
Purchasely.presentationFragment(
    presentationId = "my_presentation_id"
) { result, plan ->
    /* You can set a callback to know when your user purchased a product */
    when(result) {
        PLYProductViewResult.PURCHASED -> Log.d("Purchasely", "Purchased $plan")
        PLYProductViewResult.CANCELLED ->  Log.d("Purchasely", "Cancelled purchase of $plan")
        PLYProductViewResult.RESTORED -> Log.d("Purchasely", "Restored $plan")
    }
}

supportFragmentManager.beginTransaction()
	    .addToBackStack(null) //optional
	    .replace(R.id.inappFragment, fragment, "InAppFragment")
	    .commitAllowingStateLoss()

```

{% endtab %}

{% tab title="Java" %}

```java
Fragment fragment = Purchasely.presentationFragment("my_presentation_id", new ProductViewResultListener() {
    @Override
    public void onResult(@NotNull PLYProductViewResult result, @Nullable PLYPlan plan) {
    /* You can set a callback to know when your user purchased a product */
        switch (result) {
            case PURCHASED:
                break;
            case CANCELLED:
                break;
            case RESTORED:
                break;
        }
    }
});

getSupportFragmentManager().beginTransaction()
        .addToBackStack(null)
        .replace(R.id.inappFragment, fragment, "InAppFragment")
        .commitAllowingStateLoss();
```

{% endtab %}

{% tab title="React Native" %}

```javascript
try {
  const result = await Purchasely.presentPresentationWithIdentifier('my_presentation_id');
  console.log('Presentation View Result: ' + result.result);

  if (result.plan != null) {
    console.log('Plan Vendor ID: ' + result.plan.vendorId);
    console.log('Plan Name: ' + result.plan.name);
  }

} catch (e) {
  console.log(e);
}
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
Purchasely.presentPresentationWithIdentifier(
    'my_presentation_id',
    (callback) => {
        console.log(callback);
        if(callback.result == Purchasely.PurchaseResult.CANCELLED) {
            console.log("User cancelled purchased");
        } else {
            console.log("User purchased " + callback.plan.name);
        }
    },
    (error) => {
        console.log("Error with purchase : " + error);
    }
);
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The callback `PLYProductViewControllerResult`(iOS) / `ProductViewResultListener` (Android) is optional, you can set to null if you do not need it.
{% endhint %}

{% hint style="info" %}
You can be alerted if the purchase was made by listening to the [Notifications](https://github.com/Purchasely/Purchasely-iOS#notifications) or by implementing the optional completion block
{% endhint %}

You can also get the presentation of a specific product of plan:

{% tabs %}
{% tab title="Swift" %}

```swift
// Default presentation for a product
let paywallProductCtrl = Purchasely.productController(with: "my_product_id")
present(paywallProductCtrl, animated: true)

// Default presentation for a plan
let paywallPlanCtrl = Purchasely.planController(with: "my_plan_id")
present(paywallPlanCtrl, animated: true)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Default presentation for a product
UIViewController *paywallProductCtrl = [Purchasely productControllerFor:@"my_product_id"
																   with:nil
															 completion:nil];
[self presentViewController:paywallProductCtrl animated:YES completion:nil];

// Default presentation for a plan
UIViewController *paywallPlanCtrl = [Purchasely planControllerFor:@"my_plan_id"
												  with:nil
											completion:nil];
[self presentViewController:paywallPlanCtrl animated:YES completion:nil];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Default presentation for a product
val productFragment = Purchasely.productFragment("my_product_id") { result, plan ->
    //plan bought, restored or cancelled
}

// Default presentation for a plan
val planFragment = Purchasely.planFragment("my_plan_id") { result, plan ->
    //plan bought, restored or cancelled
}
```

{% endtab %}

{% tab title="Java" %}

```java
// Default presentation for a product
Fragment productFragment = Purchasely.productFragment("my_product_id", null, new ProductViewResultListener() {
    @Override
    public void onResult(@NotNull PLYProductViewResult result, @Nullable PLYPlan plan) {
        //plan bought, restored or cancelled
    }
});

// Default presentation for a plan
Fragment planFragment = Purchasely.planFragment("my_plan_id", null, new ProductViewResultListener() {
    @Override
    public void onResult(@NotNull PLYProductViewResult result, @Nullable PLYPlan plan) {
        //plan bought, restored or cancelled
    }
});
```

{% endtab %}

{% tab title="React Native" %}

```javascript
// Default presentation for a product
try {
  await Purchasely.presentProductWithIdentifier('my_product_id', null);
} catch (e) {
  console.log(e);
}

// Default presentation for a plan
try {
  await Purchasely.presentPlanWithIdentifier('my_plan_id', null);
} catch (e) {
  console.log(e);
}
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
// Default presentation for a product
Purchasely.presentProductWithIdentifier("my_product_id", null);

// Default presentation for a plan
Purchasely.presentPlanWithIdentifier("my_plan_id", null);
```

{% endtab %}
{% endtabs %}

## Unlock content / service once a purchase is made

Once the purchase is made to Apple Servers, registered in our systems, Purchasely sends a local `Notification` in the `NotificationCenter`. You can use it to unlock the content or refresh it.

You can catch it like this

{% tabs %}
{% tab title="Swift" %}

```swift
 NotificationCenter.default.addObserver(self, selector: #selector(reloadContent(_:)), name: .ply_purchasedSubscription, object: nil)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(reloadContent)
												 name: @"ply_purchasedSubscription"
											   object:nil];
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
Purchasely.livePurchase().observe(this) { plan: PLYPlan? -> 
    reloadContent(plan) 
}

Purchasely.purchaseListener = purchaseListener
```

{% endtab %}

{% tab title="Java" %}

```java
// You can use LiveData
Purchasely.livePurchase().observe(this, (plan) -> {
    reloadContent(plan);
});

// Or PurchaseListener
Purchasely.setPurchaseListener(purchaseListener);
```

{% endtab %}

{% tab title="ReactNative" %}

```javascript
Purchasely.addPurchasedListener(() => {
    // User has successfully purchased a product, reload content
});
```

{% endtab %}

{% tab title="Cordova" %}

```javascript
Purchasely.purchasedSubscription(() => {
	// User has successfully purchased a product, reload content
});
```

{% endtab %}
{% endtabs %}

And use it like that

{% tabs %}
{% tab title="Swift" %}

```swift
 @objc func reloadContent(_ notification: Notification) {
     // Reload the content
 }
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
- (void)reloadContent: (NSNotification *)aNotification {
    // Reload the content
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
private fun reloadContent(plan: PLYPlan?) {
    //Reload the content
}

//Instance of PurchaseListener
private val purchaseListener: PurchaseListener = object : PurchaseListener {
    override fun onPurchaseStateChanged(@NotNull state: State) {
        if (state is State.PurchaseComplete) {
            reloadContent(state.plan)
        } else if (state is State.RestorationComplete) {
            reloadContent(state.plan)
        }
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
private void reloadContent(@Nullable PLYPlan plan) {
    //Reload the content
}

//Instance of PurchaseListener
private PurchaseListener purchaseListener = new PurchaseListener() {
    @Override
    public void onPurchaseStateChanged(@NotNull State state) {
        if(state instanceof State.PurchaseComplete) {
            PLYPlan plan = ((State.PurchaseComplete) state).getPlan();
            reloadContent(plan);
        } else if(state instanceof State.RestorationComplete) {
            PLYPlan plan = ((State.RestorationComplete) state).getPlan();
            reloadContent(plan);
        }
    }
};
```

{% endtab %}
{% endtabs %}

For example, this can be done in every controller that displays premium content. That way you won't have to reload the content each time the controller is displayed unless a payment was made

## Close SDK (Android)

When done with Purchasely, you should call `close()` to remove all references to your activities. This method must only be called when you won't be using our SDK in the current user session. If you need to use our SDK again after calling `close()` then you need to call `Purchasely.Builder()` and `Purchasely.start()`.

For example you can call this method in the `onDestroy()` method of your main activity

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onDestroy() {
    super.onDestroy()
    Purchasely.close()
}
```

{% endtab %}

{% tab title="Java" %}

```java
@Override
protected void onDestroy() {
    super.onDestroy();
    Purchasely.close();
}
```

{% endtab %}

{% tab title="ReactNative" %}

```
Purchasely.close();
```

{% endtab %}

{% tab title="Cordova" %}

```
Purchasely.close();
```

{% endtab %}
{% endtabs %}
