开启minifyEnabled时Retrofit接口注解丢失问题求助
问题描述
Debug构建(未开启minifyEnabled)时一切正常,但开启minifyEnabled后调用Repository.getData会出现运行时错误,提示缺少GET、PUT等注解。
相关代码
Retrofit接口定义
interface Api1 : Api { @GET("/api/v1/data") override suspend fun loadData(): List<Entry> } interface Api2 : Api { @GET("/api/v1/data2") override suspend fun loadData(): List<Entry> } interface Api { suspend fun loadData(): List<Entry> }
Dagger2实例提供代码
@Provides fun provideApi1(retrofit: Retrofit): Api1 = retrofit.create(Api1::class.java) @Provides fun provideApi2(retrofit: Retrofit): Api2 = retrofit.create(Api2::class.java)
Repository调用逻辑
class RepositoryImpl @Inject constructor( val api1: Api1, val api2: Api2 ) : Repository { fun getData(param: Boolean) = flow { val api = if (param) api1 else api2 emit(api.loadData()) } }
已尝试在ProGuard规则中添加注解和接口的保留配置,但问题仍未解决。
问题原因
混淆优化时,当你将Api1/Api2实例赋值给父类型Api变量,混淆器会判定父接口Api的loadData方法没有注解,进而移除子类重写方法上的@GET注解——它认为这些注解在通过父类引用调用时是无用的。而Retrofit运行时依赖反射获取这些注解来生成网络请求,注解丢失就会触发报错。
解决方法
方法1:避免向上转型,直接调用子类方法
修改Repository中的调用逻辑,跳过父类型赋值,直接调用对应子类的方法:
fun getData(param: Boolean) = flow { emit(if (param) api1.loadData() else api2.loadData()) }
这是最直接有效的方案,从根源上避免了混淆器对注解的误移除。
方法2:完善ProGuard规则,强制保留子类注解
在ProGuard规则文件中添加以下配置,确保子类接口的重写方法及其注解不被混淆:
# 保留所有注解属性 -keepattributes *Annotation* # 保留Api接口的所有子类及其方法 -keep class * implements [你的Api接口全限定名] { <methods>; } # 保留所有Retrofit注解标注的方法 -keepclassmembers interface * { @retrofit2.http.* <methods>; }
注意将[你的Api接口全限定名]替换为实际的Api接口完整包路径,比如com.example.app.api.Api。
方法3:给父接口方法添加空注解(临时方案)
在父接口Api的loadData方法上添加一个空的Retrofit注解,让混淆器认为该方法需要保留注解信息:
interface Api { @GET("") suspend fun loadData(): List<Entry> }
这种方案不够优雅,仅作为无法修改业务代码时的临时替代。
内容的提问来源于stack exchange,提问作者RusArtM
相关产品推荐
相关产品推荐

