fix(sdk-update): 修复 checkAppUpdate NPE — 服务端 versionName 为 null 时崩溃

Gson 反序列化时会将 JSON null 注入 Kotlin non-null String 字段,绕过默认值。
引入内部 DTO UpdateInfoDto(所有字符串字段可空),转换为 UpdateInfo 时用 orEmpty() 补默认值。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-17 11:32:42 +08:00
父节点 7b52d09758
当前提交 ba8fc74740
共有 2 个文件被更改,包括 30 次插入3 次删除

查看文件

@ -184,7 +184,7 @@ object UpdateSDK {
}
runCatching {
api.checkUpdate(XuqmSDK.appKey, "ANDROID", versionCode, userId).data?.let { info ->
api.checkUpdate(XuqmSDK.appKey, "ANDROID", versionCode, userId).data?.toUpdateInfo()?.let { info ->
val normalized = info.copy(downloadUrl = normalizeDownloadUrl(info.downloadUrl) ?: info.downloadUrl)
val afterIgnore = if (!bypassIgnore && normalized.needsUpdate && !normalized.forceUpdate
&& isVersionIgnored(context, normalized.versionCode)

查看文件

@ -6,12 +6,39 @@ import retrofit2.http.Query
data class ApiResponse<T>(val code: Int, val data: T?, val message: String)
interface UpdateApi {
/** 服务端响应的原始 DTO,所有字符串字段可为 null,防止 Gson 绕过 Kotlin 默认值引发 NPE。 */
internal data class UpdateInfoDto(
val needsUpdate: Boolean = false,
val versionName: String? = null,
val versionCode: Int = 0,
val downloadUrl: String? = null,
val changeLog: String? = null,
val forceUpdate: Boolean = false,
val appStoreUrl: String? = null,
val marketUrl: String? = null,
val requiresLogin: Boolean = false,
val apkHash: String? = null,
) {
fun toUpdateInfo() = UpdateInfo(
needsUpdate = needsUpdate,
versionName = versionName.orEmpty(),
versionCode = versionCode,
downloadUrl = downloadUrl.orEmpty(),
changeLog = changeLog.orEmpty(),
forceUpdate = forceUpdate,
appStoreUrl = appStoreUrl.orEmpty(),
marketUrl = marketUrl.orEmpty(),
requiresLogin = requiresLogin,
apkHash = apkHash,
)
}
internal interface UpdateApi {
@GET("api/v1/updates/app/check")
suspend fun checkUpdate(
@Query("appKey") appKey: String,
@Query("platform") platform: String,
@Query("currentVersionCode") currentVersionCode: Int,
@Query("userId") userId: String? = null,
): ApiResponse<UpdateInfo>
): ApiResponse<UpdateInfoDto>
}