diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c565e..200cff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/purchasely/references/android/api-reference.md b/purchasely/references/android/api-reference.md index 7921f46..eab83ca 100644 --- a/purchasely/references/android/api-reference.md +++ b/purchasely/references/android/api-reference.md @@ -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 @@ -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 { 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 { _, _ -> @@ -295,6 +299,17 @@ Purchasely.interceptAction { 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 @@ -317,7 +332,7 @@ Purchasely.removeActionInterceptor(PLYPresentationAction.Purchase.class); // Jav Purchasely.removeAllActionInterceptors(); ``` -> The reified `interceptAction` / `removeActionInterceptor()` are `inline` functions targeting JVM 11. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload. +> The reified `interceptAction` / `removeActionInterceptor()` 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 | |--------|---------| diff --git a/purchasely/references/android/migration-v6.md b/purchasely/references/android/migration-v6.md index 9b9ec7a..347b177 100644 --- a/purchasely/references/android/migration-v6.md +++ b/purchasely/references/android/migration-v6.md @@ -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 { … }` / `removeActionInterceptor()` are `inline` functions targeting JVM 11. Compile your Kotlin module with `jvmTarget = 11`, or use the `Class`-based overload. +The reified entry points `interceptAction { … }` / `removeActionInterceptor()` 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. @@ -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 { _, _ -> @@ -267,7 +266,18 @@ Purchasely.interceptAction { info, action -> } ``` -Java callers cannot use the reified `interceptAction`. 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`. Use the same `Class`-based overload, cast the action, and resolve with `result.invoke(...)`: ```java Purchasely.interceptAction(PLYPresentationAction.Purchase.class, (info, action, result) -> { diff --git a/purchasely/references/concepts/paywall-actions.md b/purchasely/references/concepts/paywall-actions.md index 329e547..df6e369 100644 --- a/purchasely/references/concepts/paywall-actions.md +++ b/purchasely/references/concepts/paywall-actions.md @@ -90,7 +90,16 @@ Purchasely.interceptAction { info, purchase -> } ``` -> The reified `interceptAction` / `removeActionInterceptor()` 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` / `removeActionInterceptor()` 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) diff --git a/purchasely/skills/purchasely-integrate/SKILL.md b/purchasely/skills/purchasely-integrate/SKILL.md index c9677aa..146d142 100644 --- a/purchasely/skills/purchasely-integrate/SKILL.md +++ b/purchasely/skills/purchasely-integrate/SKILL.md @@ -780,8 +780,35 @@ Purchasely.interceptAction { _, _ -> } ``` +The reified `interceptAction { … }` 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` — 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.