Nexters 21기의 첫 프로젝트인 "클라이머를 위한 출석 시스템 홀디" 를 배포하면서 생긴 Issue를 해결하기 위한 과정을 담았습니다.
Debug에서 정상적으로 작동하던 홀디 앱을, 출시를 위해 Release Variants로 설정하여도 잘 작동되는지 확인해 보고자 하였습니다.
그런데 앱 로그인, 온보딩이 끝나고 홈 화면으로 들어가는 시점에서 갑자기 앱이 종료되는 현상이 발생하였습니다. 에러는 다음과 같았습니다.
2022-08-30 15:13:33.779 28548-28548/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: team.nexters.semonemo, PID: 28548
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter <this>
at team.nexters.data.moim.mapper.MoimMapperKt.toDomain(Unknown Source:2)
...
먼저, 로그에 Error가 찍혀있으니 주어진 에러를 해결하는 것을 초점에 두었습니다.
Data단에서 받은 Response
를 Domain Model
로 변환하는Mapper
에서 위와 같은 에러가 발생하였습니다. 그렇기 때문에 에러의 이유를 다음 2 가지 중 하나일 거라고 생각했습니다.
Nullable
한 값을 보내기 때문에 클라이언트 측에서도 모델의 프로퍼티를 Nullable
로 지정해야 한다. 위 두가지 에러를 해결해 보았으나, 근본적으로 해결되지는 않았습니다.
결국 다시 처음으로 돌아왔습니다.
이번에는 Debug
에서 발생하는 에러가 Release
에서만 발생한다 에 초점을 두었고 buildTypes
에서 코드를 최적화 하는 코드를 살펴보았습니다.
각각의 역할은, 다음과 같습니다
debuggable
: 디버깅 여부minifyEnabled
: 사용하지 않는 코드 제거 및 코드 난독화shrinkResources
: 사용하지 않는 리소스 제거StackOverFlow에서 비슷한 맥락의 오류를 발견했고, minifyEnabled
, shrinkResources
를 적용하는 부분에서 에러가 발생했을 가능성을 염두하여 최적화 옵션 적용을 제거했습니다.
최적화 옵션을 적용하지 않음으로서 당장은 해결할 수 있었습니다.
minifyEnabled
은 난독화 여부를 결정하는데, 난독화란 클래스 명이나 함수 명들을 a,b 등의 문자로 치환시켜 기존 코드의 보안성을 강화하는 것을 말합니다.
그러나, 단순히 최적화 옵션 적용이 안된다는 이유만으로 최적화 옵션을 버릴 수는 없었습니다.
MinifyEnabled
를 통해 클래스 파일이 난독화가 되면, 클래스나 파일 명이 a,b,c 등이 되어 Reflection
을 사용할 수가 없었습니다.
문제가 되는 코드에서 딱히 Reflection
을 사용하지 않았는데, 알고보니 Retrofit 에서 Generic Parameter에 대해 Reflection을 사용하고 있다는 것을 알게 되었습니다.
Reflection을 사용하는 클래스 등, 난독화가 되면 안되는 것들은 Proguard에 정의함으로써 방지할 수 있게 됩니다.
따라서 아래와 같이 Proguard Rule을 설정함으로써, MinifyEnabled를 적용했을 때 문제 없이 작동될 수 있었습니다.
# 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
...
Retrofit, Glide 등 외부 라이브러리는 공식 문서에 가면 Proguard Rule이 기재되어 있습니다.
해결되어서 다행입니당 :)