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

开启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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:38:42