You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit+Moshi+Kotlin捕获并上报服务端错误JSON

精准捕获JSON解析异常并记录错误JSON

针对你遇到的Crashlytics中偶发的必填字段缺失崩溃,以下是几种精准捕获错误并记录对应JSON的方案,既不用把所有字段设为可空,也不会产生全量日志:

1. 单个解析点包裹Try-Catch(基础方案)

根据你使用的JSON解析库,在解析逻辑外层包裹try-catch,捕获必填字段缺失的异常,同时上报原始JSON:

针对Gson

fun <T> parseWithGson(json: String, targetType: Type): T? {
    return try {
        Gson().fromJson(json, targetType)
    } catch (e: JsonSyntaxException) {
        // 上报至Firebase事件
        FirebaseAnalytics.getInstance().logEvent("json_parse_failure", bundleOf(
            "error_detail" to e.message.orEmpty(),
            "raw_json" to json
        ))
        // 同时保留Crashlytics崩溃记录
        FirebaseCrashlytics.getInstance().recordException(e)
        // 若不需要避免崩溃,可直接抛出异常
        throw e
    }
}

针对Moshi

Moshi中必填字段缺失会抛出JsonDataException,处理逻辑类似:

val moshi = Moshi.Builder().build()
fun <T> parseWithMoshi(json: String, targetType: Type): T? {
    val adapter = moshi.adapter<T>(targetType)
    return try {
        adapter.fromJson(json)
    } catch (e: JsonDataException) {
        FirebaseAnalytics.getInstance().logEvent("json_parse_failure", bundleOf(
            "error_detail" to e.message.orEmpty(),
            "raw_json" to json
        ))
        FirebaseCrashlytics.getInstance().recordException(e)
        throw e
    }
}

2. Retrofit全局拦截(网络请求场景)

如果崩溃来自Retrofit接口的JSON解析,可以自定义ConverterFactory,全局拦截解析异常并上报:

自定义Gson Converter

class SafeGsonConverterFactory(private val gson: Gson) : Converter.Factory() {
    override fun responseBodyConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        val delegateAdapter = gson.getAdapter(TypeToken.get(type))
        return Converter { responseBody ->
            val rawJson = responseBody.string()
            return@Converter try {
                delegateAdapter.fromJson(rawJson)
            } catch (e: JsonSyntaxException) {
                // 额外上报请求URL,方便定位接口
                FirebaseAnalytics.getInstance().logEvent("retrofit_parse_failure", bundleOf(
                    "error_detail" to e.message.orEmpty(),
                    "raw_json" to rawJson,
                    "request_url" to "${retrofit.baseUrl()}${(retrofit.requestFactory()?.toString() ?: "")}"
                ))
                FirebaseCrashlytics.getInstance().recordException(e)
                throw e
            } finally {
                responseBody.close()
            }
        }
    }

    companion object {
        fun create(gson: Gson = Gson()): SafeGsonConverterFactory {
            return SafeGsonConverterFactory(gson)
        }
    }
}

替换Retrofit默认Converter

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(SafeGsonConverterFactory.create())
    // 其他配置
    .build()

关键说明

  • 以上方案只会在解析出错时记录对应的JSON,不会产生全量请求日志,避免日志臃肿
  • 若需要保持原有崩溃行为,捕获异常后重新抛出即可,Crashlytics仍会收到崩溃报告,同时你能拿到错误JSON用于反馈给服务端
  • 可以根据需求选择上报到自有服务端或Firebase事件,核心是保留原始错误JSON和异常信息

内容的提问来源于stack exchange,提问作者HBB20

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:25:22