开启Gradle的minifyEnabled后无法创建MesResponse类转换器求助
启用
minifyEnabled true后Retrofit-Kotlin序列化转换器创建失败问题解决 问题描述
启用混淆后出现以下错误:
java.lang.IllegalArgumentException: Unable to create converter for class com.th3pl4gu3.mes.models.MesResponse
for method MesApiService.getServices
用户相关代码如下:
AppContainer.kt
/** * Dependency Injection container at the application level. */ interface AppContainer { val onlineServiceRepository: ServiceRepository } /** * Implementation for the Dependency Injection container at the application level. * * Variables are initialized lazily and the same instance is shared across the whole app. */ class DefaultAppContainer(private val context: Context): AppContainer { private val BASE_URL = "https://..." /** * Use the Retrofit builder to build a retrofit object using a kotlinx.serialization converter */ @OptIn(ExperimentalSerializationApi::class) private val retrofit: Retrofit = Retrofit.Builder() .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) .baseUrl(BASE_URL) .build() /** * Retrofit service object for creating api calls */ private val retrofitService: MesApiService by lazy { retrofit.create(MesApiService::class.java) } }
ServiceRepository.kt
/** * Repository that fetch service list from Mes API. */ interface ServiceRepository { /** Fetches list of services from Mes API */ suspend fun getMesServices(): MesResponse }
MesApiServiceRepository.kt
class MesApiServiceRepository( private val mesApiService: MesApiService ) : ServiceRepository { /** Fetches list of Services from Mes API */ override suspend fun getMesServices(): MesResponse = mesApiService.getServices() }
MesResponse.kt
@kotlinx.serialization.Serializable data class MesResponse( val services: List<Service>, val message: String, val success: Boolean )
proguard-rules.pro
##################################### ########## Kotlin Metadata ########## ##################################### -dontwarn org.jetbrains.annotations.** -keep class kotlin.Metadata { *; } ################################## ########### MES Models ########### ################################## -keep class com.th3pl4gu3.mes.models.MesResponse -keep class com.th3pl4gu3.mes.models.** {*;} -keep class com.th3pl4gu3.mes.data.** {*;} -keep class com.th3pl4gu3.mes.api.** {*;} -keep class com.th3pl4gu3.mes.di.** {*;} ############################### ########## Retrofit2 ########## ############################### # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and # EnclosingMethod is required to use InnerClasses. -keepattributes Signature, InnerClasses, EnclosingMethod # Retrofit does reflection on method and parameter annotations. -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations # Keep annotation default values (e.g., retrofit2.http.Field.encoded). -keepattributes AnnotationDefault # Retain service method parameters when optimizing. -keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* <methods>; } # Ignore annotation used for build tooling. -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement # Ignore JSR 305 annotations for embedding nullability information. -dontwarn javax.annotation.** # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. -dontwarn kotlin.Unit # Top-level functions that can only be used by Kotlin. -dontwarn retrofit2.KotlinExtensions -dontwarn retrofit2.KotlinExtensions$* # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy # and replaces all potential values with null. Explicitly keeping the interfaces prevents this. -if interface * { @retrofit2.http.* <methods>; } -keep,allowobfuscation interface <1> # Keep inherited services. -if interface * { @retrofit2.http.* <methods>; } -keep,allowobfuscation interface * extends <1> # Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items). -keep,allowobfuscation,allowshrinking interface retrofit2.Call -keep,allowobfuscation,allowshrinking class retrofit2.Response # With R8 full mode generic signatures are stripped for classes that are not # kept. Suspend functions are wrapped in continuations where the type argument # is used. -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
解决方案
问题根源是R8/ProGuard在混淆过程中移除了Kotlin序列化所需的注解元数据和相关类,导致Retrofit无法创建对应的转换器。需要更新proguard-rules.pro,添加以下规则:
# 保留Kotlin序列化核心类与注解 -keep class kotlinx.serialization.** { *; } -dontwarn kotlinx.serialization.** # 保留所有带@Serializable注解的类及其成员,确保序列化元数据不丢失 -keep @kotlinx.serialization.Serializable class ** { *; } # 保留序列化器的生成方法(默认序列化器依赖这些方法) -keepclassmembers class ** { @kotlinx.serialization.Serializer <methods>; } # 确保序列化所需的注解属性被保留 -keepattributes RuntimeVisibleAnnotations, AnnotationDefault, InnerClasses, Signature
补充说明
- 原规则中仅保留了models类,但未保留
@Serializable注解以及Kotlin序列化库的核心组件,这些是序列化转换器工作的关键。 - 如果使用的是R8 full mode,确保上述规则完全覆盖序列化相关的保留逻辑,避免元数据被剥离。
- 验证依赖中已正确引入kotlinx-serialization-json库,版本与Kotlin版本保持兼容。
内容的提问来源于stack exchange,提问作者Mervin Hemaraju
相关产品推荐
相关产品推荐

