Skip to content

docs(android): document the PLYUIHandler alert dismissal contract - #28

Open
chouaibMo wants to merge 1 commit into
mainfrom
docs/android-ui-handler-alert-dismissal
Open

chouaibMo wants to merge 1 commit into
mainfrom
docs/android-ui-handler-alert-dismissal

Conversation

@chouaibMo

Copy link
Copy Markdown

Summary

Mirrors Documentation@15e3faa0 into the plugin. An app that displays its own dialogs from PLYUIHandler.onAlert must end every branch with proceed() (the SDK displays its dialog and dismisses the alert) or alert.onDismiss() (dismisses it with no dialog). Calling neither leaves the paywall action pending, so the Screen stays displayed and stops reacting to taps, close button included.

The plugin had no coverage of PLYUIHandler at all — only a grep pattern in the review skill — so its frozen-Screen troubleshooting pointed solely at an unresolved interceptor. Early v5 releases did not wait for the dismissal, which makes this a latent v5 bug that a v6 migration surfaces.

Type of change

  • Bug fix (corrects wrong guidance, deprecated API, broken example)
  • New content (skill, recipe, reference doc, new platform)
  • New AI tool integration (added/updated a plugin manifest or bootstrap pointing to skills/)
  • Documentation / README / governance
  • Refactor (no functional change)

What changed

References

  • references/android/api-reference.md — new UI Handler — Alerts section: the proceed() vs alert.onDismiss() table, why the action stays pending, the PLYAlertMessage base-class helpers (onDismiss(), getTitleContent(), getContentMessage(), getButtonContent()), and the two rules — dismiss after your dialog closes, never call both.
  • references/android/migration-v6.md — a PLYUIHandler section plus verification-checklist item 11.
  • references/android/common-patterns.md — a Custom alert dialogs pattern dismissing from setOnDismissListener.
  • references/troubleshooting/common-issues.md — §2 "UI Frozen / Paywall Stuck" now splits Cause A (Android UI handler) from Cause B (unresolved interceptor), plus a row in the symptom → likely cause table.
  • references/concepts/paywall-actions.md — an Android anti-pattern, tying the freeze to the same root shape as an unresolved interceptor.

Skills

  • purchasely-review — check 3.3 flags a branch that can skip both calls, both calls made for the same alert, and onDismiss() called before the custom dialog closes. Search patterns now include uiHandler / setUIHandler( / onAlert(.
  • purchasely-debug — the UI handler as the second Android cause in "UI Frozen After Paywall Action", a new audit step, and a symptom-table row.
  • purchasely-migrate — a UI handler alerts step in the Android workflow (later steps renumbered).
  • purchasely-sdk-expert — a routing-index row for PLYUIHandler questions.

Scope decisions

  • Every check is Android-only (SKIP on iOS and the cross-platform bridges) — the single-action-queue behaviour documented upstream is Android-specific. Worth a second opinion if iOS shares it.
  • purchasely-integrate is untouched: it does not generate a UI handler, so a check there would be noise.

How was this tested?

Documentation-only change — no manifests, versions, or descriptions touched, so no agentskill.sh re-scan is needed. Verified that the ## UI Handler — Alerts and PLYUIHandler anchor targets exist and that every relative link added (../android/api-reference.md, ../../references/android/api-reference.md, ../../references/android/migration-v6.md) resolves to a real file. Confirmed the renumbered ordered lists in purchasely-migrate (1–15) and purchasely-debug (1–6) are sequential.

Checklist

  • Code examples reference APIs that exist in the current public Purchasely SDK
  • No real API keys or credentials committed (placeholders only)
  • Updated CHANGELOG.md under [Unreleased]
  • If a new AI tool was added: README, manifests/bootstrap files, and validation workflow are updated
  • If a public-facing description changed: .claude-plugin/plugin.json and .claude-plugin/marketplace.json are still consistent

🤖 Generated with Claude Code

An app that displays its own dialogs from PLYUIHandler.onAlert must end
every branch with proceed() or alert.onDismiss(). proceed() displays the
SDK dialog and dismisses the alert; alert.onDismiss() dismisses it with
no dialog. Calling neither leaves the paywall action pending, so the
Screen stays displayed and stops reacting to taps, close button included.

The plugin had no coverage of PLYUIHandler at all — only a grep pattern in
the review skill — so the frozen-Screen troubleshooting pointed solely at
an unresolved interceptor. Early v5 releases did not wait for the
dismissal, which makes this a latent v5 bug a v6 migration surfaces.

Mirrors Documentation@15e3faa0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Sep 11, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR should not merge until the nullable-activity examples stop routing through an SDK dialog path that cannot complete the alert.

Fix All in Claude CodeFindings

  1. P1 Null fallback blocks actions
Fix with agent prompt
### Issue 1
purchasely/references/android/api-reference.md:408
When `activity` is null or the presentation view is detached, `proceed()` cannot display the SDK dialog, so `alert.onDismiss()` is never triggered. The alert remains pending and blocks the shared action queue, leaving the paywall unresponsive-the exact freeze this example is meant to prevent. Use `alert.onDismiss()` for this fallback instead. The same unsafe fallback also appears in `common-patterns.md`, `migration-v6.md`, and `common-issues.md`.

Greptile automatically discovered a related ticket stating that a null activity or detached view prevents `proceed()` from completing the alert, which informed this comment.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

  • Adds API, migration, common-pattern, troubleshooting, and paywall-action guidance.
  • Extends review, debugging, migration, and expert-routing skills to recognize the alert dismissal contract.
  • Repeats an unsafe proceed() fallback for the nullable-activity path across four examples.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[PLYUIHandler.onAlert] --> B{Activity available?}
  B -->|Yes, custom dialog| C[Show app dialog]
  C --> D[Dialog closes]
  D --> E[alert.onDismiss]
  B -->|Yes, SDK dialog| F[proceed]
  F --> G[User dismisses SDK dialog]
  G --> E
  B -->|No| H[Documented proceed fallback]
  H --> I[SDK dialog cannot display]
  I --> J[Alert remains pending]
  J --> K[Action queue and Screen remain blocked]
Loading

Reviews (1) · Last reviewed commit: "docs(android): document the PLYUIHandler..."

```kotlin
Purchasely.uiHandler = object : PLYUIHandler {
override fun onAlert(alert: PLYAlertMessage, purchaselyView: View, activity: Activity?, proceed: () -> Unit) {
val context = activity ?: return proceed() // no activity: let the SDK display the alert

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Null fallback blocks actions

When activity is null or the presentation view is detached, proceed() cannot display the SDK dialog, so alert.onDismiss() is never triggered. The alert remains pending and blocks the shared action queue, leaving the paywall unresponsive—the exact freeze this example is meant to prevent. Use alert.onDismiss() for this fallback instead. The same unsafe fallback also appears in common-patterns.md, migration-v6.md, and common-issues.md.

Greptile automatically discovered a related ticket stating that a null activity or detached view prevents proceed() from completing the alert, which informed this comment.

Source Used: Linear — Android v6: onAlert without proceed() blocks the actions queue and locks the paywall

Prompt To Fix With AI
This is a comment left during a code review.
Path: purchasely/references/android/api-reference.md
Line: 408

Comment:
**Null fallback blocks actions**

When `activity` is null or the presentation view is detached, `proceed()` cannot display the SDK dialog, so `alert.onDismiss()` is never triggered. The alert remains pending and blocks the shared action queue, leaving the paywall unresponsive—the exact freeze this example is meant to prevent. Use `alert.onDismiss()` for this fallback instead. The same unsafe fallback also appears in `common-patterns.md`, `migration-v6.md`, and `common-issues.md`.

Greptile automatically discovered a related ticket stating that a null activity or detached view prevents `proceed()` from completing the alert, which informed this comment.

**Source Used:** Linear — [Android v6: onAlert without proceed() blocks the actions queue and locks the paywall](https://linear.app/purchasely/issue/MOB-462/android-v6-onalert-without-proceed-blocks-the-actions-queue-and-locks)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant