Skip to content

feat: Android SDK update for version 24.1.0#123

Merged
ArnabChatterjee20k merged 3 commits into
mainfrom
dev
May 19, 2026
Merged

feat: Android SDK update for version 24.1.0#123
ArnabChatterjee20k merged 3 commits into
mainfrom
dev

Conversation

@ArnabChatterjee20k
Copy link
Copy Markdown
Member

@ArnabChatterjee20k ArnabChatterjee20k commented May 18, 2026

This PR contains updates to the Android SDK for version 24.1.0.

What's Changed

  • Added: Realtime presences channel and RealtimePresence types for presence subscriptions
  • Added: Advisor and Presences services
  • Added: Insight, Presence, and Report models with list variants
  • Added: fusionauth, keycloak, and kick providers to OAuthProvider enum
  • Updated: Migrated Gradle build files to Kotlin DSL (build.gradle.kts)
  • Updated: X-Appwrite-Response-Format header to 1.9.5

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 18, 2026

Greptile Summary

This PR delivers the Android SDK 24.1.0 update, adding the Advisor and Presences REST services, a WebSocket-level presence upsert flow in Realtime, new Insight/Report/Presence model types, three new OAuthProvider values, and a full Gradle DSL migration from Groovy to Kotlin.

  • New Insight and Report models declare nullable optional fields with as Any casts in toMap() that throw NullPointerException at runtime when those fields are null.
  • Realtime.kt presence support buffers payloads in pendingPresence, gates sends on the connected event, and removes the dependency on OkHttp internal APIs.
  • ListenableCookieJar replaces removed OkHttp 5.x internal APIs with a local implementation.

Confidence Score: 4/5

The new Insight and Report models will throw NullPointerException from toMap() whenever their optional fields are null — a common state — which needs to be fixed before shipping.

Two new model classes (Insight and Report) have a runtime crash in toMap(): nullable fields are cast with as Any, and Kotlin throws NullPointerException when null is cast to a non-nullable type. Since analyzedAt, dismissedAt, and dismissedBy are null for most responses, this will affect a broad set of callers. The rest of the change is well-structured and low risk.

library/src/main/java/io/appwrite/models/Insight.kt and library/src/main/java/io/appwrite/models/Report.kt both have the toMap() null-cast issue.

Important Files Changed

Filename Overview
library/src/main/java/io/appwrite/models/Insight.kt New model for Advisor service insights; toMap() throws NPE for null optional fields due to as Any cast; nullable fields also declared as var instead of val.
library/src/main/java/io/appwrite/models/Report.kt New model for Advisor service reports; toMap() throws NPE when analyzedAt is null; analyzedAt declared as var instead of val.
library/src/main/java/io/appwrite/services/Realtime.kt Adds presence upsert support with pendingPresence buffering and appConnected gate; migrates socket to public WebSocket interface.
library/src/main/java/io/appwrite/services/Presences.kt New REST service for presence CRUD; contains unused okhttp3.Cookie and java.io.File imports.
library/src/main/java/io/appwrite/services/Advisor.kt New REST service for Advisor reports and insights; unused okhttp3.Cookie and java.io.File imports present.
library/build.gradle.kts Migrated from Groovy DSL to Kotlin DSL; upgrades OkHttp to 5.x and other dependencies.
library/src/main/java/io/appwrite/cookies/ListenableCookieJar.kt Removes dependency on OkHttp internal APIs broken by the 5.x upgrade; replaces with local implementation.
.github/workflows/publish.yml Pins GitHub Actions to full commit SHAs; upgrades checkout to v6 and setup-java to v5.

Reviews (2): Last reviewed commit: "chore: update Android SDK to 24.1.0" | Re-trigger Greptile

Comment on lines +117 to +123
if (cookie.persistent) {
if (cookie.expiresAt == Long.MIN_VALUE) {
append("; Max-Age=0")
} else {
append("; Expires=").append(formatHttpDate(cookie.expiresAt))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Long.MIN_VALUE sentinel branch is dead code

OkHttp 5.x only sets expiresAt = Long.MIN_VALUE when the incoming Max-Age value is negative or overflows MAX_AGE_CAP. A Max-Age=0 cookie gets expiresAt ≈ System.currentTimeMillis() — not Long.MIN_VALUE. The branch never fires in practice and the cookie is serialised with Expires=<past-timestamp> instead of Max-Age=0. Both forms expire the cookie correctly in java.net.CookieHandler, but the intent of the guard should be documented so future reviewers can verify correctness if OkHttp internals change.

Suggested change
if (cookie.persistent) {
if (cookie.expiresAt == Long.MIN_VALUE) {
append("; Max-Age=0")
} else {
append("; Expires=").append(formatHttpDate(cookie.expiresAt))
}
}
if (cookie.persistent) {
// OkHttp sets expiresAt=Long.MIN_VALUE only for negative/overflow Max-Age;
// Max-Age=0 produces expiresAt≈currentTimeMillis(), which serialises
// as a past Expires= date — both cause CookieHandler to delete the entry.
if (cookie.expiresAt == Long.MIN_VALUE) {
append("; Max-Age=0")
} else {
append("; Expires=").append(formatHttpDate(cookie.expiresAt))
}
}

Comment on lines +43 to +56
@SerializedName("status")
var status: String?,

/**
* Presence source.
*/
@SerializedName("source")
val source: String,

/**
* Presence expiry date in ISO 8601 format.
*/
@SerializedName("expiresAt")
var expiresAt: String?,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 status and expiresAt are var while every other field is val

Mutable fields in a data class break structural equality (equals/hashCode), make the class unsafe as a map key, and are inconsistent with every other model in this PR. Unless the SDK intentionally mutates these fields after construction, they should be val.

Suggested change
@SerializedName("status")
var status: String?,
/**
* Presence source.
*/
@SerializedName("source")
val source: String,
/**
* Presence expiry date in ISO 8601 format.
*/
@SerializedName("expiresAt")
var expiresAt: String?,
@SerializedName("status")
val status: String?,
/**
* Presence source.
*/
@SerializedName("source")
val source: String,
/**
* Presence expiry date in ISO 8601 format.
*/
@SerializedName("expiresAt")
val expiresAt: String?,

*
* The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
*
* @param {string} cookie
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 JSDoc-style {string} type annotation in KDoc comment

The @param {string} cookie uses JSDoc syntax rather than KDoc/Javadoc style, which is inconsistent with every other KDoc block in Client.kt.

Suggested change
* @param {string} cookie
* @param cookie

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +128 to +130
"analyzedAt" to analyzedAt as Any,
"dismissedAt" to dismissedAt as Any,
"dismissedBy" to dismissedBy as Any,
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 In Kotlin, casting a nullable value to a non-nullable type with as Any throws NullPointerException at runtime when the value is null. Since analyzedAt, dismissedAt, and dismissedBy are all String? and will be null for any insight that hasn't been analyzed or dismissed, every call to toMap() on such an instance crashes. The same bug exists in Report.toMap() for its analyzedAt field. Change these three entries to as Any? (and update the return type to Map<String, Any?>), or omit null entries from the map.

Suggested change
"analyzedAt" to analyzedAt as Any,
"dismissedAt" to dismissedAt as Any,
"dismissedBy" to dismissedBy as Any,
"analyzedAt" to analyzedAt as Any?,
"dismissedAt" to dismissedAt as Any?,
"dismissedBy" to dismissedBy as Any?,

@ArnabChatterjee20k ArnabChatterjee20k merged commit 85a5b4b into main May 19, 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.

3 participants