debug 에선 문제 없던 프로젝트가, 프로가드를 적용한 release build 를 진행할 경우 문제가 발생하는 경우가 많은데, 그럴 때 활용 해볼 수 있는 R8 retrace 의 사용 방법을 알아보도록 하겠다.
우선 프로가드에 의해 문제가 생긴 경우, 다음과 같이 에러 문구를 확인하여도 그 의미를 파악하기 쉽지 않은 경우가 많다.
FATAL EXCEPTION: main
Process: com.unifest.android, PID: 23793
qb.i: Function 'onAction' (JVM signature: onAction(Lcom/unifest/android/feature/intro/viewmodel/IntroUiAction;)V) not resolved in class ra.r: no members found
at r.q0.b(Unknown Source:555)
at nc.v1.b(Unknown Source:18)
at nc.j0.r(Unknown Source:7)
at nc.j0.toString(Unknown Source:2)
at ec.h.toString(Unknown Source:12)
at java.lang.String.valueOf(String.java:4092)
...
이럴 때 이제 사용 해볼 수 있는게 R8 retrace 인데, 암호화된 stack trace 를 복호화하여 에러의 원인을(original stack trace) 알려주는 도구이다.
이런식으로 사용법을 제시해주는데 솔직히 이것만 보고는 어떻게 채워넣으라는 것인지 이해를 하지 못했다. 부연 설명이 필요할 것 같아서(글을 작성하는 이유) 첨언 하자면,
/Users/{username}/StudioProjects/{projectname}/app/build/outputs/mapping/release/mapping.txt
에러로그를 전체 복사 한 뒤에, 이를 obfuscated-stacktrace.txt 라는 파일에 저장해서 프로젝트 root 위치에 넣어주고 이를 터미널 내에 커멘드에 포함시켜 주었다
retrace /Users/{username}/StudioProjects/{projectname}/app/build/outputs/mapping/release/mapping.txt obfuscated-stacktrace.txt
window 일 경우 메모장을 켜서 간단하게 텍스트 파일을 만들어서 저장할 수 있지만, mac 환경에선 아래 블로그의 방법을 활용하면 텍스트 파일을 만들 수 있다.
https://m.blog.naver.com/kim870103/221876294140
아직도 어려운 맥북
옵션 같은 경우엔 공식문서에서 처럼 위의 선택지 중 필요한 하나를 선택하거나, 생략해도 무방하다.
암호화되어 보이지 않던 에러가 다음과 같이 이해할 수 있는 형태의 에러 로그로 변한 것을 확인할 수 있었다.
compose runtime internal 관련 문제라는 것을 확인할 수 있었다. 본게임 시작
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:35)
at androidx.compose.ui.platform.ComposeView.Content(Unknown Source:428)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(Unknown Source:252) at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(Unknown Source:251) at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1$4$1.invoke$bridge(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(Unknown Source:228)
at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(Unknown Source:186)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(Unknown Source:119) at androidx.compose.material.ButtonKt$Button$3.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(Unknown Source:118) at androidx.compose.foundation.lazy.grid.LazyGridDslKt$rememberColumnWidthSums$1$1.invoke$bridge(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(Unknown Source:228)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(Unknown Source:110)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Unknown Source:139) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke(Unknown Source:138) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke$bridge(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(Unknown Source:248)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Unknown Source:138) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Unknown Source:123) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$2.invoke$bridge(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(Unknown Source:35)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(Unknown Source:90)
at androidx.compose.runtime.ComposerImpl.doCompose(Unknown Source:3302)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Unknown Source:3235)
at androidx.compose.runtime.CompositionImpl.composeContent(Unknown Source:725)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Unknown Source:1071)
at androidx.compose.runtime.CompositionImpl.composeInitial(Unknown Source:633)
at androidx.compose.runtime.CompositionImpl.setContent(Unknown Source:619)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Unknown Source:123) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Unknown Source:114) at androidx.compose.foundation.BorderModifierNode$drawGenericBorder$1.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(Unknown Source:1289)
at androidx.compose.ui.platform.WrappedComposition.setContent(Unknown Source:114)
at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Unknown Source:164)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(Unknown Source:320)
at androidx.lifecycle.LifecycleRegistry.addObserver(Unknown Source:198)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Unknown Source:121) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Unknown Source:114) at androidx.compose.foundation.BorderModifierNode$drawGenericBorder$1.invoke$bridge(Unknown Source:0)
at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(Unknown Source:1364)
at android.view.View.dispatchAttachedToWindow(View.java:23215)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3698)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3705)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3705)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3705)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3705)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3883)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3275)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:11257)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1650)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1659)
at android.view.Choreographer.doCallbacks(Choreographer.java:1129)
at android.view.Choreographer.doFrame(Choreographer.java:1055)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1622)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8913)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
프로가드 때문에 고생하시는 분들 화이팅 입니다..!