Skip to content

fix: Surveys 2.0 native fixes - #48

Merged
boehlerlukas merged 4 commits into
mainfrom
fix/surveys-v2-native
Oct 8, 2026
Merged

boehlerlukas merged 4 commits into
mainfrom
fix/surveys-v2-native

Conversation

@boehlerlukas

@boehlerlukas boehlerlukas commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Surveys 2.0: native iOS fixes

Surveys 2.0 already render in released iOS SDKs, because the survey UI is the Messenger-App web view. This PR fixes what only the native side can:

  • feedbackSent: and outboundSent: fire for 2.0 completions;
  • server-triggered surveys keep their resume data;
  • the card survey dims evenly while the keyboard is up;
  • a survey reopened in the same app session keeps its answers so far.

No public API changes and no version bump; the synced SDK release comes later. No wrapper changes are needed, because Flutter, React Native and Capacitor keep forwarding the same delegate callbacks.

Head at time of writing: ce1daf4 (4 commits). Program overview, master rollout and risks: https://github.com/GleapSDK/Server/pull/2011. Pairs with https://github.com/GleapSDK/Messenger-App/pull/238 and GleapSDK/Android-SDK#44.

Scope

  1. outboundSent: / feedbackSent: fire for v2 surveys.
    • The messenger saves v2 answers itself and reports completion as notify-event outbound-sent. The SDK used to handle only flow-started.
    • GleapFrameManagerViewController now calls feedbackSent: with {formData: <answers by key>, type: "SURVEY"}, the shape GleapFeedback reports a sent legacy survey in.
    • outboundSent: gets outboundId, outbound and formData plus surveyId, responseId, endingId and status: "completed".
    • It tracks outbound-<id>-submitted like a legacy survey, and reports a response once per app session even if the page reports it again.
    • config-update announces surveyCallbacks: true.
    • survey-shown/-answered/-completed/-closed/-legacy, sheet-viewport and height-update are accepted as explicit no-ops.
  2. Server-triggered surveys keep their data.
    • GleapEventLogHelper parseUpdate: (ping and WebSocket actions) used to pass only flow and format. start-survey now carries resume, resumeData (= action.data when resuming) and outboundAction (= action._id || action.id), like the JS SDK.
    • A missing format no longer crashes the start: the dictionary literal no longer gets nil, and the format defaults to survey.
    • Banner and modal show-survey actions are unchanged.
  3. Card survey keyboard scrim. While the keyboard is up, WebKit scrolls the focused field into view, and the uncovered strip showed the app undimmed under the translucent keyboard.
    • A scrim rgba(10,12,16,0.25) behind the web view follows the keyboard frame and its animation curve.
    • It covers only the keyboard's part, so nothing is dimmed twice.
  4. One non-persistent store per app session. GleapWebViewSupport created a fresh nonPersistentDataStore per web view, so a survey reopened in the same session lost its localStorage.
    • All web views now share one private store, still with nothing on disk.
    • The store is replaced when the session's gleapId changes (identity cleared, another user), so drafts never reach the next user. A test covers this.

(Items 3, 4 and 6 of the program are Android-only, see Android-SDK#44.)

Old SDKs (7.0–19.1) without this PR: the messenger sends them one legacy send-feedback after a v2 completion (Messenger-App 795b738). The Server answers it with 201 and stores nothing (Server ed8744886), so their feedbackSent: / outboundSent: and the submitted event fire too.

Risk and safety

  • Behaviour change for apps already on a new SDK:
    • feedbackSent: now fires once per 2.0 completion, as it did for legacy surveys.
    • Callback answer values are 2.0 values (rating 1..5, priority as a choice id). Migrated surveys keep the legacy field names.
  • The private store is shared within an app session. The gleapId reset is what keeps one user's survey state from the next; it is covered by a test.
  • Tests: xcodebuild test -scheme Gleap on the iPhone 17 simulator (what .github/scripts/test.sh runs): 125 tests, 0 failures, re-run on 2026-10-07 at ce1daf4 (level with main, nothing to merge). That includes the new testWebViewsShareTheirStoreUntilTheGleapUserChanges. No new warnings in the touched files. (swift build alone targets macOS, which this UIKit package does not support.)
  • Verified on the iPhone 17 Pro simulator against the local Surveys 2.0 stack (live v2 survey, delegate logging). This branch and released 19.1.0 each fire widgetOpened → feedbackFlowStarted → feedbackSent + outboundSent once → widgetClosed, with no ticket created and one survey response each. Message shapes were checked against Messenger-App#238 and the JS SDK.
  • Not yet checked: the keyboard scrim on a real device, and callbacks against staging. Both are to do in the release pass.

Rollout (this repo)

This PR is independent of the web rollout: released SDKs keep working through the Server ack. Release it with the next synced native SDK version (iOS, Android, then Flutter, React Native and Capacitor through the sdk-release flow) after Server#2011 and Messenger-App#238 are live. Merge together with Android-SDK#44. Master checklist: https://github.com/GleapSDK/Server/pull/2011.

Surveys 2.0 PRs

🤖 Generated with Claude Code

boehlerlukas and others added 3 commits October 7, 2026 11:48
…ion in start-survey

Like the JavaScript SDK: a resume reminder continues the server's copy of the
response and a Surveys 2.0 response records the outbound action that delivered
it. A missing format no longer crashes the start (dictionary literal with nil).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vey keyboard scrim

The messenger saves v2 answers itself and reports completion as notify-event
outbound-sent, which only flow-started was handled for. It now calls
feedbackSent: and outboundSent: in the legacy shape (outboundId, outbound,
formData, plus responseId/endingId) and tracks outbound-<id>-submitted.
survey-* lifecycle and shell layout messages are accepted as no-ops.

Card surveys: while the keyboard is up WebKit scrolls the focused field into
view and the uncovered strip is not page, so the translucent keyboard showed
the app undimmed. A scrim rgba(10,12,16,0.25) behind the web view follows the
keyboard frame; elsewhere the page's own dim stays the only one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ap user

Every web view got a fresh nonPersistentDataStore, so a survey reopened in the
same app session lost its localStorage (answers so far). They now share one
private store; it is replaced when the session's gleapId changes (clear
identity, another user) so form drafts and survey state never reach the next
user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nce per response; announce surveyCallbacks

feedbackSent: gets {formData: <answers by key>, type: "SURVEY"} like a sent
legacy survey (GleapFeedback getFormData), not the bare answers. outboundSent:
passes on everything the messenger reports (surveyId, responseId, endingId,
status) next to outboundId/outbound/formData. A response is reported once per
app session, also when the page reports it again.

config-update carries surveyCallbacks: true, so the messenger sends this SDK no
legacy send-feedback after a completion (older SDKs get one, which the server
acknowledges without storing anything, to fire the same callbacks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@boehlerlukas
boehlerlukas merged commit 7e9505e into main Oct 8, 2026
1 check passed
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