Repository navigation
Docs(android): Offline Support for SDK v5.1.0 - #584
Conversation
Adds an Offline Support group to the Android v5 SDK docs: overview, enable, show cached data, send while offline, stay in sync, media caching, encrypt the cache, and a configuration & API reference. Adds shared deprecation callouts for the two-phase fetch listeners and MessageSentListener, the nav group in docs.json and the llms index entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Swaps the fetch, single-item and send samples on 24 Android v5 pages to the two-phase fetch listeners and MessageSentListener, adds the 5.1.0 deprecation callout, an Offline Behaviour section with the cached vs server-only filters for each builder, and short offline notes on setup, auth, listeners, edit, delete, group and connection pages. Fixes the ReactionsRequest class name on the reactions page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…listener on the acting device Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…view Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… SDK 5.1.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wipe, deprecated overloads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…adle tab titles Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r from isOfflineEnabled Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rs, blocked users, reactions, server-only filters Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, failure reasons, queue limits, snippets Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e event or next sync Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lds table Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ken anchors, Groovy fence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d ReactionEvent Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne; full snapshot list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ketanyekale
left a comment
There was a problem hiding this comment.
Thanks for this — the structure is genuinely good, and the mechanical side is clean (details at the bottom). The issues below are all content-consistency ones, and four of them would change what an integrator builds, so I'd like them settled before this merges.
Blocking
1. onMessagePending is documented as unconditional in 36 places, contradicting the page that defines it.
36 code comments across three pages say it fires on every send:
sdk/android/v5/send-message.mdx:119and 31 more in that file,ai-moderation.mdx:88,:113,upload-files.mdx:432,:494:
// Fires on every send while offline support is enabled; message.getStatus() == MessageStatus.PENDING
But offline-send.mdx says it does not:
:53— "If the message cannot be queued at all, for example because its media could not be copied (codeERROR_OFFLINE_MEDIA_COPY_FAILED, reasonPERMANENT), onlyonErrorfires.":355— "A refused send (QUEUE_FULL/BYTE_OVERFLOW) is never queued, so it fires noonMessagePending".
send-message.mdx is the page most readers land on. Someone who builds their optimistic-UI row in onMessagePending and treats it as the guaranteed first event will silently drop refused and un-copyable-media sends — the row never appears and the only signal is onError. This is the most-replicated wrong statement in the PR.
2. Three mutually incompatible Kotlin signatures for the same callback.
onCachedMessages / onServerMessages appear in three Kotlin forms; at most one compiles:
messages: List<BaseMessage>— 9 occurrences, e.g.offline-cached-data.mdx:103,save-message.mdx,pin-message.mdxmessages: List<BaseMessage?>— 8 occurrences, all inreceive-messages.mdx(:281,:285,:366,:370,:452,:456,:526,:530, …)messages: List<BaseMessage?>?—threaded-messages.mdx:200,:204,:260,:264
offline-reference.mdx:102 declares only onCachedMessages(List<BaseMessage>), and every Java tab on these same pages uses the non-null form — so this is also a Java/Kotlin parity break within receive-messages.mdx and threaded-messages.mdx. A Kotlin reader copying from either gets "nothing overrides" / type-mismatch errors with no way to tell which form is right.
3. retryAllFailedMessages scope is stated two ways.
offline-reference.mdx:69— "Retry every failed message in the outbox."offline-send.mdx:288— "retries transient failures only; permanent ones are skipped." (same at:28)
A reader who builds a "Retry all" button from the reference expects every FAILED row to clear. PERMANENT ones stay stuck with no callback explaining why, and the only documented way out is discardLocalMessage per id.
4. The per-builder filter matrix the cached-data page promises isn't on the reference page.
offline-cached-data.mdx:337— "The full per-builder matrix of what the cache answers lives in the [Offline Configuration & API Reference]"offline-cached-data.mdx:240— "per-builder details live on each request's own page and in the [Offline Configuration & API Reference]"
offline-reference.mdx has no such matrix (zero hits for searchKeyword or "Server only"). The matrices this PR adds actually live on the individual request pages — retrieve-conversations.mdx, retrieve-users.mdx:558, retrieve-group-members.mdx:199, thread-subscription.mdx, mentions.mdx. So :337 raises exactly the right alarm ("one innocuous builder flag can silently disable the cached phase for a whole screen") and then sends the reader to a page that can't answer it. Either add the matrix to the reference or point at the per-request pages.
Worth fixing in the same pass
5. autoSendPendingOnReconnect(false) — queued-then-failed, or failed immediately?
offline-reference.mdx:49— "Gates only the outbox flush"offline-send.mdx:340— "a send that gets no answer becomesFAILED(TRANSIENT)" (so it was queued)offline-send.mdx:136— "an offline send becomesFAILED(TRANSIENT) right away" (so it never was)
This decides whether the reader's outbox UI needs a queued state at all.
6. Wrong recovery API named for queued messages. offline-sync.mdx:188 says forceSyncNow "does not send queued messages (use retryMessage or retryAllFailedMessages for those)". But per offline-send.mdx:288 retryAllFailedMessages acts on FAILED only — it does nothing for the PENDING messages that sentence is about. Only retryMessage applies.
7. Listener type qualification is inconsistent, so imports can't be derived. MessageFetchListener, MessageSentListener, SyncListener and OfflineMessageListener are always shown nested (CometChat.SyncListener, offline-sync.mdx:65), but OfflineCacheResetListener (offline-sync.mdx:271, :283, offline-encryption.mdx:156), MediaCallbackListener and MediaDownloadListener (offline-media-caching.mdx:157, :177, :210) are top-level. The Kotlin forms also disagree on kind: object : OfflineCacheResetListener() vs object : MediaCallbackListener {. The registration table at offline-reference.mdx:84-92 doesn't disambiguate.
8. getPendingMessages return type stated two ways. offline-reference.mdx:28 annotates it // List<BaseMessage>; the table at :67 correctly says void, delivering via CallbackListener. Minor, but it's in the block that gets copied.
9. onError nullability differs. offline-send.mdx:98 uses onError(e: CometChatException?); send-message.mdx:152 and ai-moderation.mdx:99 use non-null onError(e: CometChatException). One won't compile.
Nit. offline-send.mdx:143 "Offer the user a manual retry (see below)" sits ~140 lines above "Retry and Discard" — a named link would resolve it.
What I checked that's clean
- Build safety: 0 unresolved nav refs; Mintlify Deployment and link-rot both pass.
- Redirects: purely additive (0 removed, 0 renamed), so the
+0redirect delta is correct, not an omission. - Links: 0 broken internal links across 72 scanned files, and none pre-existing in
sdk/android/v5/. - Snippet variables: all 26
<OfflineDeprecated*>call sites passmethod=, and every Listener site passesreplacement=— nothing renders a literal{method}. - Numeric defaults and limits: every figure agrees across pages — 100 conversations / 500 messages per conversation / 250 MB / 500 MB media / 50 pending / 5 reconnect attempts / 1000-change sync page / SQLCipher 4.13.0 / minSdk 21.
- Enums and error codes:
MessageStatus,MessageFailureReason,OfflineCacheResetReason,SyncOutcome,PendingMessageOverflowPolicy,UploadFileItemStatus.Stateall agree betweenoffline-reference.mdx:126-138and the guides. - Listener-to-request pairing: all 11 two-phase listeners pair with the right request type and callback names on every modified page.
- Version pins: consistent at 5.1.0 throughout. No images in the new pages, so no stale screenshots.
- Cross-checked against #593: all 15
OfflineConfigoptions match the Flutter PR field-for-field with identical defaults and correct per-platform casing (REJECT_NEWEST/rejectNewest,AUTO/auto). That part is carefully done.
One cross-PR discrepancy: the media re-sign path lists HTTP 401, 403 or 410 here (offline-media-caching.mdx:152) but only 403 or 410 in #593 (sdk/flutter/offline-media-caching.mdx:107). Real platform difference, or is one incomplete?
Scope of this review
I could not verify API names, signatures or defaults against SDK source — the release-v5-v5.1.0 branch this PR cites isn't in the public cometchat/chat-sdk-android repo (that repo holds maven artifacts only). Everything above is internal-consistency and reader-experience review. Someone with access to the release branch should still confirm the callback names and the List<BaseMessage> nullability independently.
Not merging, per your note that 5.1.0 isn't published yet — the install steps correctly pin 5.1.0 everywhere, which is exactly why this has to wait for the release.
…natures, retry scope, listener types - onMessagePending: 36 comments corrected to fire once the message is queued (not every send); refused/media-copy-failed sends fire only onError - Kotlin onCachedMessages/onServerMessages standardised to List<BaseMessage> (receive-messages, threaded-messages) - retryAllFailedMessages scope: retries transient failures; permanent ones skipped (discard via discardLocalMessage) - offline-cached-data: re-pointed the per-builder matrix to each request's own Offline Behaviour table - offline-send: autoSendPendingOnReconnect(false) now described as queued-then-TRANSIENT; manual-retry link to Retry and Discard - offline-sync: forceSyncNow recovery names only retryMessage for queued messages - offline-reference: listener type qualification note; getPendingMessages comment fixed (void + callback delivery) - Kotlin onError overrides made non-null for consistency Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the thorough review, Ketan. I checked every point against the SDK's 5.1.0 release branch and pushed the fixes in 681e853. Fixed
Media re-sign (401 vs 403/410): Android does re-sign on 401, 403 and 410, so this page is right. The Flutter page correctly describes what the Flutter SDK does today. The gap is in the Flutter SDK, not in the docs, and we'll handle it on the SDK side. Please keep this unmerged until 5.1.0 is published. |
ketanyekale
left a comment
There was a problem hiding this comment.
Approving. I re-checked every point against 681e853c rather than taking the summary on trust, and all ten are genuinely fixed.
Verified fixed
onMessagePending— all 36 comments now read "Fires once the message is queued…" (32 insend-message.mdx, 2 inai-moderation.mdx, 2 inupload-files.mdx). No "on every send" remains anywhere, so the page most readers land on no longer contradictsoffline-send.mdx:53/:355.- Kotlin signatures — collapsed to a single form: 19 ×
messages: List<BaseMessage>, matching the 18 Java tabs and the reference row atoffline-reference.mdx:102. The nullable-element and nullable-list variants are gone. retryAllFailedMessages—offline-reference.mdx:69now reads "Retry the failed messages whose failure was transient; permanent failures are skipped — discard them withdiscardLocalMessage", which agrees withoffline-send.mdx:288and also answers the "how do I clear a PERMANENT one" gap.- Filter matrix — both pointers fixed, not just the one I quoted.
:240and:337now link to the per-request Offline Behaviour tables by name. autoSendPendingOnReconnect(false)—:136and:340now tell the same story (queued first,onMessagePendingfires, then the immediate attempt failsTRANSIENT), andoffline-reference.mdx:49is consistent with it.forceSyncNow—offline-sync.mdx:188now names onlyretryMessagefor queued messages.- Listener qualification —
offline-reference.mdx:95now states the kind and package of each: nested abstract classes onCometChat,OfflineCacheResetListeneras a top-level abstract class incom.cometchat.chat.core, the media listeners as top-level interfaces incom.cometchat.chat.models. That resolves the imports question without churning the snippets. getPendingMessages—:28and:67both sayvoid, delivering to the listener.onErrornullability — non-null on every page this PR changes. The two remaining nullable forms are inflag-message.mdx, which this PR doesn't touch, so they're out of scope here.- Nit — "see below" is now
[Retry and Discard](#retry-and-discard), and that anchor resolves to the## Retry and Discardheading at:283.
Re-ran the mechanical checks after the fixes, since the change added a lot of new cross-links: 0 unresolved navigation refs, 0 broken internal links across 72 scanned files, 0 pre-existing broken links in sdk/android/v5/, still purely additive so no redirects needed, and both new anchors resolve. Mintlify Deployment and link-rot remain green.
On the 401/403/410 difference — thanks for running that down. Taking your answer that Android re-signs on all three and the Flutter page describes current Flutter behaviour, this page is correct and the divergence belongs in the Flutter SDK. Nothing to change here.
Scope of this review, unchanged: this covers docs integrity and internal consistency, not the documented API surface against SDK source — the release-v5-v5.1.0 branch isn't in the public cometchat/chat-sdk-android repo, and nothing was built or run. Your check against the release branch is what that rests on.
Not merging — holding until 5.1.0 is published, as you asked.
jitvarpatil
left a comment
There was a problem hiding this comment.
🤖 Review Buddy (review-docs-pr)
Recommendation: request changes. Automated review; the final decision stays with a maintainer.
TL;DR: The docs are structurally safe, and the API reference matches the SDK source. The one blocker is timing: this PR must not merge until 5.1.0 is published, because the main install snippets pin a version that can't be downloaded yet. No content edit is needed for that. The P2s are small wording gaps and shouldn't hold the release.
Reviewed at 681e853c. This adds what the earlier reviews couldn't check: the documented API compared with the SDK's release-v5-v5.1.0 branch (5da06754).
P1: should fix before merge
- The install snippets point to an unpublished version:
sdk/android/v5/setup.mdx:50,sdk/android/v5/overview.mdx:70,sdk/android/v5/upgrading-from-v4.mdx:15andsdk/android/v5/offline-enable.mdx:42,47. The 5.1.0 AAR returns 404 on the documented Maven repo, while 5.0.7 is served and is still the latest GitHub release. If this merges first, new integrators following Setup get a dependency resolution failure. The author and Ketan have already agreed to hold, so this finding just records that as a merge condition. Re-check that the artifact resolves before merging.
P2: nits and wording
sdk/android/v5/offline-reference.mdx:177: "The old overloads keep working: ... the server result arrives in theonServer…/onMessageSentcallback instead ofonSuccess" describes the new listeners, not the old overloads. Deprecated overloads still receiveonSuccess. Read literally, this tells people they have to migrate their callbacks anyway.sdk/android/v5/offline-reference.mdx:166-167: the error table is incomplete.ERROR_PENDING_QUEUE_LIMITlists only refused sends, butDROP_OLDESTeviction also raises it withQUEUE_OVERFLOW(offline-send.mdx:351,Outbox.java:818).ERROR_OFFLINE_MESSAGE_PERSIST_FAILEDomits the send path. A send that can't be saved fails with this code and reasonPERMANENT(Outbox.java:531).
sdk/android/v5/offline-send.mdx:143: the table says to offer a manual retry for anyFAILEDmessage. But:192says retry won't help forPERMANENT, and:359says refused or evicted messages fail withERROR_OFFLINE_MESSAGE_NOT_FOUND. It should tell readers to checkgetFailureReason()first.sdk/android/v5/offline-media-caching.mdx:59: "Sending media always works in both modes" conflicts with theBYTE_OVERFLOWrefusal atoffline-send.mdx:353. Something like "Both modes support sending media" would avoid the absolute.sdk/android/v5/offline-reference.mdx:35: the page calls itself "the full surface", but it leaves outMessageSource/getSource(), whichoffline-sync.mdx:151uses, and thedebugTracing(boolean)builder option. Add them, or soften the claim ifdebugTracingis meant to stay undocumented.sdk/android/v5/offline-encryption.mdx:46: this doesn't mention that adding SQLCipher pulls inandroidx.sqlite:sqlite:2.2.0, which requirescompileSdk31 or higher according to the SDK'sbuild.gradlecomments. Apps on a lowercompileSdkwould hit a build error with no hint in the docs. I took this from those comments and didn't reproduce it.offline-send.mdx(7 places) andoffline-enable.mdx(1 place): Kotlin samples declaree: CometChatExceptionas non-null and then usee?.code/e?.message. This compiles with a warning.offline-cached-data.mdxalready usese.code.
What passed
- Build and links: 0 unresolved navigation refs, 0 orphans, 0 removed or renamed URLs (redirects unchanged at 926), and no new images. Mintlify Deployment and link-rot checks are green.
- Broken links: none in
sdk/android/v5/. The analyzer found two in v4 pages this PR doesn't change:sdk/android/upgrading-from-v3-guide.mdx→/sdk/android/calling-setup, andsdk/android/real-time-listeners.mdx→/sdk/android/default-calling. - Checked against SDK source:
OfflineConfigsetters, defaults and clamps- public
CometChatoffline methods and listener registration - two-phase and offline listener callback signatures (
List<BaseMessage>is correct) - enum values and error codes
- the deprecated-overload table
- the 401/403/410 re-sign rule, the 5-attempt cap and the 1000-change sync page
FIELD_AES_GCMandSOFTWAREare correctly left out, because Android never reports them
- Earlier review: spot checks of Ketan's fixes still hold (for example, the
onMessagePendingwording andretryAllFailedMessagesscope).
Not checked
- Nothing was built or run: the code samples weren't compiled, and no behaviour was exercised on a device.
- Behaviour claims: I traced a sample of them to source, not all of them.
- Modified pages: I reviewed
setup,overview,upgrading-from-v4,real-time-listeners,connection-statusandauthentication-overviewby diff. The other changed v5 pages got only pattern checks for stale callbacks, version pins and snippet use, not a line-by-line read. - Flagged code examples:
campaigns.mdx:387,408still usesCallbackListener, but oncategoriesRequest, which isn't in the deprecation table, so I didn't count it as a finding.
v5.1.0New
Enhancements
Fixes
Deprecations
|
Summary
Public docs for offline support in the Android SDK v5.1.0 (SDK only, no UI Kit). Draft for review; the 5.1.0 changelog entry is still to come.
New: Offline Support group (SDKs → Android → v5, after Messaging), 8 pages:
offline-overview: what it does and how the cached-then-server flow worksoffline-enable:OfflineConfigsetup and optionsoffline-cached-data: two-phase listeners (onCached…→onServer…→onError) for every list and single-item fetch, plus which filters are server-onlyoffline-send:MessageSentListener(onMessagePending→onMessageSent), the outbox, and failure/retry behaviouroffline-sync: catching up on reconnectoffline-media-caching: media cache modes and limitsoffline-encryption: an encrypted local storeoffline-reference: config, callbacks, error codes, and old→new overload mappingUpdated: 24 existing v5 pages. These now use the two-phase listeners and
MessageSentListenerin Java and Kotlin. Each page carries one "deprecated from 5.1.0" callout (two shared snippets insnippets/sdk/), and the affected pages get an Offline Behaviour table and notes on server-only filters.Also: the nav entry in
docs.jsonand the pages listed insdk/android/v5/llms-android-v5.mdx.Review notes
release-v5-v5.1.0branch. Every cached vs server-only claim and every callback name was checked against that code.sdk/android/.mainhave an unescaped<21(e.g.react >=18 <21), which breaksmint dev/mint broken-linkslocally. Skipping them in.mintignoreworks; that change is not in this PR.How to review
Open the Mintlify preview from the checks below, start at Android → v5 → Offline Support → Overview, then spot-check the changed Messaging, Conversations, Users and Groups pages.
🤖 Generated with Claude Code