Blog Article 08 05 - nolsigan/nolsigan.github.io GitHub Wiki

안녕하세요, 이음소시어스에서 안드로이드 개발을 맡고 있는 김범준(준)입니다.

최근 안드로이드 HTTP Client 라이브러리를 Volley에서 Retrofit2로 옮기는 과정에서 겪었던 ProGuard 관련 문제와 해결과정을 공유하려 합니다.
저희가 겪은 문제는 다음과 같습니다.

  1. 새로운 feature에 쓰이는 API 모듈을 Retrofit2를 통해 구현하였습니다.
  2. QA 과정에서 아무 문제가 없어서 구글 플레이에 배포하였습니다.
  3. 구글 플레이에서 다운로드하니 새로 만든 API가 작동을 안 했습니다 ㅠㅠ

멀쩡하던 API가 배포하니 갑자기 안되다니.. (멘붕) APK 파일을 다운로드하여 테스트하지 않고 Android Studio를 통한 빌드로만 테스트한 것이 문제였습니다.
ProGuard가 APK를 난독화하는 과정에서 문제가 생겼던 것이죠!

정확히 어떤 문제였는지 설명하기에 앞서 먼저 ProGuard와 저희가 사용한 retrofit2 설정에 대해 간략하게 설명하겠습니다.

ProGuard란?

ProGuard는 APK 빌드 과정에서 사용하지 않는 코드를 제거함으로써 크기를 최소화하고, 남은 코드를 난독화를 통해 리버스 엔지니어링을 어렵게 합니다.
ProGuard의 경우에는 class, method, field의 이름을 줄여 난독화를 하게 되는데, 예를 들면 'name' 이라는 String 타입의 field를 'a'라고 치환합니다.

이 때, 난독화가 코드 작동에 영향을 줄 수 있는 부분들은 '-keep class ~'와 같은 방법으로 난독화에서 제외해줍니다.

retrofit2 + rxjava

저희가 retrofit2을 도입하면서 선택하게 된 구조는 rxjava의 Observable class와 GsonConverter를 사용합니다.

-- 코드 -- //Retrofit 설정 mApi = new Retrofit.Builder() .baseUrl(SERVER_URL) .client(new OkHttpClient()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //Rxandroid .addConverterFactory(GsonConverterFactory.create()) //Json Parser 추가 .build().create(Im8Service.Im8Api.class); //인터페이스 연결

  • 따로 - @POST("get_nation_ids_and_names") Observable<Im8Response.Nations> getNationIdsAndNames(@Query("access_token") String accessToken);

  • 모델 따로 - -- 코드 --

RxJava의 Observable를 통해 어떤 class로 response를 받을 것인지 지정해주면, GsonConverter를 통해 response를 JSON으로 serialize하여 지정한 class의 각 멤버 변수에 대입해줍니다.
API 콜을 부르면 callback에 지정한 class의 객체를 돌려주니 그냥 바로 class method를 사용할 수 있습니다. (짱 편함..)

retrofit2 + rxjava의 자세한 설정이 궁금하신 분은 https://medium.com/@ahmedrizwan/rxandroid-and-retrofit-2-0-66dc52725fff#.rn3g84oxv를 참고해주세요~

문제는 Model의 난독화에 있었다..

위에서 언급한 것처럼 response가 들어오게 되면 GsonConverter가 JSON으로 파싱해주고 model class의 멤버 변수에 대입해주는데, 이 때 ProGuard가 이 class의 멤버 변수를 난독화하면..! 대응 되는 이름의 멤버 변수가 없으니 오류가 생기는 것이죠.

실제로 난독화 된 class를 보면 다음과 같습니다.

-- 사진 --

proguard configuration

default

retrofit 홈페이지는 proguard를 사용할 시 어떤 설정을 적용해야 하는지 친절하게 써 놓았습니다.

  • 사진 -

이것만 보고 설정이 끝났다고 생각해서 문제가 생긴 것이죠 ㅠㅠ

keep model

-- 코드 --

다음과 같이 사용하는 model class를 난독화에서 제외해주시면 됩니다. 결과는 다음과 같습니다.

-- 사진 --

Inner class를 가지고 있는 model 일 때

Inner class가 있다면 난독화에서 제외를 해주더라도 다음과 같이 안에 있는 클래스는 난독화가 됨을 확인할 수 있습니다.

-- 코드 -- 위와 같이 코드를 추가하여 Inner class도 난독화에서 제외되도록 해줍니다.

-- 사진 --

짠!

후기

저에겐 안드로이드 배포가 이번이 처음이었는데요, 예상치 못한 오류가 터져서 고생을 했지만 그래도 해결하고 나니 많이 배운 것 같아 뿌듯하네요 ㅎ