diff --git a/versioned_docs/version-3.0/adapty-paywall-builder.md b/versioned_docs/version-3.0/adapty-paywall-builder.md index 6f2c499..3e196a6 100644 --- a/versioned_docs/version-3.0/adapty-paywall-builder.md +++ b/versioned_docs/version-3.0/adapty-paywall-builder.md @@ -7,7 +7,7 @@ metadataTitle: "" import Zoom from 'react-medium-image-zoom'; import 'react-medium-image-zoom/dist/styles.css'; -We’re excited to introduce our **New Paywall Builder**, compatible with Adapty SDK v3.0 and later! This advanced no-code tool makes creating custom paywalls more intuitive and powerful than ever, allowing you to craft beautiful, engaging paywalls with ease—no technical or design expertise required! +We’re excited to introduce our **New Paywall Builder**, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later! This advanced no-code tool makes creating custom paywalls more intuitive and powerful than ever, allowing you to craft beautiful, engaging paywalls with ease—no technical or design expertise required! ## Key Features of the New Paywall Builder @@ -16,14 +16,14 @@ We’re excited to introduce our **New Paywall Builder**, compatible with Adapty - **Revamped Existing Elements**: Existing elements have been significantly improved, offering more options and capabilities to bring your paywall ideas to life. :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Design paywalls with legacy Paywall Builder](adapty-paywall-builder-legacy). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Design paywalls with legacy Paywall Builder](adapty-paywall-builder-legacy). ::: ## Structure of a paywall In the new Adapty Paywall Builder, a paywall is composed of the following: -- [**Layout**](paywall-layout-and-products): This is the foundational layer of the paywall, setting the background color and defining how products are displayed and top buttons positioned. +- [**Layout**](https://docs.adapty.io/v3.0/docs/paywall-layout-and-products): This is the foundational layer of the paywall, setting the background color and defining how products are displayed and top buttons positioned. - [**Hero Image**](paywall-head-picture): The main picture of the paywall. - **Main Area**: Here, you can place various elements like a product block, carousels, images, cards, texts, buttons, and lists. - **Footer**: Similar to the main area but it's a container that's always sticking to the bottom of the paywall on top of the main area. You can add as many elements as needed, and they will be arranged from top to to bottom inside a footer in the same order shown in the left pane. @@ -31,6 +31,10 @@ In the new Adapty Paywall Builder, a paywall is composed of the following: ## How to start designing a paywall with new Paywall Builder +:::warning +The new Paywall Builder is available for iOS and Android only and requires Adapty SDK v3.0 or later. Please make sure you've [upgraded to Adapty SDK v3.0 or later](migration-to-adapty-sdk-v3) for your new paywalls to function properly! +::: + To use the Adapty Paywall Builder: 1. Open the [**Products and Paywalls**](https://app.adapty.io/paywalls) section in the Adapty main menu and click the **Paywall** tab to open it. @@ -142,6 +146,7 @@ The elements you add to your paywall appear in the left pane of the Paywall wind - **Simple Elements**: These are individual items that cannot contain other elements. Examples include text, images, and buttons. + + + + + - **Compound Elements**: These can contain other elements or have their own structure. Examples include: - [Product lists](paywall-product-block) with products - [Carousels](paywall-carousel) with child elements @@ -160,6 +169,7 @@ The elements you add to your paywall appear in the left pane of the Paywall wind - Lists with its list items - Link blocks with links inside + + + + + **Enhancements** you can add include: 1. [Predefined tag variables for product info](paywall-builder-tag-variables) @@ -178,7 +192,7 @@ The elements you add to your paywall appear in the left pane of the Paywall wind 3. [Custom fonts](using-custom-fonts-in-paywall-builder) 4. [Localization](add-paywall-locale-in-adapty-paywall-builder) -Once configured, you can [add paywalls to placements](add-audience-paywall-ab-test) to display them in your mobile app. For more details on displaying paywalls, see [Display Paywall Builder paywalls](display-pb-paywalls). +Once configured, you can [add paywalls to placements](add-audience-paywall-ab-test) to display them in your mobile app. For more details on displaying paywalls, see [Display Paywall Builder paywalls](display-pb-paywalls). ## Customization Options diff --git a/versioned_docs/version-3.0/custom-tags-in-paywall-builder.md b/versioned_docs/version-3.0/custom-tags-in-paywall-builder.md index 6ee0f17..0963cd4 100644 --- a/versioned_docs/version-3.0/custom-tags-in-paywall-builder.md +++ b/versioned_docs/version-3.0/custom-tags-in-paywall-builder.md @@ -15,6 +15,12 @@ Custom tags are only available on AdaptyUI SDK v.2.1.0 and higher Custom tags let you avoid creating separate paywalls for different scenarios. Imagine a single paywall that adapts dynamically based on user data. For example, instead of a generic "Hello!", you could greet users personally with "Hello, John!" or "Hello, Ann!" +:::warning + +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Custom tags in legacy Paywall Builder](custom-tags-in-paywall-builder). + +::: + Here are some ways you can use custom tags: - Display the user’s name or email on the paywall. @@ -24,7 +30,7 @@ Here are some ways you can use custom tags: Custom tags help you create a flexible paywall that adapts to various situations, making your app's interface more personalized and engaging. :::warning -Make sure to add fallbacks for every line with custom tags,. +Make sure to add fallbacks for every line with custom tags. Remember to include fallbacks for every line with custom tags. @@ -81,19 +87,27 @@ To use custom tags in your mobile app, create a tagResolver object—a dictionar + ```swift let tagResolver = [ "USERNAME": "John", -] +] + +let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( + forPaywall: paywall, + tagResolver: tagResolver // or any other AdaptyTagResolver protocol implementation +) ``` + ```kotlin val customTags = mapOf("USERNAME" to "John") val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] } ``` + ```java Map customTags = new HashMap<>(); customTags.put("USERNAME", "John"); @@ -101,6 +115,26 @@ AdaptyUiTagResolver tagResolver = customTags::get; ``` + + +```dart +final customTags = { + 'USERNAME': 'John', +}; + +try { +final view = await AdaptyUI().createPaywallView( + paywall: paywall, + customTags: customTags, +); +} on AdaptyError catch (e) { + // handle the error +} catch (e) { + // handle the error +} +``` + + ```typescript diff --git a/versioned_docs/version-3.0/display-pb-paywalls.md b/versioned_docs/version-3.0/display-pb-paywalls.md index 0814aa2..bb5419b 100644 --- a/versioned_docs/version-3.0/display-pb-paywalls.md +++ b/versioned_docs/version-3.0/display-pb-paywalls.md @@ -10,15 +10,11 @@ import Details from '@site/src/components/Details'; With Adapty, you can configure paywalls remotely and define which products to display in your app, eliminating the need to hardcode products. -here are two ways to customize a paywall in the Adapty Dashboard: - -- The simple, no-code tool called the [**Paywall Builder**](adapty-paywall-builder) -- The flexible [**remote config**](customize-paywall-with-remote-config), a JSON file containing the data needed to render the paywall on the device - :::warning -This guide covers the process for **new Paywall Builder paywalls** only. The new Paywall Builder is currently supported only on iOS and Android, as it requires SDK v3.0, which is available for iOS, Android, and React Native only. Support for Flutter and Unity is coming soon. +This guide covers the process for **new Paywall Builder paywalls** only. The new Paywall Builder is currently supported only on iOS, Android, React Native, and Flutter as it requires SDK v3.0 (v3.2.0 for Flutter), which is not yet available for Unity. Support for Unity is coming soon. - For displaying **legacy Paywall Builder paywalls**, check out [Display paywalls designed with legacy Paywall Builder](display-legacy-pb-paywalls). + - For displaying **remote config paywalls**, see [Display remote config paywalls](display-remote-config-paywalls). ::: diff --git a/versioned_docs/version-3.0/facebook-ads.md b/versioned_docs/version-3.0/facebook-ads.md index 2a316be..6e7f569 100644 --- a/versioned_docs/version-3.0/facebook-ads.md +++ b/versioned_docs/version-3.0/facebook-ads.md @@ -128,20 +128,22 @@ Because of iOS IDFA changes in iOS 14.5, if you use Facebook integration, make s + ```swift import FacebookCore let builder = AdaptyProfileParameters.Builder() .with(facebookAnonymousId: AppEvents.shared.anonymousID) -Adapty.updateProfile(params: builder.build()) { error in - if error != nil { - // handle the error - } +do { + try Adapty.updateProfile(params: builder.build()) +} catch { + // handle the error } ``` + ```kotlin val builder = AdaptyProfileParameters.Builder() .withFacebookAnonymousId(AppEventsLogger.getAnonymousAppDeviceGUID(context)) @@ -154,17 +156,20 @@ Adapty.updateProfile(builder.build()) { error -> ``` + ```text There is no official SDK for Flutter ``` + ```csharp anonymousID is not available in the official SDK https://github.com/facebook/facebook-sdk-for-unity/issues/676 ``` + ```typescript import { adapty } from 'react-native-adapty'; import { AppEventsLogger } from 'react-native-fbsdk-next'; diff --git a/versioned_docs/version-3.0/fetch-paywalls-and-products.md b/versioned_docs/version-3.0/fetch-paywalls-and-products.md index bf7f3f3..0b3b0d2 100644 --- a/versioned_docs/version-3.0/fetch-paywalls-and-products.md +++ b/versioned_docs/version-3.0/fetch-paywalls-and-products.md @@ -32,6 +32,18 @@ To display the products, you need to obtain a [Paywall](paywalls) from one of yo + +```swift +do { + let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") + // the requested paywall +} catch { + // handle the error +} +``` + + + ```swift Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { @@ -44,6 +56,7 @@ Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in ``` + ```kotlin Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { @@ -60,6 +73,7 @@ Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> ``` + ```java Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { @@ -75,6 +89,7 @@ Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", result -> { ``` + ```javascript try { final paywall = await Adapty().getPaywall(id: "YOUR_PLACEMENT_ID", locale: "en"); @@ -86,6 +101,7 @@ try { ``` + ```csharp Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { @@ -98,13 +114,14 @@ Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { ``` + ```typescript try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywall(id, locale); - // the requested paywall + // the requested paywall } catch (error) { // handle the error } @@ -135,6 +152,18 @@ Once you have the paywall, you can query the product array that corresponds to i + +```swift +do { + let products = try await Adapty.getPaywallProducts(paywall: paywall) + // the requested products array +} catch { + // handle the error +} +``` + + + ```swift Adapty.getPaywallProducts(paywall: paywall) { result in switch result { @@ -147,6 +176,7 @@ Adapty.getPaywallProducts(paywall: paywall) { result in ``` + ```kotlin Adapty.getPaywallProducts(paywall) { result -> when (result) { @@ -163,6 +193,7 @@ Adapty.getPaywallProducts(paywall) { result -> ``` + ```java Adapty.getPaywallProducts(paywall, result -> { if (result instanceof AdaptyResult.Success) { @@ -178,6 +209,7 @@ Adapty.getPaywallProducts(paywall, result -> { ``` + ```javascript try { final products = await Adapty().getPaywallProducts(paywall: paywall); @@ -189,6 +221,7 @@ try { ``` + ```csharp Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { @@ -201,6 +234,7 @@ Adapty.GetPaywallProducts(paywall, (products, error) => { ``` + ```typescript try { // ...paywall @@ -221,69 +255,44 @@ Response parameters: ## Check intro offer eligibility on iOS -After getting products and before [presenting the paywall](present-remote-config-paywalls), you might want to check if the user qualifies for an introductory offer for an iOS subscription and handle cases where they don't qualify. On iOS, this usually means examining different factors like whether the user is new to the subscription or has already used an introductory offer for it. +By default, the `getPaywallProducts` method checks eligibility for introductory, promotional, and win-back offers. If you need to display products before the SDK determines offer eligibility, use the `getPaywallProductsWithoutDeterminingOffer` method instead. -You don't have to manually check these factors on iOS. Moreover, if you use the Paywall Builder, you can skip the eligibility check as it will be done automatically. However, if you do not use the Paywall Builder, use the `getProductsIntroductoryOfferEligibility(products:)` method. It automatically checks the eligibility status for each product in the array: +:::note +After showing the initial products, be sure to call the regular `getPaywallProducts` method to update the products with accurate offer eligibility information. +::: + ```swift -Adapty.getProductsIntroductoryOfferEligibility(products: products) { result in - switch result { - case .success(let eligibilities): - // update your UI - case let .failure(error): - // handle the error - } +do { + let products = try await Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) + // the requested products array without subscriptionOffer +} catch { + // handle the error } ``` - -```javascript -try { - final eligibilities = await Adapty().getProductsIntroductoryOfferEligibility(products: products); - // update your UI -} on AdaptyError catch (adaptyError) { - // handle the error -} catch (e) { - // handle the error + + +```swift +Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) { result in + switch result { + case let .success(products): + // the requested products array without subscriptionOffer + case let .failure(error): + // handle the error + } } ``` - -```csharp -Adapty.GetProductsIntroductoryOfferEligibility(products, (eligibilities, error) => { - if (eligibilities != null) { - // update your UI - } - if (error != null { - // handle the error - } -}); -``` - - - - -Next, you can see all the possible values of `AdaptyEligibility` - -| Value | Descriptions | -| :------------ | :----------------------------------------------------------------------------------- | -| eligible | The user is eligible for an intro offer, it is safe to reflect this info in your UI. | -| ineligible | The user is not eligible to get any offer, you shouldn't present it in your UI. | -| notApplicable | This product is not configured to have an offer. | - -:::warning -We urge you to be very careful with this scenario, as Apple's reviewers can check it quite rigorously. However, based on our experience with them, we conclude that the behavior of the payment environment in which they perform their checks may be somewhat different from our usual sandbox and production. -::: - ## Speed up paywall fetching with default audience paywall Typically, paywalls are fetched almost instantly, so you don’t need to worry about speeding up this process. However, in cases where you have numerous audiences and paywalls, and your users have a weak internet connection, fetching a paywall may take longer than you'd like. In such situations, you might want to display a default paywall to ensure a smooth user experience rather than showing no paywall at all. -To address this, you can use the `getPaywallForDefaultAudience` method, which fetches the paywall of the specified placement for the **All Users** audience. However, it's crucial to understand that the recommended approach is to fetch the paywall by the `getPaywall` method, as detailed in the [Fetch Paywall Information](fetch-paywalls-and-products#fetch-paywall-information) section above. +To address this, you can use the `getPaywallForDefaultAudience` method, which fetches the paywall of the specified placement for the **All Users** audience. However, it's crucial to understand that the recommended approach is to fetch the paywall by the `getPaywall` method, as detailed in the [Fetch Paywall Information](fetch-paywalls-and-products#fetch-paywall-information) section above. :::warning Why we recommend using `getPaywall` @@ -293,11 +302,23 @@ The `getPaywallForDefaultAudience` method comes with a few significant drawbacks - **Potential backward compatibility issues**: If you need to show different paywalls for different app versions (current and future), you may face challenges. You’ll either have to design paywalls that support the current (legacy) version or accept that users with the current (legacy) version might encounter issues with non-rendered paywalls. - **Loss of targeting**: All users will see the same paywall designed for the **All Users** audience, which means you lose personalized targeting (including based on countries, marketing attribution or your own custom attributes). -If you're willing to accept these drawbacks to benefit from faster paywall fetching, use the `getPaywallForDefaultAudience` method as follows. Otherwise stick to `getPaywall` described [above](fetch-paywalls-and-products#fetch-paywall-information) +If you're willing to accept these drawbacks to benefit from faster paywall fetching, use the `getPaywallForDefaultAudience` method as follows. Otherwise, stick to the `getPaywall` described [above](fetch-paywalls-and-products#fetch-paywall-information). ::: + +```swift +do { + let paywall = try await Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID") + // the requested paywall +} catch { + // handle the error +} +``` + + + ```swift Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { @@ -310,6 +331,7 @@ Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "e ``` + ```kotlin Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { @@ -326,6 +348,7 @@ Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result ``` + ```java Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { @@ -341,6 +364,7 @@ Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { ``` + ```typescript try { const id = 'YOUR_PLACEMENT_ID'; @@ -353,6 +377,12 @@ try { } ``` + :::note @@ -361,6 +391,7 @@ The `getPaywallForDefaultAudience` method is available starting from these versi - iOS: 2.11.2 - Android: 2.11.3 - React Native: 2.11.2 +- Flutter 3.2.0 The method is not yet supported in Flutter and Unity, but support will be added soon. ::: diff --git a/versioned_docs/version-3.0/flutter-handling-events-legacy.md b/versioned_docs/version-3.0/flutter-handling-events-legacy.md new file mode 100644 index 0000000..5944ae5 --- /dev/null +++ b/versioned_docs/version-3.0/flutter-handling-events-legacy.md @@ -0,0 +1,158 @@ +--- +title: "Flutter - Handle paywall events" +description: "" +metadataTitle: "" +--- + +import Zoom from 'react-medium-image-zoom'; +import 'react-medium-image-zoom/dist/styles.css'; + +Paywalls configured with the [Paywall Builder](adapty-paywall-builder) don't need extra code to make and restore purchases. However, they generate some events that your app can respond to. Those events include button presses (close buttons, URLs, product selections, and so on) as well as notifications on purchase-related actions taken on the paywall. Learn how to respond to these events below. + +:::warning + +This guide is for **legacy Paywall Builder paywalls** only which require Adapty SDK up to v2.x. For presenting paywalls in Adapty SDK v3.0 or later designed with the new Paywall Builder, see [Flutter - Handle paywall events designed with the new Paywall Builder](flutter-handling-events). + +::: + +To control or monitor processes occurring on the paywall screen within your mobile app, implement the `AdaptyUIObserver` methods and register the observer before presenting any screen: + +```javascript title="Flutter" +AdaptyUI().addObserver(this); +``` + +### User-generated events + +#### Actions + +If a user has performed some action (`close`, `openURL`, `androidSystemBack`, or `custom`, this method will be invoked: + +```javascript title="Flutter" +// You have to install url_launcher plugin in order to handle urls: +// https://pub.dev/packages/url_launcher +import 'package:url_launcher/url_launcher_string.dart'; + +void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) { + switch (action.type) { + case AdaptyUIActionType.close: + view.dismiss(); + break; + case AdaptyUIActionType.openUrl: + final urlString = action.value; + if (urlString != null) { + launchUrlString(urlString); + } + default: + break; + } +} +``` + +The following action types are supported: + +- `close` +- `openUrl` +- `custom` +- `androidSystemBack`. + +Note that at the very least you need to implement the reactions to both `close` and `openURL`. + +For example, if a user taps the close button, the action `close` will occur and you are supposed to dismiss the paywall. Refer to the [Hide Paywall Builder paywalls](hide-paywall-builder-paywalls) topic for details on dismissing a paywall screen. +Note that `AdaptyUIAction` has optional value property: look at this in the case of `openUrl` and `custom`. + +> 💡 Login Action +> +> If you have configured Login Action in the dashboard, you should implement reaction for `custom` action with value `"login"` + +#### Product selection + +If a product is selected for purchase (by a user or by the system), this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product) { +} +``` + +#### Started purchase + +If a user initiates the purchase process, this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product) { +} +``` + +#### Canceled purchase + +If a user initiates the purchase process but manually interrupts it, the function below will be invoked. Basically, this event occurs when the `Adapty.makePurchase()` function completes with the `.paymentCancelled` error: + +```javascript title="Flutter" +void paywallViewDidCancelPurchase(AdaptyUIView view, AdaptyPaywallProduct product) { +} +``` + +#### Successful purchase + +If `Adapty.makePurchase()` succeeds, this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidFinishPurchase(AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyProfile profile) { +} +``` + +We recommend dismissing the screen in that case. Refer to the [Hide Paywall Builder paywalls](hide-paywall-builder-paywalls) for details on dismissing a paywall screen. + +#### Failed purchase + +If `Adapty.makePurchase()` fails, this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidFailPurchase(AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyError error) { +} +``` + +#### Successful restore + +If `Adapty.restorePurchases()` succeeds, this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile) { +} +``` + +We recommend dismissing the screen if the user has the required `accessLevel`. Refer to the [Subscription status](subscription-status) topic to learn how to check it and to [Hide Paywall Builder paywalls](hide-paywall-builder-paywalls) topic to learn how to dismiss a paywall screen. + +#### Failed restore + +If `Adapty.restorePurchases()` fails, this method will be invoked: + +```javascript title="Flutter" +void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) { +} +``` + +### Data fetching and rendering + +#### Product loading errors + +If you don't pass the product array during the initialization, AdaptyUI will retrieve the necessary objects from the server by itself. If this operation fails, AdaptyUI will report the error by invoking this method: + +```javascript title="Flutter" +void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) { +} +``` + +#### Rendering errors + +If an error occurs during the interface rendering, it will be reported by calling this method: + +```javascript title="Flutter" +void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error) { +} +``` + +In a normal situation, such errors should not occur, so if you come across one, please let us know. \ No newline at end of file diff --git a/versioned_docs/version-3.0/flutter-handling-events.md b/versioned_docs/version-3.0/flutter-handling-events.md index f1ef828..3d2d2a4 100644 --- a/versioned_docs/version-3.0/flutter-handling-events.md +++ b/versioned_docs/version-3.0/flutter-handling-events.md @@ -2,29 +2,27 @@ title: "Flutter - Handle paywall events" description: "" metadataTitle: "" -toc_max_heading_level: 4 --- -import Zoom from 'react-medium-image-zoom'; -import 'react-medium-image-zoom/dist/styles.css'; - -Paywalls configured with the [Paywall Builder](adapty-paywall-builder) don't need extra code to make and restore purchases. However, they generate some events that your app can respond to. Those events include button presses (close buttons, URLs, product selections, and so on) as well as notifications on purchase-related actions taken on the paywall. Learn how to respond to these events below. +Paywalls configured with the [Paywall Builder](adapty-paywall-builder-legacy) don't need extra code to make and restore purchases. However, they generate some events that your app can respond to. Those events include button presses (close buttons, URLs, product selections, and so on) as well as notifications on purchase-related actions taken on the paywall. Learn how to respond to these events below. :::warning -This guide is for **legacy Paywall Builder paywalls**, which require Adapty SDK up to version 2.x. The [new Paywall Builder](adapty-paywall-builder) requires Adapty SDK 3.0 or later, which is currently not available for Flutter. + +This guide is for **new Paywall Builder paywalls** only which require Adapty SDK v3.0 or later. For presenting paywalls in Adapty SDK v2 designed with legacy Paywall Builder, see [Flutter - Handle paywall events designed with legacy Paywall Builder](flutter-handling-events-legacy). + ::: To control or monitor processes occurring on the paywall screen within your mobile app, implement the `AdaptyUIObserver` methods and register the observer before presenting any screen: ```javascript title="Flutter" -AdaptyUI().addObserver(this); +await AdaptyUI().activate(observer: this) ``` ### User-generated events #### Actions -If a user has performed some action (`close`, `openURL`, `androidSystemBack`, or `custom`, this method will be invoked: +If a user has performed some action, this method will be invoked: ```javascript title="Flutter" // You have to install url_launcher plugin in order to handle urls: @@ -32,27 +30,27 @@ If a user has performed some action (`close`, `openURL`, `androidSystemBack`, or import 'package:url_launcher/url_launcher_string.dart'; void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) { - switch (action.type) { - case AdaptyUIActionType.close: - view.dismiss(); - break; - case AdaptyUIActionType.openUrl: - final urlString = action.value; - if (urlString != null) { - launchUrlString(urlString); - } - default: - break; - } + switch (action) { + case const CloseAction(): + case const AndroidSystemBackAction(): + view.dismiss(); + break; + case OpenUrlAction(url: final url): + final Uri uri = Uri.parse(url); + launchUrl(uri, mode: LaunchMode.inAppBrowserView); + break; + default: + break; + } } ``` The following action types are supported: -- `close` -- `openUrl` -- `custom` -- `androidSystemBack`. +- `CloseAction` +- `AndroidSystemBackAction` +- `OpenUrlAction` +- `CustomAction` Note that at the very least you need to implement the reactions to both `close` and `openURL`. @@ -68,7 +66,7 @@ Note that `AdaptyUIAction` has optional value property: look at this in the case If a product is selected for purchase (by a user or by the system), this method will be invoked: ```javascript title="Flutter" -void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product) { +void paywallViewDidSelectProduct(AdaptyUIView view, String productId) { } ``` @@ -81,15 +79,6 @@ void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product } ``` -#### Canceled purchase - -If a user initiates the purchase process but manually interrupts it, the function below will be invoked. Basically, this event occurs when the `Adapty.makePurchase()` function completes with the `.paymentCancelled` error: - -```javascript title="Flutter" -void paywallViewDidCancelPurchase(AdaptyUIView view, AdaptyPaywallProduct product) { -} -``` - #### Successful purchase If `Adapty.makePurchase()` succeeds, this method will be invoked: @@ -97,7 +86,20 @@ If `Adapty.makePurchase()` succeeds, this method will be invoked: ```javascript title="Flutter" void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, - AdaptyProfile profile) { + AdaptyPurchaseResult purchaseResult) { + switch (purchaseResult) { + case AdaptyPurchaseResultSuccess(profile: final profile): + // successful purchase + break; + case AdaptyPurchaseResultPending(): + // purchase is pending + break; + case AdaptyPurchaseResultUserCancelled(): + // user cancelled the purchase + break; + default: + break; + } } ``` @@ -141,7 +143,7 @@ void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) { If you don't pass the product array during the initialization, AdaptyUI will retrieve the necessary objects from the server by itself. If this operation fails, AdaptyUI will report the error by invoking this method: ```javascript title="Flutter" -void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) { +void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyError error) { } ``` diff --git a/versioned_docs/version-3.0/flutter-present-paywalls-legacy.md b/versioned_docs/version-3.0/flutter-present-paywalls-legacy.md new file mode 100644 index 0000000..62cabcd --- /dev/null +++ b/versioned_docs/version-3.0/flutter-present-paywalls-legacy.md @@ -0,0 +1,32 @@ +--- +title: "Flutter - Present new Paywall Builder paywalls" +description: "" +metadataTitle: "" +--- + +import Zoom from 'react-medium-image-zoom'; +import 'react-medium-image-zoom/dist/styles.css'; + +If you've customized a paywall using the Paywall Builder, you don't need to worry about rendering it in your mobile app code to display it to the user. Such a paywall contains both what should be shown within the paywall and how it should be shown. + +:::warning + +This guide is for **legacy Paywall Builder paywalls**, which require Adapty SDK up to version 2.x. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builder and remote config paywalls. + +- For presenting **New Paywall Builder paywalls**, check out [Flutter - Present new Paywall Builder paywalls](flutter-present-paywalls). +- For presenting **Remote config paywalls**, see [Render paywall designed by remote config](present-remote-config-paywalls). + + . +::: + +To show a paywall, call `view.present()` method. You can use `view` from the previous step, we will introduce a new one for visibility reasons: + +```typescript title="Flutter" +try { + await view.present(); +} on AdaptyError catch (e) { + // handle the error +} catch (e) { + // handle the error +} +``` \ No newline at end of file diff --git a/versioned_docs/version-3.0/flutter-present-paywalls.md b/versioned_docs/version-3.0/flutter-present-paywalls.md index b4b7058..85cfd61 100644 --- a/versioned_docs/version-3.0/flutter-present-paywalls.md +++ b/versioned_docs/version-3.0/flutter-present-paywalls.md @@ -11,9 +11,11 @@ If you've customized a paywall using the Paywall Builder, you don't need to worr :::warning -This guide is for **legacy Paywall Builder paywalls**, which require Adapty SDK up to version 2.x. The [new Paywall Builder](adapty-paywall-builder) requires Adapty SDK 3.0 or later, which is currently not available for Flutter. +This guide is for **new Paywall Builder paywalls** only which require SDK v3.2.0 or later. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builde and remote config paywalls. + +- For presenting **Legacy Paywall Builder paywalls**, check out [Flutter - Present legacy Paywall Builder paywalls](flutter-present-paywalls-legacy). +- For presenting **Remote config paywalls**, see [Render paywall designed by remote config](present-remote-config-paywalls). -For presenting remote config paywalls, see [Render paywall designed by remote config](present-remote-config-paywalls). ::: To show a paywall, call `view.present()` method. You can use `view` from the previous step, we will introduce a new one for visibility reasons: diff --git a/versioned_docs/version-3.0/flutter-use-fallback-paywalls.md b/versioned_docs/version-3.0/flutter-use-fallback-paywalls.md index 0794019..b9e6665 100644 --- a/versioned_docs/version-3.0/flutter-use-fallback-paywalls.md +++ b/versioned_docs/version-3.0/flutter-use-fallback-paywalls.md @@ -4,18 +4,16 @@ description: "" metadataTitle: "" --- -To use fallback paywalls, call the `.setFallbackPaywalls` method. Pass the content of the fallback JSON file you [downloaded in the Adapty Dashboard](fallback-paywalls#download-fallback-paywalls-as-a-file-in-the-adapty-dashboard). Place this method in your code **before** fetching a paywall, ensuring that the mobile app possesses it when a fallback paywall is required to replace the standard one. +To use fallback paywalls, call the `.setFallbackPaywalls` method. Pass the path to the fallback JSON file you [downloaded in the Adapty Dashboard](fallback-paywalls#download-fallback-paywalls-as-a-file-in-the-adapty-dashboard). Place this method in your code **before** fetching a paywall, ensuring that the mobile app possesses it when a fallback paywall is required to replace the standard one. -```javascript title="Flutter" +```javascript title="javascript" import 'dart:async' show Future; import 'dart:io' show Platform; -import 'package:flutter/services.dart' show rootBundle; -final filePath = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; -final jsonString = await rootBundle.loadString(filePath); +final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; try { - await adapty.setFallbackPaywalls(jsonString); + await adapty.setFallbackPaywalls(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { @@ -26,4 +24,4 @@ Parameters: | Parameter | Description | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **jsonString** | The contents of the fallback JSON file you [downloaded in the Adapty Dashboard](fallback-paywalls#download-fallback-paywalls-as-a-file-in-the-adapty-dashboard). | \ No newline at end of file +| **assetId** | The path to the fallback JSON file you [downloaded in the Adapty Dashboard](fallback-paywalls#download-fallback-paywalls-as-a-file-in-the-adapty-dashboard). | diff --git a/versioned_docs/version-3.0/get-legacy-pb-paywalls.md b/versioned_docs/version-3.0/get-legacy-pb-paywalls.md index b24a494..388f15a 100644 --- a/versioned_docs/version-3.0/get-legacy-pb-paywalls.md +++ b/versioned_docs/version-3.0/get-legacy-pb-paywalls.md @@ -156,25 +156,28 @@ The result of the `createPaywallView` method can be used only once. If you need + ```swift import Adapty +import AdaptyUI -guard paywall.hasViewConfiguration else { - // use your custom logic - return -} - -AdaptyUI.getViewConfiguration(forPaywall: paywall) { result in - switch result { - case let .success(viewConfiguration): - // use loaded configuration - case let .failure(error): - // handle the error +do { + guard paywall.hasViewConfiguration else { + // use your custom logic + return } + + let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall) + + // use loaded configuration +} catch { + // handle the error } ``` + + ```kotlin if (!paywall.hasViewConfiguration) { // use your custom logic @@ -196,6 +199,7 @@ AdaptyUI.getViewConfiguration(paywall) { result -> ``` + ```java if (!paywall.hasViewConfiguration()) { // use your custom logic @@ -215,8 +219,9 @@ AdaptyUI.getViewConfiguration(paywall, result -> { ``` + ```javascript -import 'package:adapty_ui_flutter/adapty_ui_flutter.dart'; +import 'package:adapty_ui_flutter/adapty_flutter.dart'; try { final view = await AdaptyUI().createPaywallView(paywall: paywall); @@ -228,6 +233,7 @@ try { ``` + ```csharp AdaptyUI.CreatePaywallView(paywall, preloadProducts: true, (view, error) => { // use the view @@ -235,6 +241,7 @@ AdaptyUI.CreatePaywallView(paywall, preloadProducts: true, (view, error) => { ``` + ```typescript import {createPaywallView} from '@adapty/react-native-ui'; diff --git a/versioned_docs/version-3.0/get-pb-paywalls.md b/versioned_docs/version-3.0/get-pb-paywalls.md index 125159e..b3b4b09 100644 --- a/versioned_docs/version-3.0/get-pb-paywalls.md +++ b/versioned_docs/version-3.0/get-pb-paywalls.md @@ -1,5 +1,5 @@ --- -title: "Fetch new Paywall Builder paywalls and their configuration" +title: "Fetch Paywall Builder paywalls and their configuration" description: "Learn how to fetch paywalls and products for remote config paywalls in your app, crucial for displaying the right content to users based on their placements." metadataTitle: "Learn how to fetch paywalls and products for remote config paywalls in your app" --- @@ -10,17 +10,14 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import Details from '@site/src/components/Details'; -After [you designed the visual part for your paywall](adapty-paywall-builder) with Paywall Builder in the Adapty Dashboard, you can display it in your mobile app. The first step in this process is to get the paywall associated with the placement and its view configuration as described below. +After [you designed the visual part for your paywall](adapty-paywall-builder) with the new Paywall Builder in the Adapty Dashboard, you can display it in your mobile app. The first step in this process is to get the paywall associated with the placement and its view configuration as described below. :::warning - -This guide covers the process for **new Paywall Builder paywalls** only. The new Paywall Builder is currently supported only on iOS and Android, as it requires SDK v3.0, which is available for iOS, Android, and React Native only. Support for Flutter and Unity is coming soon. - -- For fetching **Legacy Paywall Builder paywalls**, check out [Fetch legacy Paywall Builder paywalls and their configuration](get-legacy-pb-paywalls). -- For fetching **Remote config paywalls**, see [Fetch paywalls and products for remote config paywalls](fetch-paywalls-and-products). - +The new Paywall Builder is available for iOS (from v3.0), Android (from v3.0), React Native (from v3.0), and Flutter (from v3.2.0) only. For presenting paywalls in Adapty SDK v2 designed with legacy Paywall Builder, see [Display paywalls designed with legacy Paywall Builder](present-pb-paywalls). ::: +Please be aware that this topic refers to Paywall Builder-customized paywalls. For guidance on fetching remote config paywalls, please refer to the [Fetch paywalls and products for remote config paywalls in your mobile app](fetch-paywalls-and-products) topic. +
Before you start displaying paywalls in your mobile app (click to expand) @@ -40,6 +37,18 @@ To get a paywall, use the `getPaywall` method: + +```swift +do { + let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID") + // the requested paywall +} catch { + // handle the error +} +``` + + + ```swift Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { @@ -52,6 +61,7 @@ Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in ``` + ```kotlin import com.adapty.utils.seconds @@ -72,6 +82,7 @@ Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en", loadTimeout = 10.seconds) ``` + ```java import com.adapty.utils.TimeInterval; @@ -90,14 +101,26 @@ Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", TimeInterval.seconds(10), result -> }); ``` + + +```javascript +try { + final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en"); + // the requested paywall +} on AdaptyError catch (adaptyError) { + // handle the error +} catch (e) { +} +``` + ```typescript try { - const id = 'YOUR_PLACEMENT_ID'; + const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; - const paywall = await adapty.getPaywall(id, locale); + const paywall = await adapty.getPaywall(placementId, locale); // the requested paywall } catch (error) { // handle the error @@ -106,6 +129,8 @@ try { +Parameters: + | Parameter | Presence | Description | |---------|--------|-----------| | **placementId** | required | The identifier of the desired [Placement](placements). This is the value you specified when creating a placement in the Adapty Dashboard. | @@ -143,24 +168,38 @@ guard paywall.hasViewConfiguration else { return } -AdaptyUI.getViewConfiguration(forPaywall: paywall) { result in - switch result { - case let .success(viewConfiguration): - // use loaded configuration - case let .failure(error): - // handle the error - } +do { + let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( + forPaywall: paywall, + products: products, + observerModeResolver: , // only for Observer Mode + tagResolver: , + timerResolver: + ) + // use loaded configuration +} catch { + // handle the error } ``` +| Parameter | Presence | Description | +| :----------------------- | :------------- | :----------------------------------------------------------- | +| **paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | +| **loadTimeout** | default: 5 sec | This value limits the timeout for this method. If the timeout is reached, cached data or local fallback will be returned.Note that in rare cases this method can timeout slightly later than specified in `loadTimeout`, since the operation may consist of different requests under the hood. | +| **products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | +| **observerModeResolver** | optional | The `AdaptyObserverModeResolver` object you've implemented in the previous step | +| **tagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](https://dev-docs.adapty.io/docs/custom-tags-in-paywall-builder) topic for more details. | +| **timerResolver** | optional | To use custom timers in your mobile app, create an object that follows the `AdaptyTimerResolver` protocol. This object defines how each custom timer should be rendered. If you prefer, you can use a `[String: Date]` dictionary directly, as it already conforms to this protocol. | + + ```kotlin if (!paywall.hasViewConfiguration) { // use your custom logic return } -AdaptyUI.getViewConfiguration(paywall) { result -> +AdaptyUI.getViewConfiguration(paywall, loadTimeout = 10.seconds) { result -> when(result) { is AdaptyResult.Success -> { val viewConfiguration = result.value @@ -173,15 +212,21 @@ AdaptyUI.getViewConfiguration(paywall) { result -> } } ``` +| Parameter | Presence | Description | +| :-------------- | :------------- | :----------------------------------------------------------- | +| **paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | +| **loadTimeout** | default: 5 sec | This value limits the timeout for this method. If the timeout is reached, cached data or local fallback will be returned.Note that in rare cases this method can timeout slightly later than specified in `loadTimeout`, since the operation may consist of different requests under the hood. | + + ```java if (!paywall.hasViewConfiguration()) { // use your custom logic return; } -AdaptyUI.getViewConfiguration(paywall, result -> { +AdaptyUI.getViewConfiguration(paywall, TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyUI.LocalizedViewConfiguration viewConfiguration = ((AdaptyResult.Success) result).getValue(); @@ -192,6 +237,49 @@ AdaptyUI.getViewConfiguration(paywall, result -> { } }); ``` +| Parameter | Presence | Description | +| :----------------------- | :------------- | :----------------------------------------------------------- | +| **paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | +| **loadTimeout** | default: 5 sec | This value limits the timeout for this method. If the timeout is reached, cached data or local fallback will be returned.Note that in rare cases this method can timeout slightly later than specified in `loadTimeout`, since the operation may consist of different requests under the hood. | + + + + +```javascript +import 'package:adapty_flutter/adapty_flutter.dart'; + +try { + final view = await AdaptyUI().createPaywallView( + paywall: paywall, + customTags: { + 'CUSTOM_TAG_NAME': 'John', + }, + customTimers: { + 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), + 'CUSTOM_TIMER_NY': DateTime(2025, 1, 1), // New Year 2025 + }, + preloadProducts: preloadProducts, + ); +} on AdaptyError catch (e) { + // handle the error +} catch (e) { + // handle the error +} +``` +| Parameter | Presence | Description | +| :---------------------------- | :------------- | :----------------------------------------------------------- | +| **paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | +| **loadTimeout** | default: 5 sec | This value limits the timeout for this method. If the timeout is reached, cached data or local fallback will be returned.Note that in rare cases this method can timeout slightly later than specified in `loadTimeout`, since the operation may consist of different requests under the hood. | +| **products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | +| **androidPersonalizedOffers** | optional | A map indicating whether the price for a specific product is personalized. The key is a string combining `basePlanId` and `vendorProductId`, separated by a `:`. If `basePlanId` is `null` or empty, only `vendorProductId` is used.

**Example**: `basePlanId:vendorProductId` or simply `vendorProductId`.

For more details, check the [[official Android Developers documentation](https://developer.android.com/google/play/billing/integrate#personalized-price).

| +| **tagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](https://dev-docs.adapty.io/docs/custom-tags-in-paywall-builder) topic for more details. | +| **timerResolver** | optional | To use custom timers in your mobile app, create an object that follows the `AdaptyTimerResolver` protocol. This object defines how each custom timer should be rendered. If you prefer, you can use a `[String: Date]` dictionary directly, as it already conforms to this protocol. | + +In the example above, `CUSTOM_TIMER_NY` and `CUSTOM_TIMER_6H` are the **Timer ID**s of developer-defined timers you set in the Adapty Dashboard. The `timerResolver` ensures your app dynamically updates each timer with the correct value—for example: + +- `CUSTOM_TIMER_NY`: The time remaining until the timer’s end, such as New Year’s Day. +- `CUSTOM_TIMER_6H`: The time left in a 6-hour period that started when the user opened the paywall. +
@@ -208,6 +296,16 @@ if (paywall.hasViewConfiguration) { //use your custom logic } ``` + +Parameters: + +| Parameter | Presence | Description | +| :------------------- | :------- | :----------------------------------------------------------- | +| **paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | +| **customTags** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | +| **timerInfo** | optional | To use custom timers in your mobile app, create an object that follows the `AdaptyTimerResolver` protocol. This object defines how each custom timer should be rendered. If you prefer, you can use a `[String: Date]` dictionary directly, as it already conforms to this protocol. | +| **prefetchProducts** | optional | Enable to optimize the display timing of products on the screen. When `true` AdaptyUI will automatically fetch the necessary products. Default: `false`. | + @@ -278,8 +376,7 @@ Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { }); ``` - - + ```typescript try { const id = 'YOUR_PLACEMENT_ID'; diff --git a/versioned_docs/version-3.0/handling-pb-paywall-events.md b/versioned_docs/version-3.0/handling-pb-paywall-events.md index 88da267..a214d0f 100644 --- a/versioned_docs/version-3.0/handling-pb-paywall-events.md +++ b/versioned_docs/version-3.0/handling-pb-paywall-events.md @@ -1,5 +1,5 @@ --- -title: "Handle new Paywall Builder paywall events" +title: "Handle paywall events" description: "" metadataTitle: "" --- @@ -11,10 +11,11 @@ Paywalls designed with the [Paywall Builder](adapty-paywall-builder) generate so In the framework-specific sections, we'll dive into details of effective management and monitoring processes taking place on the paywall screen within your mobile app using the Adapty SDK. Explore the configuration guides for every platform below: -- [iOS - Handling events](ios-handling-events) -- [Android - Handling events](android-handling-events) -- [React Native - Handling events](react-native-handling-events-1) +- [iOS](ios-handling-events) +- [Android](android-handling-events) +- [Flutter](flutter-handling-events) +- [React Native](react-native-handling-events-1) :::warning -The new Paywall Builder is available for iOS, Android, and React Native only and requires Adapty SDK v3.0 or later. For handling of legacy Paywall Builder paywall events, see [Handle paywall events designed with legacy Paywall Builder](handling-legacy-pb-paywall-events). +The new Paywall Builder is available for iOS, Android, React Native, and Flutter only and requires Adapty SDK v3.0 (v3.2.0 for Flutter) or later. For presenting paywalls in Adapty SDK v2 designed with legacy Paywall Builder, see [Handle paywall events designed with legacy Paywall Builder](handling-pb-paywall-events). ::: \ No newline at end of file diff --git a/versioned_docs/version-3.0/hide-paywall-builder-paywalls.md b/versioned_docs/version-3.0/hide-paywall-builder-paywalls.md index fb1a667..fdf7cfe 100644 --- a/versioned_docs/version-3.0/hide-paywall-builder-paywalls.md +++ b/versioned_docs/version-3.0/hide-paywall-builder-paywalls.md @@ -9,7 +9,7 @@ While Paywall Builder seamlessly handles the purchasing process upon clicking "b In native iOS and Android SDKs, you have complete control over both presenting and hiding the paywalls. However in Flutter, React Native, and Unity SDKs this works a bit differently. Learn how below. :::warning -This guide covers only hiding **new Paywall Builder paywalls** which requires Adapty SDK v3.0 or later. To learn how to hide **legacy Paywall Builder paywalls**, read the [Hide legacy Paywall Builder paywalls (on cross-platform SDKs)](hide-legacy-paywall-builder-paywalls) +This guide covers only hiding **new Paywall Builder paywalls** which require Adapty SDK v3.0 (v3.2.0 for Flutter) or later. To learn how to hide **legacy Paywall Builder paywalls**, read the [Hide legacy Paywall Builder paywalls (on cross-platform SDKs)](hide-legacy-paywall-builder-paywalls) ::: ## Dismiss a paywall screen in React Native diff --git a/versioned_docs/version-3.0/identifying-users.md b/versioned_docs/version-3.0/identifying-users.md index 307ecdd..f261102 100644 --- a/versioned_docs/version-3.0/identifying-users.md +++ b/versioned_docs/version-3.0/identifying-users.md @@ -48,10 +48,21 @@ If you don't have a user ID in the SDK configuration, you can set it later at an + +```swift +do { + try await Adapty.identify("YOUR_USER_ID") +} catch { + // handle the error +} +``` + + + ```swift Adapty.identify("YOUR_USER_ID") { error in - if error == nil { - // successful identify + if let error { + // handle the error } } ``` @@ -123,6 +134,17 @@ You can logout the user anytime by calling `.logout()` method: + +```swift +do { + try await Adapty.logout() +} catch { + // handle the error +} +``` + + + ```swift Adapty.logout { error in if error == nil { @@ -132,6 +154,7 @@ Adapty.logout { error in ``` + ```kotlin Adapty.logout { error -> if (error == null) { @@ -141,6 +164,7 @@ Adapty.logout { error -> ``` + ```java Adapty.logout(error -> { if (error == null) { @@ -150,6 +174,7 @@ Adapty.logout(error -> { ``` + ```javascript try { await Adapty().logout(); @@ -160,6 +185,7 @@ try { ``` + ```csharp Adapty.Logout((error) => { if(error == null) { @@ -169,6 +195,7 @@ Adapty.Logout((error) => { ``` + ```typescript try { await adapty.logout(); diff --git a/versioned_docs/version-3.0/ios-handling-events.md b/versioned_docs/version-3.0/ios-handling-events.md index f191d9d..d0e592c 100644 --- a/versioned_docs/version-3.0/ios-handling-events.md +++ b/versioned_docs/version-3.0/ios-handling-events.md @@ -63,9 +63,10 @@ Make sure to implement responses for all [built-in and custom actions](paywall-b If a user selects a product for purchase, this method will be invoked: ```swift title="Swift" - func paywallController(_ controller: AdaptyPaywallController, - didSelectProduct product: AdaptyPaywallProduct) { - } + func paywallController( + _ controller: AdaptyPaywallController, + didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer + ) { } ``` #### Started purchase @@ -80,27 +81,19 @@ func paywallController(_ controller: AdaptyPaywallController, It will not be invoked in Observer mode. Refer to the [iOS - Present Paywall Builder paywalls in Observer mode](ios-present-paywall-builder-paywalls-in-observer-mode) topic for details. -#### Canceled purchase - -If a user initiates the purchase process but manually interrupts it, the method below will be invoked. This event occurs when the `Adapty.makePurchase()` function completes with a `.paymentCancelled` error: - -```swift title="Swift" -func paywallController(_ controller: AdaptyPaywallController, - didCancelPurchase product: AdaptyPaywallProduct) { -} -``` - -It will not be invoked in Observer mode. Refer to the [iOS - Present Paywall Builder paywalls in Observer mode](ios-present-paywall-builder-paywalls-in-observer-mode) topic for details. - -#### Successful purchase +#### Successful or canceled purchase If `Adapty.makePurchase()` succeeds, this method will be invoked: ```swift title="Swift" -func paywallController(_ controller: AdaptyPaywallController, - didFinishPurchase product: AdaptyPaywallProduct, - purchasedInfo: AdaptyPurchasedInfo) { - controller.dismiss(animated: true) +func paywallController( + _ controller: AdaptyPaywallController, + didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer, + purchaseResult: AdaptyPurchaseResult +) { + if !purchaseResult.isPurchaseCancelled { + controller.dismiss(animated: true) + } } ``` @@ -113,10 +106,11 @@ It will not be invoked in Observer mode. Refer to the [iOS - Present Paywall Bui If `Adapty.makePurchase()` fails, this method will be invoked: ```swift title="Swift" -func paywallController(_ controller: AdaptyPaywallController, - didFailPurchase product: AdaptyPaywallProduct, - error: AdaptyError) { -} +func paywallController( + _ controller: AdaptyPaywallController, + didFailPurchase product: AdaptyPaywallProduct, + error: AdaptyError +) { } ``` It will not be invoked in Observer mode. Refer to the [iOS - Present Paywall Builder paywalls in Observer mode](ios-present-paywall-builder-paywalls-in-observer-mode) topic for details. @@ -126,9 +120,10 @@ It will not be invoked in Observer mode. Refer to the [iOS - Present Paywall Bui If `Adapty.restorePurchases()` succeeds, this method will be invoked: ```swift title="Swift" -func paywallController(_ controller: AdaptyPaywallController, - didFinishRestoreWith profile: AdaptyProfile) { -} +func paywallController( + _ controller: AdaptyPaywallController, + didFinishRestoreWith profile: AdaptyProfile +) { } ``` We recommend dismissing the screen if a the has the required `accessLevel`. Refer to the [Subscription status](subscription-status) topic to learn how to check it. @@ -138,9 +133,10 @@ We recommend dismissing the screen if a the has the required `accessLevel`. Refe If `Adapty.restorePurchases()` fails, this method will be invoked: ```swift title="Swift" -public func paywallController(_ controller: AdaptyPaywallController, - didFailRestoreWith error: AdaptyError) { -} +public func paywallController( + _ controller: AdaptyPaywallController, + didFailRestoreWith error: AdaptyError +) { } ``` ### Data fetching and rendering @@ -150,8 +146,10 @@ public func paywallController(_ controller: AdaptyPaywallController, If you don't pass the product array during the initialization, AdaptyUI will retrieve the necessary objects from the server by itself. If this operation fails, AdaptyUI will report the error by calling this method: ```swift title="Swift" -public func paywallController(_ controller: AdaptyPaywallController, - didFailLoadingProductsWith error: AdaptyError) -> Bool { +public func paywallController( + _ controller: AdaptyPaywallController, + didFailLoadingProductsWith error: AdaptyError +) -> Bool { return true } ``` @@ -163,9 +161,10 @@ If you return `true`, AdaptyUI will repeat the request after 2 seconds. If an error occurs during the interface rendering, it will be reported by this method: ```swift title="Swift" -public func paywallController(_ controller: AdaptyPaywallController, - didFailRenderingWith error: AdaptyError) { -} +public func paywallController( + _ controller: AdaptyPaywallController, + didFailRenderingWith error: AdaptyError +) { } ``` In a normal situation, such errors should not occur, so if you come across one, please let us know. @@ -187,19 +186,16 @@ var body: some View { switch action { case .close: paywallPresented = false - case .openURL(url): - // handle opening the URL (incl. for terms and privacy) - case + case let .openURL(url): + // handle opening the URL (incl. for terms and privacy) default: // handle other actions - break } }, didSelectProduct: { /* Handle the event */ }, didStartPurchase: { /* Handle the event */ }, didFinishPurchase: { product, info in /* Handle the event */ }, didFailPurchase: { product, error in /* Handle the event */ }, - didCancelPurchase: { /* Handle the event */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { /* Handle the event */ }, didFailRestore: { /* Handle the event */ }, @@ -219,9 +215,8 @@ You can register only the closure parameters you need, and omit those you do not | :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **didSelectProduct** | If a user selects a product for purchase, this parameter will be invoked. | | **didStartPurchase** | If a user initiates the purchase process, this parameter will be invoked. | -| **didFinishPurchase** | If Adapty.makePurchase() succeeds, this parameter will be invoked. | +| **didFinishPurchase** | If `Adapty.makePurchase()` succeeds or is cancelled by the user, this parameter will be invoked. | | **didFailPurchase** | If Adapty.makePurchase() fails, this parameter will be invoked. | -| **didCancelPurchase** | If a user initiates the purchase process but manually interrupts it, this parameter will be invoked. | | **didStartRestore** | If a user initiates the purchase restoration, this parameter will be invoked. | | **didFinishRestore** | If `Adapty.restorePurchases()` succeeds, this parameter will be invoked. | | **didFailRestore** | If `Adapty.restorePurchases()` fails, this parameter will be invoked. | diff --git a/versioned_docs/version-3.0/ios-present-paywall-builder-paywalls-in-observer-mode.md b/versioned_docs/version-3.0/ios-present-paywall-builder-paywalls-in-observer-mode.md index 7a36d38..a586670 100644 --- a/versioned_docs/version-3.0/ios-present-paywall-builder-paywalls-in-observer-mode.md +++ b/versioned_docs/version-3.0/ios-present-paywall-builder-paywalls-in-observer-mode.md @@ -55,18 +55,35 @@ This section refers to [Observer mode](observer-vs-full-mode) only. If you do no | onStartPurchase() | The callback should be invoked to notify AdaptyUI that the purchase is started. | | onFinishPurchase() | The callback should be invoked to notify AdaptyUI that the purchase is finished. | -2. Initialize the visual paywall you want to display by using the `.paywallController(for:products:viewConfiguration:delegate:)` method: +2. Create a paywall configuration object: + + ```swift title="Swift" + do { + let paywallConfiguration = try AdaptyUI.getPaywallConfiguration( + forPaywall: , + observerModeResolver: + ) + } catch { + // handle the error + } + ``` + + Request parameters: + + | Parameter | Presence | Description | + | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | + | **ObserverModeResolver** | required | The `AdaptyObserverModeResolver` object you've implemented in the previous step | + +3. Initialize the visual paywall you want to display by using the `.paywallController(for:products:viewConfiguration:delegate:)` method: ```swift title="Swift" import Adapty import AdaptyUI let visualPaywall = AdaptyUI.paywallController( - for: , - products: , - viewConfiguration: , + with: , delegate: - observerModeResolver: ) ``` @@ -74,12 +91,8 @@ Request parameters: | Parameter | Presence | Description | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | -| **Products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | -| **ViewConfiguration** | required | An `AdaptyUI.LocalizedViewConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getViewConfiguration(paywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | +| **Paywall Configuration** | required | An `AdaptyUI.PaywallConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | | **Delegate** | required | An `AdaptyPaywallControllerDelegate` to listen to paywall events. Refer to [Handling paywall events](ios-handling-events) topic for more details. | -| **ObserverModeResolver** | required | The `AdaptyObserverModeResolver` object you've implemented in the previous step | -| **TagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | Returns: @@ -108,9 +121,7 @@ var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, - paywall: , - configuration: , - observerModeResolver: , + paywallConfiguration: , didPerformAction: { action in switch action { case .close: @@ -131,9 +142,8 @@ Request parameters: | Parameter | Presence | Description | | :----------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | -| **Product** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | -| **Configuration** | required | An `AdaptyUI.LocalizedViewConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getViewConfiguration(paywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | +| **Paywall Configuration** | required | An `AdaptyUI.PaywallConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | +| **Products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | | **TagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | | **ObserverModeResolver** | optional | The `AdaptyObserverModeResolver` object you've implemented in the previous step | @@ -160,11 +170,11 @@ Don't forget to [Associate paywalls to purchase transactions](associate-paywalls Before you start presenting paywalls (Click to Expand) 1. Set up initial integration of Adapty [with the Google Play](initial-android) and [with the App Store](initial_ios). -2. Install and configure Adapty SDK. Make sure to set the `observerMode` parameter to `true`. Refer to our framework-specific instructions [for iOS](sdk-installation-ios#configure-adapty-sdk), [for Android](sdk-installation-android), [for Flutter](sdk-installation-flutter#configure-adapty-sdks-for-ios), [for React Native](sdk-installation-reactnative#configure-adapty-sdks), and [for Unity](sdk-installation-unity#initiate-adapty-unity-plugin-on-ios). -3. [Create products](create-product) in the Adapty Dashboard. -4. [Configure paywalls, assign products to them](create-paywall), and customize them using Paywall Builder in the Adapty Dashboard. -5. [Create placements and assign your paywalls to them](create-placement) in the Adapty Dashboard. -6. [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) in your mobile app code. +1. Install and configure Adapty SDK. Make sure to set the `observerMode` parameter to `true`. Refer to our framework-specific instructions [for iOS](sdk-installation-ios#configure-adapty-sdk), [for Android](sdk-installation-android), [for Flutter](sdk-installation-flutter#configure-adapty-sdks-for-ios), [for React Native](sdk-installation-reactnative#configure-adapty-sdks), and [for Unity](sdk-installation-unity#initiate-adapty-unity-plugin-on-ios). +2. [Create products](create-product) in the Adapty Dashboard. +3. [Configure paywalls, assign products to them](create-paywall), and customize them using Paywall Builder in the Adapty Dashboard. +4. [Create placements and assign your paywalls to them](create-placement) in the Adapty Dashboard. +5. [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) in your mobile app code.

diff --git a/versioned_docs/version-3.0/ios-present-paywalls.md b/versioned_docs/version-3.0/ios-present-paywalls.md index 124ef15..9ac4a81 100644 --- a/versioned_docs/version-3.0/ios-present-paywalls.md +++ b/versioned_docs/version-3.0/ios-present-paywalls.md @@ -11,7 +11,7 @@ If you've customized a paywall using the Paywall Builder, you don't need to worr :::warning -This guide is for **new Paywall Builder paywalls** only which require SDK v3.0. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builde, remote config paywalls, and [Observer mode](observer-vs-full-mode). +This guide is for **new Paywall Builder paywalls** only which require SDK v3.0 or later. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builde, remote config paywalls, and [Observer mode](observer-vs-full-mode). - For presenting **Legacy Paywall Builder paywalls**, check out [iOS - Present legacy Paywall Builder paywalls](ios-present-paywalls-legacy). - For presenting **Remote config paywalls**, see [Render paywall designed by remote config](present-remote-config-paywalls). @@ -21,48 +21,57 @@ This guide is for **new Paywall Builder paywalls** only which require SDK v3.0. ## Present paywalls in Swift -In order to display the visual paywall on the device screen, you must first configure it. To do this, use the method `.paywallController(for:products:introductoryOffersEligibilities:viewConfiguration:delegate:)`: - -```swift title="Swift" -import Adapty -import AdaptyUI - -do { - let visualPaywall = try AdaptyUI.paywallController( - for: , - products: , - introductoryOffersEligibilities: , - viewConfiguration: , - delegate: - ) -} catch { - // handle the error -} -``` +In order to display the visual paywall on the device screen, do the following: -Request parameters: +1. Create a paywall configuration object: -| Parameter | Presence | Description | -| :---------------------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | -| **Products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | -| **IntroductoryOffersEligibilities** | optional | Provide the dictionary of offers eligibilities to optimize the display timing of offers eligibilities on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary offers eligibilities. | -| **ViewConfiguration** | required | An `AdaptyUI.LocalizedViewConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getViewConfiguration(paywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | -| **Delegate** | required | An `AdaptyPaywallControllerDelegate` to listen to paywall events. Refer to [Handling paywall events](ios-handling-events) topic for more details. | -| **TagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | -| **TimerResolver** | optional | Pass the resolver here if you are going to use custom timer functionality. | + ```swift title="Swift" + do { + let paywallConfiguration = try AdaptyUI.getPaywallConfiguration( + forPaywall: + ) + } catch { + // handle the error + } + ``` -Returns: + Request parameters: -| Object | Description | -| :---------------------- | :--------------------------------------------------- | -| AdaptyPaywallController | An object, representing the requested paywall screen | + | Parameter | Presence | Description | + | :---------- | :------- | :----------------------------------------------------------- | + | **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | -After the object has been successfully created, you can display it on the screen of the device: +3. Initialize the visual paywall you want to display by using the `.paywallController(for:products:viewConfiguration:delegate:)` method: -```swift title="Swift" -present(visualPaywall, animated: true) -``` + ```swift title="Swift" + import Adapty + import AdaptyUI + + let visualPaywall = AdaptyUI.paywallController( + with: , + delegate: + ) + ``` + + Request parameters: + + | Parameter | Presence | Description | + | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | **Paywall Configuration** | required | An `AdaptyUI.PaywallConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | + | **Delegate** | required | An `AdaptyPaywallControllerDelegate` to listen to paywall events. Refer to [Handling paywall events](ios-handling-events) topic for more details. | + + + Returns: + + | Object | Description | + | :---------------------- | :--------------------------------------------------- | + | AdaptyPaywallController | An object, representing the requested paywall screen | + +3. After the object has been successfully created, you can display it on the screen of the device: + + ```swift title="Swift" + present(visualPaywall, animated: true) + ``` ## Present paywalls in SwiftUI @@ -95,16 +104,11 @@ var body: some View { } ``` -Request parameters: - -| Parameter | Presence | Description | -| :---------------------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Paywall** | required | An `AdaptyPaywall` object to obtain a controller for the desired paywall. | -| **Product** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | -| **IntroductoryOffersEligibilities** | optional | Provide the dictionary of offers eligibilities to optimize the display timing of offers eligibilities on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary offers eligibilities. | -| **Configuration** | required | An `AdaptyUI.LocalizedViewConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getViewConfiguration(paywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | -| **TagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | -| **TimerResolver** | optional | Pass the resolver here if you are going to use custom timer functionality. | +| Parameter | Presence | Description | +| :----------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Paywall Configuration** | required | An `AdaptyUI.PaywallConfiguration` object containing visual details of the paywall. Use the `AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` method. Refer to [Fetch Paywall Builder paywalls and their configuration](get-pb-paywalls) topic for more details. | +| **Products** | optional | Provide an array of `AdaptyPaywallProducts` to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. | +| **TagResolver** | optional | Define a dictionary of custom tags and their resolved values. Custom tags serve as placeholders in the paywall content, dynamically replaced with specific strings for personalized content within the paywall. Refer to [Custom tags in paywall builder](custom-tags-in-paywall-builder) topic for more details. | Closure parameters: @@ -118,27 +122,3 @@ Closure parameters: Refer to the [iOS - Handling events](ios-handling-events) topic for other closure parameters. -## Use developer-defined timers - -To use developer-defined timers in your mobile app, create a `timerResolver` object—a dictionary or map that pairs custom timers with the string values that will replace them when the paywall is rendered. Here's an example: - -```Swift -@MainActor -struct AdaptyTimerResolverImpl: AdaptyTimerResolver { - func timerEndAtDate(for timerId: String) -> Date { - switch timerId { - case "CUSTOM_TIMER_6H": - Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours - case "CUSTOM_TIMER_NY": - Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) - default: - Date(timeIntervalSinceNow: 3600.0) // 1 hour - } - } -} -``` - -In this example, `CUSTOM_TIMER_NY` and `CUSTOM_TIMER_6H` are the IDs of custom timers you set in the Adapty Dashboard. The `timerResolver` ensures your app dynamically updates each timer with the correct value—for example: - -- `CUSTOM_TIMER_NY`: The time remaining until the timer’s end, such as New Year’s Day. -- `CUSTOM_TIMER_6H`: The time left in a 6-hour period that started when the user opened the paywall. diff --git a/versioned_docs/version-3.0/ios-sdk-error-handling.md b/versioned_docs/version-3.0/ios-sdk-error-handling.md index baaa63d..760d787 100644 --- a/versioned_docs/version-3.0/ios-sdk-error-handling.md +++ b/versioned_docs/version-3.0/ios-sdk-error-handling.md @@ -1,5 +1,5 @@ --- -title: "iOS - Handle errors and warnings" +title: "iOS - Handle errors" description: "Learn how to effectively manage errors in iOS development with Adapty SDK's AdaptyError, featuring detailed properties for troubleshooting common issues." metadataTitle: "iOS Error Handling: AdaptyError Overview" --- @@ -23,8 +23,10 @@ Adapty SDK has its own wrapper for all kinds of errors, called `AdaptyError`. Ba It's pretty easy to check the error for specific codes and react to them accordingly. ```swift title="Swift" -Adapty.makePurchase(product: product) { result in - if result.error?.adaptyErrorCode == .paymentCancelled { +do { + let info = try await Adapty.makePurchase(product: product) +} catch { + if error.adaptyErrorCode == .paymentCancelled { // purchase was cancelled // you can offer discount to your user or remind them later } @@ -90,3 +92,4 @@ Warnings don’t need to be fixed unless they lead to errors. +| operationInterrupted | 9000 | This operation was interrupted by the system. | \ No newline at end of file diff --git a/versioned_docs/version-3.0/ios-use-fallback-paywalls.md b/versioned_docs/version-3.0/ios-use-fallback-paywalls.md index 42480d1..4917e00 100644 --- a/versioned_docs/version-3.0/ios-use-fallback-paywalls.md +++ b/versioned_docs/version-3.0/ios-use-fallback-paywalls.md @@ -6,6 +6,8 @@ metadataTitle: "" import Zoom from 'react-medium-image-zoom'; import 'react-medium-image-zoom/dist/styles.css'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; To use fallback paywalls: @@ -14,11 +16,29 @@ To use fallback paywalls: Here's an example of retrieving fallback paywall data from a locally stored JSON file named `ios_fallback.json`. -```swift title="Swift" + + + +```swift +do { + if let urlPath = Bundle.main.url(forResource: fileName, withExtension: "json") { + try await Adapty.setFallbackPaywalls(fileURL: urlPath) + } +} catch { + // handle the error +} +``` + + + +```swift if let url = Bundle.main.url(forResource: "ios_fallback", withExtension: "json") { Adapty.setFallbackPaywalls(fileURL: url) - +} ``` + + + Parameters: diff --git a/versioned_docs/version-3.0/making-purchases.md b/versioned_docs/version-3.0/making-purchases.md index 36806a4..71eeec7 100644 --- a/versioned_docs/version-3.0/making-purchases.md +++ b/versioned_docs/version-3.0/making-purchases.md @@ -31,20 +31,52 @@ In paywalls built with [Paywall Builder](adapty-paywall-builder) purchases are p + +```swift +do { + let purchaseResult = try await Adapty.makePurchase(product: product) + + switch purchaseResult { + case .userCancelled: + // handle the user cancelled purchase + case .pending: + // handle the pending purchase + case let .success(profile, transaction): + if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { + // successful purchase + } + } +} catch { + // handle the error +} +``` + + + + ```swift Adapty.makePurchase(product: product) { result in switch result { - case let .success(info): - if info.profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { - // successful purchase - } + case let .success(purchaseResult): + switch purchaseResult { + case .userCancelled: + // handle the user cancelled purchase + case .pending: + // handle the pending purchase + case let .success(profile, transaction): + if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { + // successful purchase + } + } case let .failure(error): // handle the error } } ``` + + ```kotlin Adapty.makePurchase(activity, product) { result -> when (result) { @@ -66,6 +98,7 @@ Adapty.makePurchase(activity, product) { result -> ``` + ```java Adapty.makePurchase(activity, product, result -> { if (result instanceof AdaptyResult.Success) { @@ -88,19 +121,33 @@ Adapty.makePurchase(activity, product, result -> { ``` +This snippet is valid for v.2.0 or later. + ```javascript try { - final profile = await Adapty().makePurchase(product: product); - if (profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive ?? false) { - // successful purchase - } + final purchaseResult = await Adapty().makePurchase(product: product); + switch (purchaseResult) { + case AdaptyPurchaseResultSuccess(profile: final profile): + if (profile.accessLevels['premium']?.isActive ?? false) { + // successful purchase + } + break; + case AdaptyPurchaseResultPending(): + break; + case AdaptyPurchaseResultUserCancelled(): + break; + default: + break; + } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { + // handle the error } ``` + ```csharp Adapty.MakePurchase(product, (profile, error) => { if(error != null) { @@ -116,6 +163,7 @@ Adapty.MakePurchase(product, (profile, error) => { ``` + ```typescript try { const profile = await adapty.makePurchase(product); diff --git a/versioned_docs/version-3.0/manage-paywall-ui-elements.md b/versioned_docs/version-3.0/manage-paywall-ui-elements.md index 75a42b8..1e2a2a4 100644 --- a/versioned_docs/version-3.0/manage-paywall-ui-elements.md +++ b/versioned_docs/version-3.0/manage-paywall-ui-elements.md @@ -11,7 +11,7 @@ After choosing a template, the elements of it will be displayed in the left pane :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder](adapty-paywall-builder-legacy). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder](adapty-paywall-builder-legacy). ::: diff --git a/versioned_docs/version-3.0/migration-to-adapty-sdk-v3.md b/versioned_docs/version-3.0/migration-to-adapty-sdk-v3.md index fc8f63d..1a08426 100644 --- a/versioned_docs/version-3.0/migration-to-adapty-sdk-v3.md +++ b/versioned_docs/version-3.0/migration-to-adapty-sdk-v3.md @@ -13,7 +13,7 @@ Adapty SDK v.3.0 brings support for the new exciting [Adapty Paywall Builder](ad ## Upgrade process includes -1. Upgrading to Adapty SDK v3.x (instructions differ for iOS and Android). +1. Upgrading to Adapty SDK v3.x (instructions differ for platforms). 2. Migrating your existing paywalls to the new Paywall Builder. ## Upgrading to Adapty SDK v3.x @@ -194,6 +194,110 @@ dependencies { + + +:::info + +Please note that the AdaptyUI library is deprecated and is now included as part of AdaptySDK. + +::: + +## Remove AdaptyUI SDK + +1. AdaptyUI becomes a module in Adapty SDK, so please remove `adapty_ui_flutter` from your `pubspec.yaml` file: + + ```diff + dependencies: + + adapty_flutter: ^3.2.1 + - adapty_flutter: ^2.10.3 + - adapty_ui_flutter: ^2.1.3 + ``` + +2. Run: + + ```bash title="Bash" + flutter pub get + ``` + +## Configure Adapty SDKs + +Previously, you needed to use `Adapty-Info.plist` and `AndroidManifest.xml` files for Adapty SDK configuration. + +Now, there’s no need to use additional files. Instead, you can provide all required parameters during activation. + +You only need to configure the Adapty SDK once, typically at the start of your app’s lifecycle. + +### Activate Adapty module of Adapty SDK + +1. Remove the AdaptyUI SDK import from your application as follows: + + ```diff + import 'package:adapty_flutter/adapty_flutter.dart'; + - import 'package:adapty_ui_flutter/adapty_ui_flutter.dart'; + ``` + +2. Update the Adapty SDK activation like this: + + ```diff + try { + - Adapty().activate(); + + await Adapty().activate( + + configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') + + ..withLogLevel(AdaptyLogLevel.debug) + + ..withObserverMode(false) + + ..withCustomerUserId(null) + + ..withIpAddressCollectionDisabled(false) + + ..withIdfaCollectionDisabled(false), + + ); + } catch (e) { + // handle the error + } + ``` + +Parameters: + +| Parameter | Presence | Description | +| ----------------------------------- | -------- | ------------------------------------------------------------ | +| **PUBLIC_SDK_KEY** | required | The key you can find in the **Public SDK key** field of your app settings in Adapty: [**App settings**-> **General** tab -> **API keys** subsection](https://app.adapty.io/settings/general) | +| **withLogLevel** | optional | Adapty logs errors and other crucial information to provide insight into your app's functionality. There are the following available levels:
  • error: Only errors will be logged.
  • warn: Errors and messages from the SDK that do not cause critical errors, but are worth paying attention to will be logged.
  • info: Errors, warnings, and serious information messages, such as those that log the lifecycle of various modules will be logged.
  • verbose: Any additional information that may be useful during debugging, such as function calls, API queries, etc. will be logged.
| +| **withObserverMode** | optional |

A boolean value controlling [Observer mode](observer-vs-full-mode). Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics.

The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| +| **withCustomerUserId** | optional | An identifier of the user in your system. We send it in subscription and analytical events, to attribute events to the right profile. You can also find customers by `customerUserId` in the [**Profiles and Segments**](https://app.adapty.io/profiles/users) menu. | +| **withIdfaCollectionDisabled** | optional |

Set to `true` to disable IDFA collection and sharing.

the user IP address sharing.

The default value is `false`.

For more details on IDFA collection, refer to the [Analytics integration](analytics-integration#disable-collection-of-idfa) section.

| +| **withIpAddressCollectionDisabled** | optional |

Set to `true` to disable user IP address collection and sharing.

The default value is `false`.

| + +### Activate AdaptyUI module of Adapty SDK + +You need to configure the AdaptyUI module only if you plan to use [Paywall Builder](display-pb-paywalls): + +```dart title="Dart" +try { + final mediaCache = AdaptyUIMediaCacheConfiguration( + memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB + memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart + diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB + ); + + await AdaptyUI().activate( + configuration: AdaptyUIConfiguration(mediaCache: mediaCache), + observer: , + ); +} catch (e) { + // handle the error +} +``` + +Please note that AdaptyUI configuration is optional, you can activate AdaptyUI module without its config. However, if you use the config, all parameters are required in it. + +Parameters: + +| Parameter | Presence | Description | +| :------------------------------ | :------- | :----------------------------------------------------------- | +| **memoryStorageTotalCostLimit** | required | Total cost limit of the storage in bytes. | +| **memoryStorageCountLimit** | required | The item count limit of the memory storage. | +| **diskStorageSizeLimit** | required | The file size limit on disk of the storage in bytes. 0 means no limit. | + +
+
## Migrate your paywalls to new Paywall Builder diff --git a/versioned_docs/version-3.0/mixpanel.md b/versioned_docs/version-3.0/mixpanel.md index d01c8b4..3c4af76 100644 --- a/versioned_docs/version-3.0/mixpanel.md +++ b/versioned_docs/version-3.0/mixpanel.md @@ -85,6 +85,22 @@ Use `Adapty.updateProfile()` method to set `mixpanelUserId`. If not set, Adapty + +```swift +import Mixpanel + +let builder = AdaptyProfileParameters.Builder() + .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) + +do { + try await Adapty.updateProfile(params: builder.build()) +} catch { + // handle the error +} +``` + + + ```swift import Mixpanel @@ -95,10 +111,12 @@ Adapty.updateProfile(params: builder.build()) ``` + ```kotlin val params = AdaptyProfileParameters.Builder() .withMixpanelUserId(mixpanelAPI.distinctId) .build() + Adapty.updateProfile(params) { error -> if (error != null) { // handle the error @@ -107,6 +125,7 @@ Adapty.updateProfile(params) { error -> ``` + ```javascript import 'package:mixpanel_flutter/mixpanel_flutter.dart'; @@ -117,15 +136,17 @@ final builder = AdaptyProfileParametersBuilder() await mixpanel.getDistinctId(), ); - try { - await Adapty().updateProfile(builder.build()); - } on AdaptyError catch (adaptyError) { - // handle error - } catch (e) {} +try { + await Adapty().updateProfile(builder.build()); +} on AdaptyError catch (adaptyError) { + // handle error +} catch (e) {} ``` -```csharp var builder = new Adapty.ProfileParameters.Builder(); + +```csharp +var builder = new Adapty.ProfileParameters.Builder(); builder.SetMixpanelUserId(Mixpanel.DistinctId); Adapty.UpdateProfile(builder.Build(), (error) => { @@ -134,6 +155,7 @@ Adapty.UpdateProfile(builder.Build(), (error) => { ``` + ```typescript import { adapty } from 'react-native-adapty'; import { Mixpanel } from 'mixpanel-react-native'; diff --git a/versioned_docs/version-3.0/onboarding-screens-tracking.md b/versioned_docs/version-3.0/onboarding-screens-tracking.md index 27b4e8f..d320c33 100644 --- a/versioned_docs/version-3.0/onboarding-screens-tracking.md +++ b/versioned_docs/version-3.0/onboarding-screens-tracking.md @@ -16,8 +16,27 @@ To do this, simply call the `.logShowOnboarding` function: + +```swift +do { + try await Adapty.logShowOnboarding( + name: "onboarding_name", + screenName: "first_screen", + screenOrder: 1 + ) +} catch { + // handle the error +} +``` + + + ```swift -Adapty.logShowOnboarding(name: "onboarding_name", screenName: "first_screen", screenOrder: 1) +Adapty.logShowOnboarding( + name: "onboarding_name", + screenName: "first_screen", + screenOrder: 1 +) ``` diff --git a/versioned_docs/version-3.0/onesignal.md b/versioned_docs/version-3.0/onesignal.md index e95967d..c2da413 100644 --- a/versioned_docs/version-3.0/onesignal.md +++ b/versioned_docs/version-3.0/onesignal.md @@ -205,6 +205,7 @@ val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver { ``` + ```java // PlayerID (pre-v5 OneSignal SDK) OSSubscriptionObserver osSubscriptionObserver = stateChanges -> { @@ -236,8 +237,13 @@ IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> { }); }; ``` - + + + + + + ```javascript OneSignal.shared.setSubscriptionObserver((changes) { final playerId = changes.to.userId; @@ -245,6 +251,7 @@ OneSignal.shared.setSubscriptionObserver((changes) { final builder = AdaptyProfileParametersBuilder() ..setOneSignalPlayerId(playerId); + // ..setOneSignalSubscriptionId(playerId); try { Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { @@ -257,6 +264,7 @@ OneSignal.shared.setSubscriptionObserver((changes) { ``` + ```csharp using OneSignalSDK; @@ -269,8 +277,10 @@ Adapty.UpdateProfile(builder.Build(), (error) => { // handle error }); ``` + + ```typescript import { adapty } from 'react-native-adapty'; import OneSignal from 'react-native-onesignal'; diff --git a/versioned_docs/version-3.0/paywall-builder-tag-variables.md b/versioned_docs/version-3.0/paywall-builder-tag-variables.md index c087241..f9a8cb3 100644 --- a/versioned_docs/version-3.0/paywall-builder-tag-variables.md +++ b/versioned_docs/version-3.0/paywall-builder-tag-variables.md @@ -19,7 +19,7 @@ Tag variables allow you to automatically localize these strings based on data di :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder tag variables](paywall-builder-tag-variables-legacy). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder tag variables](paywall-builder-tag-variables-legacy). ::: diff --git a/versioned_docs/version-3.0/paywall-builder-templates.md b/versioned_docs/version-3.0/paywall-builder-templates.md index 4f22339..8a68bc5 100644 --- a/versioned_docs/version-3.0/paywall-builder-templates.md +++ b/versioned_docs/version-3.0/paywall-builder-templates.md @@ -22,7 +22,7 @@ Ready-made paywall templates are professionally designed and tailored to streaml :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder templates](paywall-builder-templates-legacy). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder templates](paywall-builder-templates-legacy). ::: diff --git a/versioned_docs/version-3.0/paywall-buttons.md b/versioned_docs/version-3.0/paywall-buttons.md index efaad3b..c38f12a 100644 --- a/versioned_docs/version-3.0/paywall-buttons.md +++ b/versioned_docs/version-3.0/paywall-buttons.md @@ -14,7 +14,7 @@ A paywall button is a UI element that lets users do things like login, restore a :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Paywall texts and buttons in legacy Paywall Builder](paywall-texts-and-buttons). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Paywall texts and buttons in legacy Paywall Builder](paywall-texts-and-buttons). ::: diff --git a/versioned_docs/version-3.0/paywall-card.md b/versioned_docs/version-3.0/paywall-card.md index 84122e1..b2d87fe 100644 --- a/versioned_docs/version-3.0/paywall-card.md +++ b/versioned_docs/version-3.0/paywall-card.md @@ -22,7 +22,7 @@ A card is a paywall element that combines several other elements into a single b :::warning -Paywall cards are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 and later, available for iOS, Android, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall card functionality. +Paywall cards are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later, available for iOS, Android, Flutter, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall card functionality. ::: diff --git a/versioned_docs/version-3.0/paywall-carousel.md b/versioned_docs/version-3.0/paywall-carousel.md index a4be893..8e0c6a0 100644 --- a/versioned_docs/version-3.0/paywall-carousel.md +++ b/versioned_docs/version-3.0/paywall-carousel.md @@ -23,7 +23,7 @@ A carousel is a dynamic set of swipeable cards that can be moved left or right, :::warning -Carousels are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 and later, available for iOS, Android, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall carousel functionality. +Carousels are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later, available for iOS, Android, Flutter, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall carousel functionality. ::: diff --git a/versioned_docs/version-3.0/paywall-dark-mode.md b/versioned_docs/version-3.0/paywall-dark-mode.md index 3c106bb..f47bff7 100644 --- a/versioned_docs/version-3.0/paywall-dark-mode.md +++ b/versioned_docs/version-3.0/paywall-dark-mode.md @@ -26,7 +26,7 @@ To use the Paywall dark mode, you’ll need a paid plan: Pro, Pro+, or Enterpris /> :::warning -Dark mode is supported on iOS starting with version 3.1.0 and Android starting with version 3.1.1. Support for React Native, Flutter, and Unity is coming soon. Dark mode is also included in fallback paywalls. +Dark mode is supported on iOS starting with v3.1.0, Android starting with v3.1.1, and Flutter starting with v3.2.0. Support for React Native and Unity is coming soon. Dark mode is also included in fallback paywalls. ::: To set up dark mode for your paywall: diff --git a/versioned_docs/version-3.0/paywall-device-compatibility-preview.md b/versioned_docs/version-3.0/paywall-device-compatibility-preview.md index ea331af..e80408e 100644 --- a/versioned_docs/version-3.0/paywall-device-compatibility-preview.md +++ b/versioned_docs/version-3.0/paywall-device-compatibility-preview.md @@ -23,7 +23,7 @@ Use the drop-down menu under the preview to select different devices, providing :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder device compatibility preview](paywall-layout-and-products-legacy#device-compatibility-preview). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder device compatibility preview](paywall-layout-and-products-legacy#device-compatibility-preview). ::: diff --git a/versioned_docs/version-3.0/paywall-head-picture.md b/versioned_docs/version-3.0/paywall-head-picture.md index 44bc2d0..ddff6c4 100644 --- a/versioned_docs/version-3.0/paywall-head-picture.md +++ b/versioned_docs/version-3.0/paywall-head-picture.md @@ -11,7 +11,7 @@ The hero image is the star of your paywall, setting the tone, establishing the t :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder head picture](paywall-layout-and-products-legacy#main-image-and-sizing). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder head picture](paywall-layout-and-products-legacy#main-image-and-sizing). ::: diff --git a/versioned_docs/version-3.0/paywall-layout-and-products.md b/versioned_docs/version-3.0/paywall-layout-and-products.md index 9bb6429..920a691 100644 --- a/versioned_docs/version-3.0/paywall-layout-and-products.md +++ b/versioned_docs/version-3.0/paywall-layout-and-products.md @@ -11,7 +11,7 @@ After selecting a template for your paywall in Adapty's Paywall Builder, you can :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder paywall layout](paywall-layout-and-products-legacy#layout). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder paywall layout](paywall-layout-and-products-legacy#layout). ::: diff --git a/versioned_docs/version-3.0/paywall-product-block.md b/versioned_docs/version-3.0/paywall-product-block.md index 0308399..4da24f5 100644 --- a/versioned_docs/version-3.0/paywall-product-block.md +++ b/versioned_docs/version-3.0/paywall-product-block.md @@ -19,7 +19,7 @@ After you reviewed the list of products: :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS, Android, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder paywall products](paywall-layout-and-products-legacy#products). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Legacy Paywall Builder paywall products](paywall-layout-and-products-legacy#products). ::: diff --git a/versioned_docs/version-3.0/paywall-timer.md b/versioned_docs/version-3.0/paywall-timer.md index 92994e7..56a50d1 100644 --- a/versioned_docs/version-3.0/paywall-timer.md +++ b/versioned_docs/version-3.0/paywall-timer.md @@ -23,7 +23,7 @@ The paywall timer is a great tool for promoting special and seasonal offers with :::warning -Paywall timers are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 and later, available for iOS, Android, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall timer functionality. +Paywall timers are only available in the [new Paywall Builder](adapty-paywall-builder), which is compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later, available for iOS, Android, Flutter, and React Native. The legacy Paywall Builder with Adapty SDK v2.x or earlier does not support paywall timer functionality. ::: @@ -68,7 +68,7 @@ You can control how the timer behaves when users see it by using the **Timer mod ## How to set up developer-defined timers in your mobile app -To use developer-defined timers in your mobile app, create a `timerResolver` object—a dictionary or map that pairs custom timers with the string values that will replace them when the paywall is rendered. Here's an example: +To use custom timers in your mobile app, create an object that follows the `AdaptyTimerResolver` protocol. This object defines how each custom timer should be rendered. If you prefer, you can use a `[String: Date]` dictionary directly, as it already conforms to this protocol. Here is an example: diff --git a/versioned_docs/version-3.0/paywall-video.md b/versioned_docs/version-3.0/paywall-video.md index 615dfff..361526c 100644 --- a/versioned_docs/version-3.0/paywall-video.md +++ b/versioned_docs/version-3.0/paywall-video.md @@ -30,7 +30,7 @@ To use the Paywall hero video, you’ll need a paid plan: Pro, Pro+, or Enterpri :::warning -Hero video is supported on Adapty SDK for iOS starting with version 3.1.0 and Android starting with version 3.1.1. Support for React Native, Flutter, and Unity is coming soon. If the video isn't supported or in fallback cases, the first frame of the video will be shown instead. +Hero video is supported on Adapty SDK for iOS starting with v3.1.0, Android starting with v3.1.1, and Flutter starting with v3.2.0. Support for React Native and Unity is coming soon. If the video isn't supported or in fallback cases, the first frame of the video will be shown instead. ::: diff --git a/versioned_docs/version-3.0/present-pb-paywalls.md b/versioned_docs/version-3.0/present-pb-paywalls.md index 85e7928..9be9e78 100644 --- a/versioned_docs/version-3.0/present-pb-paywalls.md +++ b/versioned_docs/version-3.0/present-pb-paywalls.md @@ -1,5 +1,5 @@ --- -title: "Present new Paywall Builder paywalls" +title: "Present Paywall Builder paywalls" description: "" metadataTitle: "" --- @@ -17,12 +17,5 @@ For detailed guidance on presenting paywalls within different frameworks, please - [React Native](react-native-present-paywalls) :::warning - -This guide covers the process for **new Paywall Builder paywalls** only. The new Paywall Builder is currently supported only on iOS and Android, as it requires SDK v3.0, which is available for iOS, Android, and React Native only. Support for Flutter and Unity is coming soon. - -- For presenting **legacy Paywall Builder paywalls**, check out [Present legacy Paywall Builder paywalls and their configuration](present-legacy-pb-paywalls). - -- For presenting **remote config paywalls**, see [Render paywall designed by remote config](present-remote-config-paywalls). -- For presenting observer mode paywalls, see [Implement Observer mode](implement-observer-mode). - -::: +The new Paywall Builder is available for iOS (from v3.0), Android (from v3.0), React Native (from v3.0), and Flutter (from v3.2.0) only. For presenting paywalls in Adapty SDK v2 designed with legacy Paywall Builder, see [Display paywalls designed with legacy Paywall Builder](present-pb-paywalls). +::: \ No newline at end of file diff --git a/versioned_docs/version-3.0/present-remote-config-paywalls.md b/versioned_docs/version-3.0/present-remote-config-paywalls.md index d647abe..96799ca 100644 --- a/versioned_docs/version-3.0/present-remote-config-paywalls.md +++ b/versioned_docs/version-3.0/present-remote-config-paywalls.md @@ -17,16 +17,33 @@ Don't forget to [check if a user is eligible for an introductory offer in iOS](f To get a remote config of a paywall, access the `remoteConfig` property and extract the needed values. + + +```swift +do { + let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") + let headerText = paywall.remoteConfig?.dictionary?["header_text"] as? String +} catch { + // handle the error +} +``` + + + + ```swift -Adapty.getPaywall("YOUR_PLACEMENT_ID") { result in +Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") { result in let paywall = try? result.get() let headerText = paywall?.remoteConfig?.dictionary?["header_text"] as? String } ``` + + + ```kotlin Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> when (result) { @@ -41,8 +58,10 @@ Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> } } ``` + + ```java Adapty.getPaywall("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { diff --git a/versioned_docs/version-3.0/react-native-present-paywalls.md b/versioned_docs/version-3.0/react-native-present-paywalls.md index a33c571..0f04002 100644 --- a/versioned_docs/version-3.0/react-native-present-paywalls.md +++ b/versioned_docs/version-3.0/react-native-present-paywalls.md @@ -2,6 +2,7 @@ title: "React Native - Present new Paywall Builder paywalls" description: "" metadataTitle: "" + --- import Zoom from 'react-medium-image-zoom'; @@ -11,7 +12,7 @@ If you've customized a paywall using the Paywall Builder, you don't need to worr :::warning -This guide is for **new Paywall Builder paywalls** only which require SDK v3.0. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builder and remote config paywalls. +This guide is for **new Paywall Builder paywalls** only which require SDK v3.0 or later. The process for presenting paywalls differs for paywalls designed with different versions of Paywall Builder and remote config paywalls. - For presenting **legacy Paywall Builder paywalls**, check out [React Native - Present Paywall Builder paywalls](react-native-present-paywalls-legacy). - For presenting **remote config paywalls**, see [Render paywall designed by remote config](present-remote-config-paywalls). @@ -45,3 +46,4 @@ let timerInfo = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } view = await createPaywallView(paywall, { timerInfo }) ``` +In this example, `CUSTOM_TIMER_NY` is the **Timer ID** of the developer-defined timer you set in the Adapty dashboard. The `timerResolver` ensures your app dynamically updates the timer with the correct value—like `13d 09h 03m 34s` (calculated as the timer’s end time, such as New Year’s Day, minus the current time). diff --git a/versioned_docs/version-3.0/restore-purchase.md b/versioned_docs/version-3.0/restore-purchase.md index 9910f7f..c7efe6c 100644 --- a/versioned_docs/version-3.0/restore-purchase.md +++ b/versioned_docs/version-3.0/restore-purchase.md @@ -19,11 +19,25 @@ To restore a purchase if you do not use the [Paywall Builder](adapty-paywall-bui + +```swift +do { + let profile = try await Adapty.restorePurchases() + if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { + // successful access restore + } +} catch { + // handle the error +} +``` + + + ```swift Adapty.restorePurchases { [weak self] result in switch result { case let .success(profile): - if info.profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { + if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } case let .failure(error): @@ -33,6 +47,7 @@ Adapty.restorePurchases { [weak self] result in ``` + ```kotlin Adapty.restorePurchases { result -> when (result) { @@ -52,6 +67,7 @@ Adapty.restorePurchases { result -> ``` + ```java Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { @@ -72,6 +88,7 @@ Adapty.restorePurchases(result -> { ``` + ```javascript try { final profile = await Adapty().restorePurchases(); @@ -85,25 +102,27 @@ try { ``` + ```csharp Adapty.RestorePurchases((profile, error) => { if (error != null) { // handle the error - return; - } + return; + } - var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; - if (accessLevel != null && accessLevel.IsActive) { - // restore access - } + var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; + if (accessLevel != null && accessLevel.IsActive) { + // restore access + } }); ``` + ```typescript try { const profile = await adapty.restorePurchases(); - const isSubscribed = profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; + const isSubscribed = profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // restore access diff --git a/versioned_docs/version-3.0/sdk-installation-flutter.md b/versioned_docs/version-3.0/sdk-installation-flutter.md index cab74d9..50ccdc3 100644 --- a/versioned_docs/version-3.0/sdk-installation-flutter.md +++ b/versioned_docs/version-3.0/sdk-installation-flutter.md @@ -4,6 +4,111 @@ description: "Discover step-by-step instructions for installing and configuring metadataTitle: "Flutter - Adapty SDK Installation and Configuration Guide" --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + +Adapty SDK includes two key modules for seamless integration into your mobile app: + +- **Core Adapty**: This essential SDK is required for Adapty to function properly in your app. +- **AdaptyUI**: This module is required if you’re using the Adapty Paywall Builder—a no-code, user-friendly tool for creating cross-platform paywalls. With a visual constructor right in the dashboard, you can build paywalls that run natively on devices and are designed to deliver high performance with minimal effort. + The module is installed automatically with the Adapty SDK, but you can leave it deactivated if you don’t need it. + +:::danger +Go through the release checklist before releasing your app + +Before releasing your application, make sure to carefully review the [Release Checklist](release-checklist) thoroughly. This checklist ensures that you've completed all necessary steps and provides criteria for evaluating the success of your integration. +::: + +## Install Adapty SDKs + +1. Add Adapty and AdaptyUI to your `pubspec.yaml` file: + + ```yaml title="pubspec.yaml" + dependencies: + adapty_flutter: ^3.2.1 + ``` + +2. Run: + + ```bash title="Bash" + flutter pub get + ``` + +## Configure Adapty SDKs + +You only need to configure the Adapty SDK once, typically early in your app's lifecycle. + +### Activate Adapty module of Adapty SDK + +1. Import Adapty SDKs in your application in the following way: + + ```dart title="Dart" + import 'package:adapty_flutter/adapty_flutter.dart'; + ``` + +2. Activate Adapty SDK with the following code: + + ```dart title="Dart" + try { + await Adapty().activate( + configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') + ..withLogLevel(AdaptyLogLevel.debug) + ..withObserverMode(false) + ..withCustomerUserId(null) + ..withIpAddressCollectionDisabled(false) + ..withIdfaCollectionDisabled(false), + ); + } catch (e) { + // handle the error + } + ``` + +Parameters: + +| Parameter | Presence | Description | +| ----------------------------------- | -------- | ------------------------------------------------------------ | +| **PUBLIC_SDK_KEY** | required | The key you can find in the **Public SDK key** field of your app settings in Adapty: [**App settings**-> **General** tab -> **API keys** subsection](https://app.adapty.io/settings/general) | +| **withLogLevel** | optional | Adapty logs errors and other crucial information to provide insight into your app's functionality. There are the following available levels:
  • error: Only errors will be logged.
  • warn: Errors and messages from the SDK that do not cause critical errors, but are worth paying attention to will be logged.
  • info: Errors, warnings, and serious information messages, such as those that log the lifecycle of various modules will be logged.
  • verbose: Any additional information that may be useful during debugging, such as function calls, API queries, etc. will be logged.
| +| **withObserverMode** | optional |

A boolean value controlling [Observer mode](observer-vs-full-mode). Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics.

The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| +| **withCustomerUserId** | optional | An identifier of the user in your system. We send it in subscription and analytical events, to attribute events to the right profile. You can also find customers by `customerUserId` in the [**Profiles and Segments**](https://app.adapty.io/profiles/users) menu. | +| **withIdfaCollectionDisabled** | optional |

Set to `true` to disable IDFA collection and sharing.

the user IP address sharing.

The default value is `false`.

For more details on IDFA collection, refer to the [Analytics integration](analytics-integration#disable-collection-of-idfa) section.

| +| **withIpAddressCollectionDisabled** | optional |

Set to `true` to disable user IP address collection and sharing.

The default value is `false`.

| + +### Activate AdaptyUI module of Adapty SDK + +You need to configure the AdaptyUI module only if you plan to use [Paywall Builder](display-pb-paywalls) and have [installed AdaptyUI module](sdk-installation-ios#install-sdks-via-cocoapods): + +```dart title="Dart" +try { + final mediaCache = AdaptyUIMediaCacheConfiguration( + memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB + memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart + diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB + ); + + await AdaptyUI().activate( + configuration: AdaptyUIConfiguration(mediaCache: mediaCache), + observer: , + ); +} catch (e) { + // handle the error +} +``` + +Please note that AdaptyUI configuration is optional, you can activate AdaptyUI module without its config. However, if you use the config, all parameters are required in it. + +Parameters: + +| Parameter | Presence | Description | +| :------------------------------ | :------- | :----------------------------------------------------------- | +| **memoryStorageTotalCostLimit** | required | Total cost limit of the storage in bytes. | +| **memoryStorageCountLimit** | required | The item count limit of the memory storage. | +| **diskStorageSizeLimit** | required | The file size limit on disk of the storage in bytes. 0 means no limit. | + +
+ Adapty comprises two crucial SDKs for seamless integration into your mobile app: - Core **AdaptySDK**: This is a fundamental, mandatory SDK necessary for the proper functioning of Adapty within your app. @@ -18,12 +123,6 @@ Please consult the compatibility table below to choose the correct pair of Adapt | 2.10.1 | 2.1.2 | | 2.10.3 | 2.1.3 | -:::danger -Go through the release checklist before releasing your app - -Before releasing your application, make sure to carefully review the [Release Checklist](release-checklist) thoroughly. This checklist ensures that you've completed all necessary steps and provides criteria for evaluating the success of your integration. -::: - ## Install Adapty SDKs 1. Add Adapty and AdaptyUI to your `pubspec.yaml` file: @@ -66,10 +165,10 @@ Create `Adapty-Info.plist` and add it to your project. Add the flag `AdaptyPubli Parameters: -| Parameter | Presence | Description | -|---------|--------|-----------| -| **AdaptyPublicSdkKey** | required | The key you can find in the **Public SDK key** field of your app settings in Adapty: [**App settings**-> **General** tab -> **API keys** subsection](https://app.adapty.io/settings/general) | -| **AdaptyObserverMode** | optional |

A boolean value controlling [Observer mode](observer-vs-full-mode). Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics. At any purchase or restore in your application, you'll need to call `.restorePurchases()` method to record the action in Adapty. The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| +| Parameter | Presence | Description | +| -------------------------- | -------- | ------------------------------------------------------------ | +| **AdaptyPublicSdkKey** | required | The key you can find in the **Public SDK key** field of your app settings in Adapty: [**App settings**-> **General** tab -> **API keys** subsection](https://app.adapty.io/settings/general) | +| **AdaptyObserverMode** | optional |

A boolean value controlling [Observer mode](observer-vs-full-mode). Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics. At any purchase or restore in your application, you'll need to call `.restorePurchases()` method to record the action in Adapty. The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| | **idfaCollectionDisabled** | optional |

A boolean parameter, that allows you to disable IDFA collection for your iOS app. The default value is `false`.

For more details, refer to the [Analytics integration](analytics-integration#disable-collection-of-idfa) section.

| ### Configure Adapty SDKs for Android @@ -90,10 +189,10 @@ Parameters: Required parameters: -| Parameter | Presence | Description | -|---------|--------|-----------| -| PUBLIC_SDK_KEY | required |

Contents of the **Public SDK key** field in the [**App Settings** -> **General** tab](https://app.adapty.io/settings/general) in the Adapty Dashboard. **SDK keys** are unique for every app, so if you have multiple apps make sure you choose the right one.

Make sure you use the **Public SDK key** for Adapty initialization, since the **Secret key** should be used for [server-side API](getting-started-with-server-side-api) only.

| -| AdaptyObserverMode | optional |

A boolean value that is controlling [Observer mode](observer-vs-full-mode) . Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics.

The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| +| Parameter | Presence | Description | +| ---------------------------- | -------- | ------------------------------------------------------------ | +| PUBLIC_SDK_KEY | required |

Contents of the **Public SDK key** field in the [**App Settings** -> **General** tab](https://app.adapty.io/settings/general) in the Adapty Dashboard. **SDK keys** are unique for every app, so if you have multiple apps make sure you choose the right one.

Make sure you use the **Public SDK key** for Adapty initialization, since the **Secret key** should be used for [server-side API](getting-started-with-server-side-api) only.

| +| AdaptyObserverMode | optional |

A boolean value that is controlling [Observer mode](observer-vs-full-mode) . Turn it on if you handle purchases and subscription status yourself and use Adapty for sending subscription events and analytics.

The default value is `false`.

🚧 When running in Observer mode, Adapty SDK won't close any transactions, so make sure you're handling it.

| | AdaptyIDFACollectionDisabled | optional |

A boolean parameter, that allows you to disable IDFA collection for your app. The default value is `false`.

For more details, refer to the [Analytics integration](analytics-integration#disable-collection-of-idfa) section.

| @@ -119,12 +218,12 @@ Please keep in mind that for paywalls and products to be displayed in your mobil Adapty logs errors and other crucial information to provide insight into your app's functionality. There are the following available levels: -| Level | Description | -| :------ | :-------------------------------------------------------------------------------------------------------------------------- | -| error | Only errors will be logged. | -| warn | Errors and messages from the SDK that do not cause critical errors, but are worth paying attention to will be logged. | +| Level | Description | +| :------ | :----------------------------------------------------------- | +| error | Only errors will be logged. | +| warn | Errors and messages from the SDK that do not cause critical errors, but are worth paying attention to will be logged. | | info | Errors, warnings, and serious information messages, such as those that log the lifecycle of various modules will be logged. | -| verbose | Any additional information that may be useful during debugging, such as function calls, API queries, etc. will be logged. | +| verbose | Any additional information that may be useful during debugging, such as function calls, API queries, etc. will be logged. | You can set `logLevel` in your app before configuring Adapty. @@ -135,8 +234,11 @@ try { } catch (e) {} ``` +
+ :::danger Read checklist before releasing the app Before releasing your application, go through the [Release Checklist](release-checklist) to ensure that you have completed all the steps, and also check the success of the integration using the criteria for assessing its success. -::: \ No newline at end of file +::: + diff --git a/versioned_docs/version-3.0/sdk-installation-ios.md b/versioned_docs/version-3.0/sdk-installation-ios.md index d44d46f..2666bda 100644 --- a/versioned_docs/version-3.0/sdk-installation-ios.md +++ b/versioned_docs/version-3.0/sdk-installation-ios.md @@ -48,8 +48,8 @@ In Xcode, go to **File** -> **Add Package Dependency...**. Note that the steps t 2. **AdaptyUI** is an optional module you need if you plan to use the [Adapty Paywall Builder](adapty-paywall-builder). ```shell title="Podfile" - pod 'Adapty', '~> 3.1.0' - pod 'AdaptyUI', '~> 3.1.0' # optional module needed only for Paywall Builder + pod 'Adapty', '~> 3.2.0' + pod 'AdaptyUI', '~> 3.2.0' # optional module needed only for Paywall Builder ``` 2. Run: @@ -103,8 +103,8 @@ struct SampleApp: App { .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional - Adapty.activate(with: configurationBuilder) { error in - // handle the error + Task { + try await Adapty.activate(with: configurationBuilder) } } @@ -147,27 +147,28 @@ You need to configure the AdaptyUI module only if you plan to use [Paywall Build import AdaptyUI // Only if you are going to use AdaptyUI // After calling Adapty.activate() - let adaptyUIConfiguration = AdaptyUI.Configuration( - mediaCacheConfiguration: .init( - memoryStorageTotalCostLimit: 100 * 1024 * 1024, - memoryStorageCountLimit: .max, - diskStorageSizeLimit: 100 * 1024 * 1024 - ) - ) - AdaptyUI.activate( - configuration: adaptyUIConfiguration - ) +let adaptyUIConfiguration = AdaptyUI.Configuration( + mediaCacheConfiguration: .init( + memoryStorageTotalCostLimit: 100 * 1024 * 1024, + memoryStorageCountLimit: .max, + diskStorageSizeLimit: 100 * 1024 * 1024 + ) +) + +try await AdaptyUI.activate( + configuration: adaptyUIConfiguration +) ``` Please note that AdaptyUI configuration is optional, you can activate AdaptyUI module without its config. However, if you use the config, all parameters are required in it. Parameters: -| Parameter | Presence | Description | -| :-------------------------- | :------- | :----------------------------------------------------------- | -| memoryStorageTotalCostLimit | required | Total cost limit of the storage in bytes. | -| memoryStorageCountLimit | required | The item count limit of the memory storage. | -| diskStorageSizeLimit | required | The file size limit on disk of the storage in bytes. 0 means no limit. | +| Parameter | Presence | Description | +| :------------------------------ | :------- | :----------------------------------------------------------- | +| **memoryStorageTotalCostLimit** | required | Total cost limit of the storage in bytes. | +| **memoryStorageCountLimit** | required | The item count limit of the memory storage. | +| **diskStorageSizeLimit** | required | The file size limit on disk of the storage in bytes. 0 means no limit. |
@@ -256,6 +257,7 @@ struct SampleApp: App { .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional + .with(LogLevel: verbose) // optional Adapty.activate(with: configurationBuilder) { error in // handle the error @@ -284,6 +286,7 @@ Parameters: | **customerUserId** | optional | An identifier of the user in your system. We send it in subscription and analytical events, to attribute events to the right profile. You can also find customers by `customerUserId` in the [**Profiles and Segments**](https://app.adapty.io/profiles/users) menu. | | **idfaCollectionDisabled** | optional |

Set to `true` to disable IDFA collection and sharing.

the user IP address sharing.

The default value is `false`.

For more details on IDFA collection, refer to the [Analytics integration](analytics-integration#disable-collection-of-idfa) section.

| | **ipAddressCollectionDisabled** | optional |

Set to `true` to disable user IP address collection and sharing.

The default value is `false`.

| +| **LogLevel** | optional | Adapty logs errors and other crucial information to provide insight into your app's functionality. There are the following available levels:
  • error: Only errors will be logged.
  • warn: Errors and messages from the SDK that do not cause critical errors, but are worth paying attention to will be logged.
  • info: Errors, warnings, and serious information messages, such as those that log the lifecycle of various modules will be logged.
  • verbose: Any additional information that may be useful during debugging, such as function calls, API queries, etc. will be logged.
| :::note @@ -297,29 +300,12 @@ Please keep in mind that for paywalls and products to be displayed in your mobil
-## Set up the logging system - -Adapty logs errors and other crucial information to provide insight into your app's functionality. Available levels: - -| Level | Description | -| :------ | :----------------------------------------------------------------------------------------------------- | -| error | Only errors will be logged. | -| warn | Logs errors and non-critical messages that warrant attention. | -| info | Logs errors, warnings, and significant informational messages, such as module lifecycle events. | -| verbose | Logs detailed information that may be useful during debugging, such as function calls and API queries. | - -You can set `logLevel` at any time, but it's recommended to do so before configuring Adapty. - -```swift title="Swift" -Adapty.logLevel = .verbose -``` - ## Redirect the logging system messages -If you need to send Adapty's log messages to your system or save them to a file, you can override the default behavior: +If you need to send Adapty's log messages to your system or save them to a file, you can add the desired behavior: ```swift title="Swift" -Adapty.setLogHandler { level, message in - writeToLocalFile("Adapty \(level): \(message)") +Adapty.setLogHandler { record in + writeToLocalFile("Adapty \(record.level): \(record.message)") } ``` \ No newline at end of file diff --git a/versioned_docs/version-3.0/setting-user-attributes.md b/versioned_docs/version-3.0/setting-user-attributes.md index eb98eae..45f19ab 100644 --- a/versioned_docs/version-3.0/setting-user-attributes.md +++ b/versioned_docs/version-3.0/setting-user-attributes.md @@ -17,6 +17,31 @@ To set user attributes, call `.updateProfile()` method: + +```swift +let builder = AdaptyProfileParameters.Builder() + .with(email: "email@email.com") + .with(phoneNumber: "+18888888888") + .with(facebookAnonymousId: "facebookAnonymousId") + .with(amplitudeUserId: "amplitudeUserId") + .with(amplitudeDeviceId: "amplitudeDeviceId") + .with(mixpanelUserId: "mixpanelUserId") + .with(appmetricaProfileId: "appmetricaProfileId") + .with(appmetricaDeviceId: "appmetricaDeviceId") + .with(firstName: "John") + .with(lastName: "Appleseed") + .with(gender: .other) + .with(birthday: Date()) + +do { + try await Adapty.updateProfile(params: builder.build()) +} catch { + // handle the error +} +``` + + + ```swift let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") @@ -40,6 +65,7 @@ Adapty.updateProfile(params: builder.build()) { error in ``` + ```kotlin val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") @@ -61,8 +87,10 @@ Adapty.updateProfile(builder.build()) { error -> } } ``` + + ```java AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder() .withEmail("email@email.com") @@ -86,6 +114,7 @@ Adapty.updateProfile(builder.build(), error -> { ``` + ```javascript final builder = AdaptyProfileParametersBuilder() ..setEmail("email@email.com") @@ -110,6 +139,7 @@ try { ``` + ```typescript // Only for TypeScript validation import type { AdaptyProfileParameters } from 'react-native-adapty'; @@ -137,13 +167,14 @@ try { ``` + ```csharp var builder = new Adapty.ProfileParameters.Builder() .SetFirstName("John") - .SetLastName("Appleseed") - .SetBirthday(new DateTime(1970, 1, 3)) - .SetGender(ProfileGender.Female) - .SetEmail("example@adapty.io"); + .SetLastName("Appleseed") + .SetBirthday(new DateTime(1970, 1, 3)) + .SetGender(ProfileGender.Female) + .SetEmail("example@adapty.io"); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != nil) { @@ -151,6 +182,7 @@ Adapty.UpdateProfile(builder.Build(), (error) => { } }); ``` + @@ -172,8 +204,25 @@ The allowed keys `` of `AdaptyProfileParameters.Builder` and the values ` + -```swift + +```swift +if #available(iOS 14, macOS 11.0, *) { + let builder = AdaptyProfileParameters.Builder() + .with(appTrackingTransparencyStatus: .authorized) + + do { + try await Adapty.updateProfile(params: builder.build()) + } catch { + // handle the error + } +} +``` + + + +```swift if #available(iOS 14, macOS 11.0, *) { let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) @@ -187,6 +236,7 @@ if #available(iOS 14, macOS 11.0, *) { ``` + ```javascript final builder = AdaptyProfileParametersBuilder() ..setAppTrackingTransparencyStatus(AdaptyIOSAppTrackingTransparencyStatus.authorized); @@ -200,6 +250,7 @@ try { ``` + ```csharp var builder = new Adapty.ProfileParameters.Builder(); .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); @@ -212,6 +263,7 @@ Adapty.UpdateProfile(builder.Build(), (error) => { ``` + ```typescript import {AppTrackingTransparencyStatus} from 'react-native-adapty'; diff --git a/versioned_docs/version-3.0/subscription-status.md b/versioned_docs/version-3.0/subscription-status.md index b10b4e5..83bfd95 100644 --- a/versioned_docs/version-3.0/subscription-status.md +++ b/versioned_docs/version-3.0/subscription-status.md @@ -31,6 +31,21 @@ To get the access level from the server, use the `.getProfile()` method: + +```swift +do { + let profile = try await Adapty.getProfile() + + if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { + // grant access to premium features + } +} catch { + // handle the error +} +``` + + + ```swift Adapty.getProfile { result in if let profile = try? result.get() { @@ -43,6 +58,7 @@ Adapty.getProfile { result in ``` + ```kotlin Adapty.getProfile { result -> when (result) { @@ -119,6 +135,19 @@ Here is an example for checking for the default "premium" access level: + +```swift +do { + let profile = try await Adapty.getProfile() + let isPremium = profile.accessLevels["premium"]?.isActive ?? false + // grant access to premium features +} catch { + // handle the error +} +``` + + + ```swift Adapty.getProfile { result in if let profile = try? result.get(), @@ -218,16 +247,18 @@ To receive messages from Adapty, you need to make some additional configuration: + ```swift Adapty.delegate = self // To receive subscription updates, extend `AdaptyDelegate` with this method: -func didLoadLatestProfile(_ profile: AdaptyProfile) { +nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { // handle any changes to subscription state } ``` + ```kotlin Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state diff --git a/versioned_docs/version-3.0/using-custom-fonts-in-paywall-builder.md b/versioned_docs/version-3.0/using-custom-fonts-in-paywall-builder.md index 83c24eb..dad4254 100644 --- a/versioned_docs/version-3.0/using-custom-fonts-in-paywall-builder.md +++ b/versioned_docs/version-3.0/using-custom-fonts-in-paywall-builder.md @@ -10,7 +10,7 @@ import 'react-medium-image-zoom/dist/styles.css'; Consistency in visuals is key to great design. When building no-code paywalls, you might want to use a custom font to match the rest of your app. Here, we'll discuss how to customize fonts and how you can use them. :::warning -This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 and later which is now available for iOS and Android only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Custom fonts in legacy Paywall Builder](using-custom-fonts-in-legacy-paywall-builder). +This section describes the new Paywall Builder, compatible with Adapty SDK v3.0 (3.2.0 for Flutter) and later which is now available for iOS, Android, Flutter, and React Native only. For information on the legacy Paywall Builder compatible with Adapty SDK v2.x or earlier, see [Custom fonts in legacy Paywall Builder](using-custom-fonts-in-legacy-paywall-builder). ::: ## diff --git a/versioned_sidebars/version-3.0-sidebars.json b/versioned_sidebars/version-3.0-sidebars.json index 9afa091..9dae221 100644 --- a/versioned_sidebars/version-3.0-sidebars.json +++ b/versioned_sidebars/version-3.0-sidebars.json @@ -124,7 +124,7 @@ "label": "Enable Real-time developer notifications (RTDN) in Google Play Console" } ] - } + } ] }, { @@ -565,6 +565,11 @@ "type": "doc", "id": "android-present-paywalls", "label": "Android" + }, + { + "type": "doc", + "id": "flutter-present-paywalls", + "label": "Flutter" }, { "type": "doc", @@ -597,6 +602,11 @@ "type": "doc", "id": "android-handling-events", "label": "Android" + }, + { + "type": "doc", + "id": "flutter-handling-events", + "label": "Flutter" }, { "type": "doc", @@ -644,7 +654,7 @@ }, { "type": "doc", - "id": "flutter-present-paywalls", + "id": "flutter-present-paywalls-legacy", "label": "Flutter" }, { @@ -686,7 +696,7 @@ }, { "type": "doc", - "id": "flutter-handling-events", + "id": "flutter-handling-events-legacy", "label": "Flutter" }, { @@ -1580,7 +1590,7 @@ } ] }, - { + { "type": "category", "label": "SERVER-SIDE API", "collapsible": false, @@ -1635,6 +1645,7 @@ ]} ] }, + { "type": "category", "label": "SDK MIGRATION GUIDES", @@ -1734,5 +1745,5 @@ } ] } - ] + ] } \ No newline at end of file