Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project are documented here. The format is based on

## [Unreleased]

### Fixed

- Android references (`api-reference.md`, `migration-v6.md`, `concepts/paywall-actions.md`) no longer show a separate `import io.purchasely.ext.interceptAction` / `removeActionInterceptor`. As of SDK `6.0.0-rc.2`, both are inline member functions of `Purchasely` — importing `io.purchasely.ext.Purchasely` is enough.

## [2.0.0-rc.5] — 2026-07-03

React Native joins the **v6 line**. The plugin now treats native iOS, native Android, Flutter, and React Native as SDK v6 platforms, while **Cordova stays on v5 (`5.7.3`)**. React Native guidance targets the published **`react-native-purchasely` `6.0.0-rc.2`** packages and their native **`6.0.0-rc.2`** dependencies.
Expand Down
27 changes: 21 additions & 6 deletions purchasely/references/android/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import io.purchasely.ext.PLYRunningMode
import io.purchasely.ext.LogLevel
import io.purchasely.ext.PLYError
import io.purchasely.ext.PLYInterceptResult
import io.purchasely.ext.interceptAction
import io.purchasely.ext.removeActionInterceptor

import io.purchasely.ext.presentation.PLYPresentation
import io.purchasely.ext.presentation.PLYPresentationAction
Expand Down Expand Up @@ -271,13 +269,19 @@ AndroidView(factory = { loaded.buildView(it) { outcome -> } })

## Action Interceptor

The global `setPaywallActionsInterceptor` was removed. Each action has its own typed interceptor returning a `PLYInterceptResult`.
The global `setPaywallActionsInterceptor` was removed. Each action has its own typed interceptor.
There are three ways to register one — pick by call site:

Kotlin (reified):
| Style | Signature | How you return the result |
|-------|-----------|---------------------------|
| Kotlin, coroutine | `interceptAction<T> { info, action -> … }` | **return** a `PLYInterceptResult` (lambda is `suspend`) |
| Kotlin, no coroutine | `interceptAction(T::class.java) { info, action, result -> … }` | call `result(…)` later (callback) |
| Java | `interceptAction(T.class, callback)` | call `result.invoke(…)` later (callback) |

Kotlin — with coroutine (reified, returns `PLYInterceptResult` directly; `suspend` calls allowed):

```kotlin
import io.purchasely.ext.PLYInterceptResult
import io.purchasely.ext.interceptAction
import io.purchasely.ext.presentation.PLYPresentationAction

Purchasely.interceptAction<PLYPresentationAction.Login> { _, _ ->
Expand All @@ -295,6 +299,17 @@ Purchasely.interceptAction<PLYPresentationAction.Purchase> { info, purchase ->
}
```

Kotlin — without coroutine (Class-based overload, selected via `::class.java`; return the result
later through the `result` lambda — call it exactly once, synchronously or after async work):

```kotlin
Purchasely.interceptAction(PLYPresentationAction.Purchase::class.java) { info, action, result ->
val purchase = action as PLYPresentationAction.Purchase // not cast for you here
// ... optionally async (billing, dialog); then:
result(PLYInterceptResult.NOT_HANDLED)
}
```

Java (Class-based overload — the reified form is not callable from Java):

```java
Expand All @@ -317,7 +332,7 @@ Purchasely.removeActionInterceptor(PLYPresentationAction.Purchase.class); // Jav
Purchasely.removeAllActionInterceptors();
```

> The reified `interceptAction<T>` / `removeActionInterceptor<T>()` are `inline` functions targeting JVM 11. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload.
> The reified `interceptAction<T>` / `removeActionInterceptor<T>()` are `inline` member functions of `Purchasely` targeting JVM 11 — no separate import beyond `io.purchasely.ext.Purchasely` is needed. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload.

| Result | Meaning |
|--------|---------|
Expand Down
16 changes: 13 additions & 3 deletions purchasely/references/android/migration-v6.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ If `6.0.0-rc.1` is only installed on the developer machine, add `mavenLocal()` i

SDK v6 uses the modern Android toolchain: Gradle 9.3.0+, AGP 9.x, Kotlin 2.2.x (K2 compiler), JDK 17 to build, minSdk 23, compileSdk 36.

The reified entry points `interceptAction<T> { … }` / `removeActionInterceptor<T>()` are `inline` functions targeting JVM 11. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload.
The reified entry points `interceptAction<T> { … }` / `removeActionInterceptor<T>()` are `inline` member functions of `Purchasely` targeting JVM 11 — no separate import beyond `io.purchasely.ext.Purchasely` is needed. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload.

With AGP 9, remove the explicit `org.jetbrains.kotlin.android` plugin; AGP provides Android Kotlin support directly. Keep specialized Kotlin plugins such as Compose or Serialization when the app uses them. Also remove `android { kotlinOptions { ... } }` once `kotlin-android` is gone.

Expand Down Expand Up @@ -249,7 +249,6 @@ The global `setPaywallActionsInterceptor` API was removed. Use typed interceptor

```kotlin
import io.purchasely.ext.PLYInterceptResult
import io.purchasely.ext.interceptAction
import io.purchasely.ext.presentation.PLYPresentationAction

Purchasely.interceptAction<PLYPresentationAction.Login> { _, _ ->
Expand All @@ -267,7 +266,18 @@ Purchasely.interceptAction<PLYPresentationAction.Purchase> { info, action ->
}
```

Java callers cannot use the reified `interceptAction<T>`. Use the `Class`-based overload, cast the action, and resolve with `result.invoke(...)`:
The reified lambda above is `suspend` (return the result directly). If your Kotlin call site is
**not** a coroutine, use the `Class`-based overload — select it with `::class.java` and return the
result later via the `result` lambda (call it exactly once):

```kotlin
Purchasely.interceptAction(PLYPresentationAction.Purchase::class.java) { info, action, result ->
val purchase = action as PLYPresentationAction.Purchase // not cast for you here
result(PLYInterceptResult.NOT_HANDLED) // may be deferred after async work
}
```

Java callers cannot use the reified `interceptAction<T>`. Use the same `Class`-based overload, cast the action, and resolve with `result.invoke(...)`:

```java
Purchasely.interceptAction(PLYPresentationAction.Purchase.class, (info, action, result) -> {
Expand Down
11 changes: 10 additions & 1 deletion purchasely/references/concepts/paywall-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,16 @@ Purchasely.interceptAction<PLYPresentationAction.Purchase> { info, purchase ->
}
```

> The reified `interceptAction<T>` / `removeActionInterceptor<T>()` are `inline` functions targeting JVM 11. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload (see Java below).
> The reified `interceptAction<T>` / `removeActionInterceptor<T>()` are `inline` member functions of `Purchasely` targeting JVM 11 — no separate import beyond `io.purchasely.ext.Purchasely` is needed. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload (below).

If your call site is **not** a coroutine, use the `Class`-based overload from Kotlin too (select it with `::class.java`) and return the result later via the `result` lambda:

```kotlin
Purchasely.interceptAction(PLYPresentationAction.Purchase::class.java) { info, action, result ->
val purchase = action as PLYPresentationAction.Purchase // cast yourself
result(PLYInterceptResult.NOT_HANDLED) // call exactly once, may be deferred
}
```

### Android (Java)

Expand Down
27 changes: 27 additions & 0 deletions purchasely/skills/purchasely-integrate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,8 +780,35 @@ Purchasely.interceptAction<PLYPresentationAction.Purchase> { _, _ ->
}
```

The reified `interceptAction<T> { … }` lambda is `suspend` and **returns** the `PLYInterceptResult`.
When your call site is not a coroutine, use the `Class`-based overload (`::class.java`) and return
the result later via the `result` lambda:

```kotlin
Purchasely.interceptAction(PLYPresentationAction.Purchase::class.java) { _, action, result ->
val purchase = action as PLYPresentationAction.Purchase // cast yourself
result(PLYInterceptResult.NOT_HANDLED) // call exactly once, may be deferred
}
```

Android v6 returns `PLYInterceptResult.SUCCESS`, `FAILED`, or `NOT_HANDLED`; there is no `processAction` callback in the new native Android interceptor.

### Android (Java, SDK v6)

Java cannot use the reified `interceptAction<T>` — use the `Class`-based overload, cast the action,
and resolve via `result.invoke(...)`:

```java
Purchasely.interceptAction(PLYPresentationAction.Login.class, (info, action, result) ->
result.invoke(PLYInterceptResult.NOT_HANDLED));

Purchasely.interceptAction(PLYPresentationAction.Purchase.class, (info, action, result) -> {
PLYPresentationAction.Purchase purchase = (PLYPresentationAction.Purchase) action;
// ... optionally async; call result exactly once:
result.invoke(PLYInterceptResult.NOT_HANDLED);
});
```

### React Native (TypeScript, SDK v6)

Register **one handler per action kind** with `Purchasely.interceptAction(kind, handler)`. The async handler receives `(info, payload)` and returns the **string** `'success' | 'failed' | 'notHandled'` — there is no `onProcessAction`. Use `Purchasely.removeActionInterceptor(kind)` / `Purchasely.removeAllActionInterceptors()` to tear them down.
Expand Down
Loading