Skip to content

feat(android): resolve show*/trigger() host via explicit Context#128

Closed
ethanpschoen wants to merge 12 commits into
justin/feat/cross-activity-lifecyclefrom
ethanpschoen/feat/explicit-context-host-resolution
Closed

feat(android): resolve show*/trigger() host via explicit Context#128
ethanpschoen wants to merge 12 commits into
justin/feat/cross-activity-lifecyclefrom
ethanpschoen/feat/explicit-context-host-resolution

Conversation

@ethanpschoen

@ethanpschoen ethanpschoen commented Jul 14, 2026

Copy link
Copy Markdown

Description of this change

Add an optional context param to showConsent/showPreferences/ showPreferencesTab/trigger that deterministically supplies the FragmentActivity host, falling back to the tracked/seeded host when omitted. Fixes the case where Ketch is constructed from a non-Activity context (e.g. a ViewModel holding applicationContext) and show*/trigger is called before any Activity has resumed, which previously failed with "No active Activity to host the Ketch experience".

  • findFragmentActivity(): walks the ContextWrapper chain to a FragmentActivity; falls back to the existing tracker/seed chain for a pure-Compose ComponentActivity or when no context is passed.
  • explicitHost is cleared on full dismiss so it can't outlive the call that set it.
  • Also fixes ZTriggerFunctionTest.warmWebView_dispatchesTriggerWithoutError, which left the consent banner open (isShowingExperience still true) before calling trigger(), causing the pre-existing no-host guard to block dispatch. Dismisses via the tag's primary button first, matching the retained-warm-WebView pattern used in ZWebViewRetentionTest.

Why is this change being made?

  • Chore (non-functional changes)
  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

How was this tested? How can the reviewer verify your testing?

Added integration tests, ran sample app

Related issues

KD-17712

Checklist

  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have evaluated the security impact of this change, and OWASP Secure Coding Practices have been observed.
  • I have informed stakeholders of my changes.

Note

Medium Risk
Changes core UI host resolution for consent/preferences/trigger; behavior is additive (optional param) but wrong context could attach dialogs to the wrong Activity.

Overview
Adds an optional context argument to showConsent, showPreferences, showPreferencesTab, and trigger so integrators can supply the hosting FragmentActivity when the SDK was created from applicationContext and no Activity has been tracked yet (avoiding "No active Activity"). findFragmentActivity() walks ContextWrapper chains; explicitHost overrides the lifecycle tracker and is cleared on dismiss.

Integration tests: ZExplicitContextShowTest covers no-arg failure vs explicit context success; ZTriggerFunctionTest dismisses the banner via the primary button (warm WebView) and waits for onHasShownExperience before trigger().

Reviewed by Cursor Bugbot for commit 6f338c5. Configure here.

Expose headless bootstrap/config/profile/consent endpoints via HeadlessApiClient,
wire Ketch/KetchSdk surface APIs, refresh index HTML init, and add unit plus
integration test coverage.
Remove tap-outside dismiss plumbing and index HTML touch handlers from
this branch; those belong in run-sample-skills. Branch is off main only
(no native storage commits).
Drop Index.kt, KetchWebView.kt, Events.kt, and WebView flow changes from
the headless branch. Keep HeadlessApiClient, models, KetchSdk/Ketch REST
methods, data center wiring, and integration tests.
ketch_samples/android is only provisioned on the production CDN
(global.ketchcdn.com / KetchDataCenter.US), not the dev/UAT CDN
(dev.ketchcdn.com). testGetBootstrapConfiguration and
testHeadlessColdStartConsentRoundTrip 404 on org-specific endpoints
(/config/ketch_samples/android/boot.json) against UAT, while
testGetLocationReturnsGeoIP incidentally passes since /ip carries no
org/property path segment. Every other reference to this org/property
in the repo (sample apps, WebView-based integration tests, SDK doc
comments) already targets the production CDN.

Introduced in 30c83c7 with no stated rationale for UAT; verified via
git blame and a live re-run against the real CDN (32/34 -> 34/34).
Mirrors the showConsent/showPreferences warm/cold WebView dispatch
pattern to fire ketch-tag's onFunction rule trigger
(ketch('trigger', 'custom', '<name>', options)). Cold boots defer
the trigger command until the tag finishes loading, since a custom
function has no boot URL param the way consent/preferences do.

- KetchWebView.trigger() / Ketch.trigger() with functionName validation
- Unit tests for functionName validation
- Integration test covering warm/cold dispatch and invalid-name rejection
- Demo button wired into both sample apps
…17712 D)

Add an optional context param to showConsent/showPreferences/
showPreferencesTab/trigger that deterministically supplies the
FragmentActivity host, falling back to the tracked/seeded host when
omitted. Fixes the case where Ketch is constructed from a non-Activity
context (e.g. a ViewModel holding applicationContext) and show*/trigger
is called before any Activity has resumed, which previously failed with
"No active Activity to host the Ketch experience".

- findFragmentActivity(): walks the ContextWrapper chain to a
  FragmentActivity; falls back to the existing tracker/seed chain for
  a pure-Compose ComponentActivity or when no context is passed.
- explicitHost is cleared on full dismiss so it can't outlive the call
  that set it.
- Also fixes ZTriggerFunctionTest.warmWebView_dispatchesTriggerWithoutError,
  which left the consent banner open (isShowingExperience still true)
  before calling trigger(), causing the pre-existing no-host guard to
  block dispatch. Dismisses via the tag's primary button first, matching
  the retained-warm-WebView pattern used in ZWebViewRetentionTest.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 6f338c5. Configure here.

Comment thread ketchsdk/src/main/java/com/ketch/android/Ketch.kt
Base automatically changed from ethanpschoen/feat/onfunction-trigger to justin/feat/cross-activity-lifecycle July 15, 2026 01:00
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