Android Kotlin ProGuard 规则错误?

Posted

技术标签:

【中文标题】Android Kotlin ProGuard 规则错误?【英文标题】:Android Kotlin ProGuard Rules Wrong? 【发布时间】:2020-11-11 08:27:38 【问题描述】:

目前我有一个可供多个其他项目使用的库,但是在使用 .aar 时遇到代码混淆问题,尤其是在某些类中:

这个用于处理后端响应或异步任务等。

sealed class Result<out T : Any> 
    open class Success<out T : Any>(val data: T) : Result<T>()
    open class Error(val error: ErrorModel) : Result<Nothing>()

这个可以作为库的初始化器或类似的东西:

class LibApp private constructor(
    val appContext: Context
) 

    companion object 
        @JvmStatic lateinit var instance: LibApp
            private set

        fun init(
            appContext: Context
        ) 
            if (this::instance.isInitialized.not()) 
                instance = LibApp(appContext)
            
        
    

我使用的规则是:

#noinspection ShrinkerUnresolvedReference
-keep class com.cross.project.compilation.testlib.response.**  *; 
-keep class com.cross.project.compilation.testlib.LibApp.**  *; 

目前我有 3 种构建类型和 2 种风格:

buildTypes 
        release 
            debuggable false
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        

        releaseDebug
            debuggable true
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        

        debug
            debuggable true
            minifyEnabled false
        
    

    flavorDimensions "libFlavors"

    productFlavors 

        dev 

        

        prod 

        

    

当我检查消费者项目中的发布变体的反编译源时,我得到:

Result 从 Success 返回中获取

public sealed class Result<out T : kotlin.Any> private constructor() 
    public open class Error public constructor(error: com.cross.project.compilation.testlib.response.ErrorModel) : com.cross.project.compilation.testlib.response.Result 
        public final val error: com.cross.project.compilation.testlib.response.ErrorModel /* compiled code */
    

    public open class Success<out T : kotlin.Any> public constructor(data: T) : com.cross.project.compilation.testlib.response.Result 
        public final val data: T /* compiled code */
    

这改变了变体中的编码方式,类似于 dev 中的代码:

 return when (val response = accountService.getAccountData()) 
            is Result.Success -> ConsumerResult.Success(response.data)
            is Result.ErrorModel -> ConsumerResult.Failure(response.errorModel)
        

到这里:

 return when (val response = accountService.getAccountData()) 
            is Result.Success<*> -> ConsumerResult.Success((response.data as AccountData))
            is Result.ErrorModel -> ConsumerResult.Failure(response.errorModel)
        

LibApp 类由于某种原因被删除。

我尝试修改规则以避免这些问题,但仅通过应用以下内容成功地保留了 LibApp 类:

-keepclasseswithmembers class com.cross.project.compilation.testlib.LibApp 
    public *;


-keep @interface kotlin.Metadata 
  *;

-keepattributes RuntimeVisibleAnnotations

并且还将@Keep注解添加到类中的每个级别,例如:

@Keep class LibApp private constructor(
    ...

    @Keep
    companion object 
       ...

        @Keep
        fun init(
        ...

但是我没有运气修改规则以保持 Result.Success 的通用返回,知道我做错了什么吗?

作为附加信息,我正在使用和构建 maven-publish 插件:

Android Gradle 插件 4.0.1 Gradle 包装器 6.1.1

这个问题好像是我升级后出现的:

Android Gradle 插件 3.6.3 Gradle 包装器 5.6.4

【问题讨论】:

【参考方案1】:

Result.Error 中的 Nothing 类型在被 R8 混淆时被删除。尝试在 build.gradle 文件中添加以下内容:

buildscript 
     repositories 
       // other repos are omitted 
        maven  url  'https://storage.googleapis.com/r8-releases/raw' 
    
    dependencies 
        classpath 'com.android.tools:r8:2.1.68'
        // other dependencies are omitted 

在 proguard 文件中声明 Result 类型以防止混淆

-keep class [path_to_class].Result  *; 
-keep class [path_to_class].Result$**  *; 

【讨论】:

以上是关于Android Kotlin ProGuard 规则错误?的主要内容,如果未能解决你的问题,请参考以下文章

Android Kotlin ProGuard 规则错误?

带有 proguard 的 Kotlin AAR 库:如何只保留类和方法名?

带有 Proguard 的 Kotlin 反射失败

启用 Proguard 时未找到 kotlin.Any

Proguard 和 Kotlin 的“找不到引用的类”

Kotlin 反映 proguard SmallSortedMap