Retrofit 및 카카오 로그인 Proguard 프로가드 난독화 관련 오류 질문 있습니다

문의 시, 사용하시는 SDK 버전 정보와 디벨로퍼스 앱ID를 알려주세요.

Faq 목록 - 10. Android ( Faq 목록 입니다 ) 먼저 확인해주세요.


SDK 버전: 26 ~ 34

buildTypes {
        getByName("debug") {
            isShrinkResources = false
            isMinifyEnabled = false
            isDebuggable = true
            signingConfig = signingConfigs.getByName("debug")
        }
        getByName("release") {
            isShrinkResources = false
            isMinifyEnabled = false
            isDebuggable = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
            proguardFile("proguard-kakao.pro")
            proguardFile("proguard-retrofit2.pro")
            signingConfig = signingConfigs.getByName("release")
        }
    }

위와 같이 buildType을 설정하고 나서 release로 빌드하고 앱을 run해서 로그인을 시도하면 네트워크상으로는 로그인에 성공하지만 다음 화면으로 넘어가지 못하고 다음과 같은 오류가 발생합니다.

위에 보이는 at a3.c.s와 at i8.b.onResponse를 보고 나서 build → outputs → mapping → release → mapping.txt를 열어서 관련 부분을 찾아보니 다음과 같았습니다.

com.google.android.datatransport.runtime.backends.BackendResponse$Status$EnumUnboxingLocalUtility -> a3.c

com.kakao.sdk.auth.model.OAuthToken refreshToken$auth_release(com.kakao.sdk.auth.model.OAuthToken):0:0 -> a
com.kakao.sdk.auth.AuthApiManager$agt$1$1 -> i8.b:




프로가드(proguard.pro) 파일에 카카오 디벨로퍼스(시작하기 | Kakao Developers 시작하기)에서 제시하는 코드를 넣었는데도 이런 오류가 발생하네요.

retrofit 관련 proguard 코드는 다음과 같이 작성했습니다.

# 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>

# 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 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>

# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response


-keep class retrofit2.** { *; }
-dontwarn retrofit2.**

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

##---------------End: proguard configuration for Gson  ----------

-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
-dontwarn org.slf4j.**

카카오 관련 proguard는 다음과 같습니다. (2024-01-19 수정)

-keep class com.kakao.sdk.**.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
# https://github.com/square/okhttp/pull/6792
-dontwarn org.bouncycastle.jsse.*
-dontwarn org.conscrypt.*
-dontwarn org.openjsse.**

-keep interface com.kakao.sdk.**.*Api




로그인 관련 data class에는 모두 @Keep을 붙였는데도 오류가 발생하는데
뭐가 문제인지 도저히 모르겠어서 질문 드립니다.

안녕하세요.

에러는 모델객체를 난독화 예외 조치 하지 않아 발생한 것으로 보이고
기재해주신 프로가드(ProGuard) 규칙 파일에 가이드에서 안내하는 예외 구문이 안보이는데요? 추가해보시겠어요?

-keep class com.kakao.sdk.**.model.* { <fields>; }

안녕하세요.

위에 작성한 글에서 누락되었는데, proguard-kakao.pro를 별도로 만들어서 다음과 같이 코드를 작성했습니다.
근데도 안되네요…

-keep class com.kakao.sdk.**.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
# https://github.com/square/okhttp/pull/6792
-dontwarn org.bouncycastle.jsse.*
-dontwarn org.conscrypt.*
-dontwarn org.openjsse.**

-keep interface com.kakao.sdk.**.*Api
buildTypes {
        getByName("debug") {
            isShrinkResources = false
            isMinifyEnabled = false
            isDebuggable = true
            signingConfig = signingConfigs.getByName("debug")
        }
        getByName("release") {
            isShrinkResources = false
            isMinifyEnabled = false
            isDebuggable = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
            proguardFile("proguard-kakao.pro")
            proguardFile("proguard-google.pro")
            proguardFile("proguard-retrofit2.pro")
            signingConfig = signingConfigs.getByName("release")
        }
    }

아래 구문은 제거 해주시고, release 빌드하고 앱 종료 후, 재실행했을때 어떤 에러 발생하는지 확인해주시겠어요?

-keep interface com.kakao.sdk.**.*Api

해당 구문을 제거하고 실행했을 때 다음과 같이 오류가 발생합니다.
네트워크상으로는 로그인이 성공했지만 다음 화면으로 이동하지 못하고 비정상 종료가 발생하네요.

    FATAL EXCEPTION: main
    Process: com.onandoff.onandoff_android, PID: 9375
    java.lang.ClassCastException
    at a3.c.s(Unknown Source:5)
    at i8.c.onResponse(Unknown Source:481)
    at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0(Unknown Source:25)
    at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.b(Unknown Source:0)
    at retrofit2.a.run(Unknown Source:14)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
}

안녕하세요.

재현을 위해 아래 정보 확인 부탁드립니다.

  • AGP Version
  • Gradle Version
  • kotlin Version
  • JDK Version
  • AGP Version : 8.1.1
  • Gradle Version : 8.0
  • kotlin Version : 1.9.20, 1.9.22 (둘 다 해봤습니다)
  • JDK Version : 17

안녕하세요

말씀해주신 환경에서 테스트를 해보았는데 이슈가 재현되지 않아서 정확하게 원인파악이 되지 않고 있네요ㅠㅠ

조금 번거로우시겠지만 빈 프로젝트에 이슈를 재현해서 해당 프로젝트를 통째로 첨부해주실 수 있을까요?

안녕하세요.

새로운 프로젝트를 만들어서 동일한 환경(AGP Version, Gradle Version, kotlin Version, JDK Version, proguard 등)을 설정하고 카카오 로그인을 시도했는데 정상적으로 실행되었습니다. (???)

기존의 프로젝트에서는 왜 오류가 발생하는지 원인을 파악할 수는 없습니다만, 본 페이지에 업로드하기는 어려워서 메일을 알려주시면 기존의 프로젝트를 보내드리고 싶습니다.

tony.mb@kakaocorp.com 으로 프로젝트를 보내주시면 원인 파악해보고 답변 남기도록 하겠습니다!

어제 메일로 보냈습니다!

확인이 조금 늦었네요…

보내주신 메일 확인해서 테스트해봤는데 메일에서 설명해주신 동선은 서버 이슈로 제대로 진행하지 못해 이슈를 재현하지 못했습니다. 이 부분은 이슈 재현 방법을 다시 설명해주시면 확인해보도록 하겠습니다.

이슈 재현과 별개로 코드도 대략적으로 살펴보았습니다. 난독화 mapping.txt 파일을 확인해보고 카카오SDK에서 크래시가 발생하는 것으로 추측하신 것도 확인했지만, 메일에서 설명해주신 이슈 재현 동선에서는 카카오SDK를 사용하지 않고 있는 것으로 보여서 이 부분이 잘 이해가 되지 않네요

카카오SDK 의존성을 제거한 상태에서도 이슈가 발생하는지 확인해보시는 것도 좋을 것 같습니다.