Skip to content

Commit 86f595a

Browse files
committed
iOS polish
1 parent 8464483 commit 86f595a

10 files changed

Lines changed: 66 additions & 58 deletions

src/content/docs/ios/ios-handle-permissions.mdx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
---
2-
title: "Handle permission requests - iOS"
2+
title: "Handle permission requests in flows (beta) - iOS"
33
description: "Implement AdaptySystemRequestsHandler to respond to system permission requests triggered from paywall and onboarding flows."
4-
metadataTitle: "Handle Permission Requests - iOS | Adapty Docs"
4+
metadataTitle: "Handle Permission Requests in Flows (beta) - iOS | Adapty Docs"
55
---
66

77
If a flow includes buttons that request system permissions (push notifications, camera access, and others), the SDK calls your `AdaptySystemRequestsHandler`. You implement this handler to request the permission from the OS and return the result.
88

9+
## When the handler fires
10+
11+
The handler is invoked when the user taps a button in the rendered flow that triggers a system permission request. The SDK calls your `handlePermission` method with the permission type, you request the permission from the OS, and return the result — the flow then continues based on whether you returned `.granted` or `.denied`.
12+
913
## Implement AdaptySystemRequestsHandler
1014

1115
Create a class that conforms to the `AdaptySystemRequestsHandler` protocol and implement the required `handlePermission` method. Return `.granted(_)` or `.denied(_)` to report the result back to the flow — the associated `String?` carries optional detail (often `nil`).

src/content/docs/ios/ios-handling-events.mdx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "Handle paywall & flow events - iOS"
33
description: "Handle paywall and onboarding flow events in your iOS app."
44
metadataTitle: "Handle Flow Events - iOS | Adapty Docs"
55
toc_max_heading_level: 4
6-
keywords: ['event', 'AdaptyFlowControllerDelegate', 'AdaptyPaywallControllerDelegate', 'flowController', 'didSelectProduct', 'didStartPurchase', 'didFinishPurchase', 'didFailPurchase', 'didFinishRestoreWith', 'didFailRestoreWith', 'didFailLoadingProductsWith', 'didFailRenderingWith', 'didReceiveAnalyticEvent', 'didFinishWebPaymentNavigation']
6+
keywords: ['event', 'AdaptyFlowControllerDelegate', 'AdaptyPaywallControllerDelegate', 'flowController', 'didSelectProduct', 'didStartPurchase', 'didFinishPurchase', 'didFailPurchase', 'didFinishRestoreWith', 'didFailRestoreWith', 'didFailLoadingProductsWith', 'didFailRenderingWith', 'didFinishWebPaymentNavigation']
77
---
88

99
import SampleApp from '@site/src/components/reusable/SampleApp.md';
@@ -85,7 +85,7 @@ You can register only the closure parameters you need and omit those you do not
8585

8686
For UIKit apps, events are handled through the `AdaptyFlowControllerDelegate` protocol. See [Display flows & paywalls - iOS](ios-present-paywalls) for how to set up `AdaptyFlowController` with `AdaptyFlowControllerDelegate`.
8787

88-
The protocol declares 14 methods. Three of them have no default implementation and must be implemented when conforming: `didFailPurchase`, `didFinishRestoreWith`, and `didFailRestoreWith`. The rest provide default no-op implementations and can be overridden when you want custom behavior. Methods are grouped below by purpose.
88+
The protocol declares 13 methods. Three of them have no default implementation and must be implemented when conforming: `didFailPurchase`, `didFinishRestoreWith`, and `didFailRestoreWith`. The rest provide default no-op implementations and can be overridden when you want custom behavior. Methods are grouped below by purpose.
8989

9090
### Lifecycle
9191

@@ -201,18 +201,6 @@ func flowController(
201201

202202
Invoked after a web payment navigation finishes, whether successful or failed.
203203

204-
### Analytic events
205-
206-
```swift showLineNumbers title="Swift"
207-
func flowController(
208-
_ controller: AdaptyFlowController,
209-
didReceiveAnalyticEvent name: String,
210-
params: [String: any Sendable]
211-
) { }
212-
```
213-
214-
Forward custom analytic events fired by the flow's script (e.g. `paywall_opened`, `cta_tapped`) to your analytics provider (Amplitude, Mixpanel, etc.). Only events explicitly marked as customer-facing in the flow configuration are delivered here.
215-
216204
</SDKv4>
217205

218206
<SDKv3>
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
---
2-
title: "Paywall and onboarding flows - iOS"
3-
description: "Display and manage paywall and onboarding flows built with the Adapty Flow Builder in your iOS app."
4-
metadataTitle: "Paywall and Onboarding Flows - iOS | Adapty Docs"
2+
title: "Paywalls and flows - iOS"
3+
description: "Display and manage paywalls and flows built with the Adapty Paywall Builder or Flow Builder in your iOS app."
4+
metadataTitle: "Paywalls and Flows - iOS | Adapty Docs"
55
---
66

77
import CustomDocCardList from '@site/src/components/CustomDocCardList';
88

99
## Display paywalls
1010

11-
### Adapty Paywall Builder/Flow Builder
11+
### Adapty Paywall Builder & Flow Builder
1212

13-
<CustomDocCardList ids={['get-pb-paywalls', 'ios-present-paywalls', 'ios-handling-events', 'handle-paywall-actions', 'ios-handle-permissions']} />
13+
<CustomDocCardList ids={['get-pb-paywalls', 'ios-present-paywalls', 'ios-handling-events', 'handle-paywall-actions']} />
1414

1515
:::tip
1616
To get started with the Adapty Paywall Builder paywalls quickly, see our [quickstart guide](ios-quickstart-paywalls).
@@ -24,4 +24,4 @@ For more guides on implementing paywalls and handling purchases manually, see th
2424

2525
## Useful features
2626

27-
<CustomDocCardList ids={['ios-use-fallback-paywalls', 'localizations-and-locale-codes', 'ios-web-paywall']} />
27+
<CustomDocCardList ids={['ios-use-fallback-paywalls', 'localizations-and-locale-codes', 'ios-web-paywall', 'ios-handle-permissions']} />

src/content/docs/ios/ios-present-paywalls.mdx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,20 @@ To get the `AdaptyUI.FlowConfiguration` object used below, see [Get paywalls and
1818

1919
### Present as a modal view
2020

21-
In order to display a paywall or flow on the device screen as a modal view, use the `.flow` modifier in SwiftUI:
21+
In order to display a paywall or flow on the device screen as a modal view, use the `.flow` modifier in SwiftUI. The minimal call requires `isPresented`, `flowConfiguration`, and the four required callbacks:
22+
23+
```swift showLineNumbers title="SwiftUI"
24+
.flow(
25+
isPresented: $flowPresented,
26+
flowConfiguration: <AdaptyUI.FlowConfiguration>,
27+
didFailPurchase: { _, _ in /* handle the error */ },
28+
didFinishRestore: { _ in /* check access level and dismiss */ },
29+
didFailRestore: { _ in /* handle the error */ },
30+
didFailRendering: { _ in flowPresented = false }
31+
)
32+
```
33+
34+
For more control, add optional callbacks like `didPerformAction` to handle button taps and `didFinishPurchase` to react to successful purchases:
2235

2336
```swift showLineNumbers title="SwiftUI"
2437
@State var flowPresented = false // ensure that you manage this variable state and set it to `true` at the moment you want to show the paywall or flow
@@ -134,14 +147,6 @@ extension YourViewController: AdaptyFlowControllerDelegate {
134147
didFailRenderingWith error: AdaptyUIError) {
135148
controller.dismiss(animated: true)
136149
}
137-
138-
// Optional — forward custom analytic events fired by the flow's script
139-
// (e.g. to Amplitude or Mixpanel). Has a default no-op implementation.
140-
func flowController(_ controller: AdaptyFlowController,
141-
didReceiveAnalyticEvent name: String,
142-
params: [String: any Sendable]) {
143-
// Forward `name` and `params` to your analytics provider
144-
}
145150
}
146151
```
147152

src/content/docs/ios/ios-quickstart-paywalls.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Before you start, complete these steps:
4343
2. [Create your products](create-product) in Adapty.
4444
3. [Create a paywall and add products to it](create-paywall).
4545
4. [Create a placement and add your paywall to it](create-placement).
46-
5. [Install and activate the Adapty SDK](sdk-installation-ios) in your app code.
46+
5. [Install and activate the Adapty SDK](sdk-installation-ios) in your app code. This guide uses Adapty iOS SDK v4 (beta) APIs.
4747

4848
:::tip
4949
The fastest way to complete these steps is to follow the [quickstart guide](quickstart) or create paywalls and placements using the [Developer CLI](developer-cli-quickstart).

src/content/docs/ios/migration-to-ios-sdk-v4.mdx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: "Migrate to Adapty iOS SDK v4.0 (beta) by replacing paywall builder
44
metadataTitle: "Migrating to Adapty iOS SDK v4.0 (beta) | Adapty Docs"
55
---
66

7-
Adapty iOS SDK 4.0 (beta) introduces a new flow methods alongside the existing paywall methods. The new flow methods work with both the Paywall Builder and the new Flow Builder — no setup changes are required on the Adapty Dashboard side. There are three things to know about the type changes:
7+
Adapty iOS SDK 4.0 (beta) introduces new flow methods to replace the v3 paywall methods. The new flow methods work with both the Paywall Builder and the new Flow Builder — no setup changes are required on the Adapty Dashboard side. There are three things to know about the type changes:
88

99
- **`AdaptyFlow` is a new type.** It is a placement that wraps one or more paywalls — the value returned by the new `Adapty.getFlow(placementId:)` method.
1010
- **`AdaptyPaywall` has been renamed to `AdaptyFlowPaywall`.** Code that previously held a single paywall now holds an `AdaptyFlowPaywall` (the type the SDK returns inside an `AdaptyFlow.paywalls` collection or via flow-builder APIs).
@@ -22,7 +22,7 @@ Adapty iOS SDK 4.0 (beta) introduces a new flow methods alongside the existing p
2222

2323
## Replace getPaywall with getFlow
2424

25-
Replace `Adapty.getPaywall()` with `Adapty.getFlow()`. The returned type changes from `AdaptyPaywall` to `AdaptyFlow`. The `locale` parameter has been removed.
25+
Replace `Adapty.getPaywall()` with `Adapty.getFlow()`. The returned type changes from `AdaptyPaywall` to `AdaptyFlow`. The `locale` parameter has moved from the fetch call to `AdaptyUI.getFlowConfiguration(forFlow:locale:)` — see the next section.
2626

2727
```diff showLineNumbers
2828
- let paywall = try await Adapty.getPaywall(
@@ -34,13 +34,22 @@ Replace `Adapty.getPaywall()` with `Adapty.getFlow()`. The returned type changes
3434

3535
## Replace getPaywallConfiguration with getFlowConfiguration
3636

37-
Replace `AdaptyUI.getPaywallConfiguration(forPaywall:)` with `AdaptyUI.getFlowConfiguration(forFlow:)`. The method now takes an `AdaptyFlow` object instead of `AdaptyPaywall`.
37+
Replace `AdaptyUI.getPaywallConfiguration(forPaywall:)` with `AdaptyUI.getFlowConfiguration(forFlow:)`. The method now takes an `AdaptyFlow` object instead of `AdaptyPaywall`. Locale handling now lives here — pass it via the `locale:` parameter:
3838

3939
```diff showLineNumbers
4040
- let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
4141
+ let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow)
4242
```
4343

44+
If you previously passed `locale:` to `getPaywall`, pass it to `getFlowConfiguration` instead:
45+
46+
```diff showLineNumbers
47+
- let paywall = try await Adapty.getPaywall(placementId: "main", locale: "fr")
48+
- let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
49+
+ let flow = try await Adapty.getFlow(placementId: "main")
50+
+ let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "fr")
51+
```
52+
4453
## Replace AdaptyPaywallController with AdaptyFlowController (UIKit)
4554

4655
Replace `AdaptyPaywallController` with `AdaptyFlowController` and update the factory method name:
@@ -133,13 +142,6 @@ Rename the delegate protocol and update all method signatures. Note that `didSel
133142
+ func flowController(_ controller: AdaptyFlowController,
134143
+ didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
135144
+ error: AdaptyError?) { }
136-
+
137-
+ // New in v4: forward custom analytic events fired by the flow's script
138-
+ // (e.g. to Amplitude or Mixpanel). The method has a default no-op
139-
+ // implementation, so override only when you need it.
140-
+ func flowController(_ controller: AdaptyFlowController,
141-
+ didReceiveAnalyticEvent name: String,
142-
+ params: [String: any Sendable]) { }
143145
}
144146
```
145147

@@ -148,7 +150,7 @@ Rename the delegate protocol and update all method signatures. Note that `didSel
148150
Rename the modifier from `.paywall()` to `.flow()` and update the configuration parameter name from `paywallConfiguration` to `flowConfiguration`:
149151

150152
```diff showLineNumbers
151-
@State var flowPresented = false
153+
@State var flowPresented = false // rename freely — the variable name is your choice
152154

153155
var body: some View {
154156
Text("Hello, AdaptyUI!")

src/content/docs/version-3.0/get-pb-paywalls.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ Parameters:
9999

100100
| Parameter | Presence | Description |
101101
| :----------------------- | :------------- | :---------- |
102-
| **flow** | required | An `AdaptyFlow` object to obtain a controller for the desired paywall. |
102+
| **forFlow** | required | An `AdaptyFlow` object obtained via `Adapty.getFlow`. |
103+
| **locale** | <p>optional</p><p>default: `nil`</p> | The identifier of the [paywall localization](add-paywall-locale-in-adapty-paywall-builder). Expected as a language code with one or two subtags separated by `-` (e.g., `en`, `pt-br`). See [Localizations and locale codes](localizations-and-locale-codes). |
103104
| **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. |
104105
| **products** | optional | Provide an array of `AdaptyPaywallProduct` objects to optimize the display timing of products on the screen. If `nil` is passed, AdaptyUI will automatically fetch the necessary products. |
105106

src/pages/[...slug].astro

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -513,9 +513,10 @@ const globalComponents = Object.entries(reusableComponents).reduce((acc, [path,
513513
}
514514
}
515515

516-
// Tag TOC <li>s with the SDK version of the block their heading lives in,
517-
// so we can hide entries belonging to the inactive tab.
518-
const versionedTocItems = { v3: [], v4: [] };
516+
// Tag TOC <li>s with a class indicating which SDK version their heading
517+
// belongs to. Use a class (not data-sdk-version) to avoid colliding with
518+
// the global `[data-sdk-version] { display: none }` rule that hides
519+
// page-content blocks.
519520
document.querySelectorAll('.toc-link').forEach(link => {
520521
const slug = link.getAttribute('data-slug');
521522
if (!slug) return;
@@ -527,8 +528,7 @@ const globalComponents = Object.entries(reusableComponents).reduce((acc, [path,
527528
if (!li) return;
528529
const version = sdkBlock.getAttribute('data-sdk-version');
529530
if (version === 'v3' || version === 'v4') {
530-
li.setAttribute('data-sdk-version', version);
531-
versionedTocItems[version].push(li);
531+
li.classList.add(`toc-sdk-${version}`);
532532
}
533533
});
534534

@@ -537,8 +537,9 @@ const globalComponents = Object.entries(reusableComponents).reduce((acc, [path,
537537
v3Blocks.forEach(el => el.classList.toggle('sdk-version-active', tab === 'v3'));
538538
v4Tab.classList.toggle('active', tab === 'v4');
539539
v3Tab.classList.toggle('active', tab === 'v3');
540-
versionedTocItems.v4.forEach(li => { li.style.display = tab === 'v4' ? '' : 'none'; });
541-
versionedTocItems.v3.forEach(li => { li.style.display = tab === 'v3' ? '' : 'none'; });
540+
// Toggle a root class so CSS can hide inactive-tab TOC entries.
541+
document.documentElement.classList.toggle('sdk-active-v4', tab === 'v4');
542+
document.documentElement.classList.toggle('sdk-active-v3', tab === 'v3');
542543
localStorage.setItem(SDK_VERSION_KEY, tab);
543544
}
544545

src/pages/[locale]/[...slug].astro

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,10 @@ Object.entries(localeReusableComponents).forEach(([p, module]: [string, any]) =>
288288
}
289289
}
290290

291-
// Tag TOC <li>s with the SDK version of the block their heading lives in,
292-
// so we can hide entries belonging to the inactive tab.
293-
const versionedTocItems = { v3: [], v4: [] };
291+
// Tag TOC <li>s with a class indicating which SDK version their heading
292+
// belongs to. Use a class (not data-sdk-version) to avoid colliding with
293+
// the global `[data-sdk-version] { display: none }` rule that hides
294+
// page-content blocks.
294295
document.querySelectorAll('.toc-link').forEach(link => {
295296
const slug = link.getAttribute('data-slug');
296297
if (!slug) return;
@@ -302,8 +303,7 @@ Object.entries(localeReusableComponents).forEach(([p, module]: [string, any]) =>
302303
if (!li) return;
303304
const version = sdkBlock.getAttribute('data-sdk-version');
304305
if (version === 'v3' || version === 'v4') {
305-
li.setAttribute('data-sdk-version', version);
306-
versionedTocItems[version].push(li);
306+
li.classList.add(`toc-sdk-${version}`);
307307
}
308308
});
309309

@@ -312,8 +312,9 @@ Object.entries(localeReusableComponents).forEach(([p, module]: [string, any]) =>
312312
v3Blocks.forEach(el => el.classList.toggle('sdk-version-active', tab === 'v3'));
313313
v4Tab.classList.toggle('active', tab === 'v4');
314314
v3Tab.classList.toggle('active', tab === 'v3');
315-
versionedTocItems.v4.forEach(li => { li.style.display = tab === 'v4' ? '' : 'none'; });
316-
versionedTocItems.v3.forEach(li => { li.style.display = tab === 'v3' ? '' : 'none'; });
315+
// Toggle a root class so CSS can hide inactive-tab TOC entries.
316+
document.documentElement.classList.toggle('sdk-active-v4', tab === 'v4');
317+
document.documentElement.classList.toggle('sdk-active-v3', tab === 'v3');
317318
localStorage.setItem(SDK_VERSION_KEY, tab);
318319
}
319320

src/styles/global.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,12 @@ html.dark pre .highlight-line,
11591159
display: block;
11601160
}
11611161

1162+
/* TOC entries are tagged with toc-sdk-v3 / toc-sdk-v4 by sdk-version-tabs.js
1163+
when their heading lives inside a [data-sdk-version] block. Hide entries
1164+
that belong to the inactive tab. */
1165+
html.sdk-active-v4 .toc-sdk-v3 { display: none; }
1166+
html.sdk-active-v3 .toc-sdk-v4 { display: none; }
1167+
11621168
/* API reference: schema row layout (shared by SchemaTree and OperationParameters) */
11631169
.schema-row {
11641170
padding: 0.625rem 0;

0 commit comments

Comments
 (0)