grep

Android

안드로이드 런처와 위젯 톺아보기 (4) - 페이코 앱 위젯/숏컷 이슈 일대기 (완)

NHN

2022년 1월 10일

원문에서 보기 ↗

소개

안녕하세요. PAYCO 앱기술개발팀 유상현입니다. 주로 런처와 위젯, 숏컷 3가지에 관한 주제로 공유를 시작하여 어느덧 마지막 공유 글이 되었습니다.

이번 편에서는 페이코 안드로이드 앱에서 실제 발생했던 위젯과 숏컷 관련 이슈를 중심으로 공유를 진행할 예정입니다.

혹시나 런처 / 위젯 / 숏컷 3가지의 명칭 구분에서 혼동이 오신다면 전편 공유 글의 설명을 참고 부탁드립니다.

본격적인 이슈 공유에 앞서, 3편에서 위젯과 숏컷 관련 이슈가 발생하는 케이스는 아래와 같았습니다.

런처가 업데이트될 때, 위젯은 앱에서 대응할 수 있다.

--> 앱에서 대응을 잘못할 경우 이슈가 발생합니다.

런처가 업데이트될 때, 숏컷은 앱에서 대응할 방법이 없다. 오로지 런처의 판단으로 숏컷 업데이트가 진행된다.

--> 런처의 판단이 의도한 방향이 아닐 경우 앱의 의도와 상관없이 이슈가 발생합니다.

이번 공유에서는 페이코 앱에서 위의 2가지 원인으로 인해 어떤 이슈가 발생했는지 각각 소개하고, 대응했던 내용에 대해 작성해보겠습니다.

1. 위젯이 초기화되었어요

런처가 업데이트될 때 위젯 대응을 잘못한 경우

때는 바야흐로 작년, 안드로이드의 페이코 결제 위젯에 이슈가 발생했습니다.

1.png

당시 페이코 결제 위젯은 설치 시 런처에서 위와 같은 형태로 동작을 하게 되는데요, 각 영역을 클릭 시 결제 / 카드 변경 / 앱 실행 이 되는 이벤트를 가지고 있습니다.

2.png

그런데 어느 날 위와 같이 결제 영역의 카드가 사라지고, 카드 변경 버튼이나 앱 실행 버튼도 동작하지 않는다는 이슈가 접수되었습니다.

해당 현상이 발생하는 케이스는 아래와 같았습니다.

위젯 설치 후,

휴대폰 재부팅 시 앱 업데이트 시 OS 업데이트 시

기타 등등... 런처가 업데이트되는 경우 이슈가 발생하였습니다.

그러면 런처가 업데이트될 때 왜 위젯에 이슈가 생긴 걸까요?

* 매번 새로 그려줘야 하는 위젯

3.png

런처가 업데이트되는 경우, (또는 위젯이 자체적으로 업데이트되는 경우) AppWidgetProvider를 상속받은 클래스에서 위의 onUpdate 메서드가 호출되는데요. 이때 반드시 인자로 넘어온 모든 appWidgetId에 대해 위젯 뷰를 다시 그려줘야 합니다. 만약 다시 그리지 않는 경우 아무 클릭 이벤트가 없는 기본 형태로 초기화되게 됩니다.

4.png

런처가 업데이트되거나, 기타 위젯의 업데이트가 필요할 경우 안드로이드 시스템 또는 런처는 android.appwidget.action.APPWIDGET_UPDATE라는 action으로 broadcast를 전송합니다.

해당 broadcast를 받은 경우 안드로이드 시스템은 앱에서 대응하기 쉽도록, onUpdate 콜백을 제공하며 이 부분이 위에 작성한 코드 부분입니다.

5.png

해당 콜백에서 위 예시와 같이 appWidgetManager.updateAppWidget를 호출하지 않는다면, 위젯이 초기화되게 됩니다. 한마디로, onUpdate 콜백에서 반드시 새로운 뷰를 생성하고 updateAppWidget을 호출해야 위젯이 초기화되지 않습니다.

얼핏 보면 굉장히 단순한 사실인 것 같지만, 뷰를 그리기 위해 여러 개의 분기 처리가 들어가는 경우, 또는 뷰를 그리는 도중 에러가 발생하는 경우를 섬세히 챙기지 않는다면 어느 순간 초기화가 될 수 있습니다.

페이코 앱에서도 이러한 케이스에 해당하여 이슈가 발생하였는데요. 위젯 뷰를 그리기 위해 네트워크 작업이 들어갈 경우 이슈가 있었습니다.

* 네트워크 작업 이슈

6.png

페이코 결제 위젯의 경우 위의 실물 카드 이미지를 네트워크 작업을 통해 받고 있었는데요, 특정 단말기에서 해당 네트워크 작업을 진행할 때 이슈가 발생하고 있었습니다. 주요 로그는 아래와 같습니다.

7.png

주로 Android 10 환경에서, 앱 업데이트 또는 기기 리부팅 직후에 위젯에서 네트워크 요청을 할 경우, 실제로 네트워크는 연결되어있지만 java.net.UnknownHostException 이 발생하는 이슈가 있었습니다.

해당 이슈는 페이코에서만이 아니라 기기에 설치된 많은 앱들에서 동일하게 로그가 찍히고 있는 것을 확인하였는데요. 해당 에러는 네트워크가 연결되지 않았을 때 나타나는 로그로, 실제 네트워크가 연결되어 있음에도 실물 카드 이미지를 받아오지 못하고 있었습니다.

이때 이미지 로딩 중 에러가 발생한 케이스에 대해 updateAppWidget 호출 코드가 누락이 되어있었고, 이런 경우 위젯이 초기화되었습니다.

에러가 발생한 케이스에 대해 updateAppWidget 호출 코드를 추가하면 이슈는 일단락되는 부분이지만, 근본적으로 java.net.UnknownHostException 이 왜 발생하였는지에 대해서는 Android 10 버그로 추정이 될 뿐 명확한 원인을 찾을 수 없었습니다.

* 위젯 초기화 이슈 결론 및 요약

8.png

  1. 위젯은 개발자가 업데이트를 설정하지 않더라도 런처가 업데이트되는 여러 가지 상황에서 자동으로 업데이트가 이루어지고 업데이트가 될 때마다 반드시 모든 케이스에 대해 위젯 뷰를 updateAppWidget 메서드를 통해 새로 그려주어야 합니다.

  2. 위 과정에서 updateAppWidget 메서드 호출이 누락되는 케이스가 생기면 위젯이 초기화됩니다.

  3. OS 버전에 따라 예상치 못한 에러가 발생할 수 있고, 발생하였을 때 사용자의 불편을 최소화하도록 뷰에 새로고침 버튼을 만들어 사용자가 추후 쉽게 에러 상황에서 벗어날 수 있도록 대응하는 것이 필요합니다.

2. 숏컷이 사라졌어요

위젯과 달리, 숏컷은 한 번 생성한 이후에는 앱에서 관여할 수 있는 부분이 없습니다. 따라서 런처가 업데이트될 때, 숏컷은 오로지 런처의 판단으로 업데이트가 진행되는데요, 이 런처의 판단에 따라 괴상한 일이 일어나곤 합니다.

9.png

어느 날, 일부 기기에서 설치해둔 페이코 삼성 페이 숏컷이 기기를 재부팅하거나 앱을 업데이트하는 경우에 런처에서 저절로 사라져 버렸다는 이슈가 들어왔는데요.

이슈를 확인한 결과 뜬금없는 곳에서 문제를 확인했습니다.

* Activity 이름이 숏컷에 영향을?

결론부터 말씀드리면 해당 이슈의 원인은 아이러니하게도 특정 Activity의 이름 변경이었습니다.

여기서 특정 Activity는 흔히 SplashActivity, LauncherActivity라고 부르는 Activity로, 구체적으로는 아래와 같습니다.

10.png

AndroidManifest.xml 에 위의 action과 category 가 지정된 Acitvity로, 해당 Activity는 일반적으로 앱 실행 시 최초로 실행되는 Activity입니다. 또한, 해당 action과 category는 2편에서 작성하였던 런처에서 설치된 앱을 노출하기 위해 사용하는 정보이기도 합니다.

* LauncherActivity의 이름이 왜 숏컷에 영향을?

일반적으로 안드로이드에서 사용자가 기기에 설치된 앱을 제거할 때, 앱을 실행하는 아이콘뿐만이 아니라 해당 앱에서 설치해둔 위젯 및 숏컷 역시 모두 삭제되는데요.

해당 스펙을 위해 일부 메이저 런처에서는 제거할 앱과, 제거할 앱에서 설치된 위젯 및 숏컷을 판단하기 위해 아래의 값을 비교하고 있는 것으로 보입니다.

  1. 제거할 앱의 패키지명 + 현재 LauncherActivity 명
  2. 위젯 및 숏컷 설치 시점의 패키지명 + LauncherActivity 명

여기서 숏컷의 경우, 설치 시점의 LauncherActivity 명은 이후 앱의 LauncherActivity 명이 변경되더라도 업데이트가 되지 않습니다.

즉, 숏컷이 어떤 앱에서 설치한 것인지 알 수 없어지는 케이스가 발생하며 이때 이슈가 발생하게 됩니다.

* 숏컷 이슈 발생 플로우

위의 Activity 명 변경이 숏컷에 어떤 영향을 미치는지 상세한 설명을 위해, 테스트 앱을 대동했습니다. 우선 간단히 이슈가 발생하는 플로우를 설명하면 아래와 같습니다.

11.png

위 플로우와 같이, 숏컷을 설치하여 사용하고 있는 사용자가 앱을 업데이트했을 때

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

위 옵션이 지정된 Activity의 이름이 변경되었다면, 이후 기기 재부팅이나 OS 업데이트 등으로 인해 런처가 업데이트되었을 때 숏컷이 사라지는 기기들이 있습니다.

1편에서 작성한 바와 같이 런처 역시 서드파티 앱이기 때문에 제조사, OS 버전, 심지어는 각 모델마다 런처의 스펙이 달라 생기는 이슈라고 볼 수 있습니다. 이슈가 발생하는 런처가 서드파티 앱이다 보니 코드를 볼 수 없어 추측만 가능한 부분이지만,

런처가 기기에 설치된 앱을 판단하는 기준에 LauncherActivity 가 들어가 있고, 해당 LauncherActivity 명이 변경된 경우 기존 앱이 제거되었다고 판단하여 숏컷 역시 제거를 시키는 것으로 보입니다.

때문에 LauncherActivity에 해당하는 위의 intent-filter 가 지정된 Activity의 이름은 웬만한 경우라면 변경하지 않는 것이 좋습니다.

LauncherActivity 명이 변경되는 케이스는

  1. 개발자가 직접 코드상에서 파일명을 변경하는 케이스도 있지만,
  2. 각종 난독화 라이브러리를 통해 빌드 시점에 클래스 이름이 변경될 수도 있습니다.

페이코의 경우도 2번에 해당하여 이슈가 발생하였고 해당 난독화 케이스의 경우 배포 전에 인지하기가 쉽지 않은 부분이라 LauncherActivity에 해당하는 Activity 가 난독화 제외 처리가 되어있는지 체크가 필요합니다.

* 이미 LauncherActivity 명이 변경되어 배포가 나간 경우라면?

해당 이슈의 가장 크리티컬 한 점은 사용자가 단 한 번이라도 LauncherActivity 명이 변경되는 시점에 앱을 업데이트한 경우, 앱을 지웠다가 재설치해도 기기 재부팅 시 계속 숏컷이 삭제되는 경우가 있다는 점입니다.

12.png

특정 기기의 런처에서는 숏컷을 설치하는 위 화면의 정보를 캐싱하는 것으로 추정되는데요. 앱을 재설치해도 변경 전의 LauncherActivity를 기준으로 숏컷이 생성되고, 이후 런처가 업데이트될 때 이미 변경된 LauncherActivity 때문에 기존 앱이 제거되었다고 판단하여 숏컷이 제거됩니다.

결론적으로 LauncherActivity 명 1회 변경 이후 더이상 변경을 하지 않더라도 일부 사용자는 영원히 재부팅 시마다 설치한 숏컷이 사라지는 참사가 일어날 수 있습니다.

페이코에서는 난독화로 인해 무려 연속으로 3번이나 LauncherActivity 명이 변경되며 배포가 나가버렸고, 그 후 더이상 LauncherActivity 가 난독화되지 않도록 조치를 취했으나 숏컷은 계속해서 사라져 갔습니다.

* 구원자 activity-alias

절망적인 상황이었지만 그래도 해결책은 있었습니다.

숏컷이 사라지는 원인은 결국 변경 전의 LauncherActivity 클래스가 AndroidManifest.xml 에 존재하지 않아서이기 때문에, 변경 전의 LauncherActivity 가 여전히 존재하는 척해보면 어떨까? 라는 생각을 하게 되었습니다.

위 생각을 실천에 옮길 수 있는 방법으로 activity-alias라는 옵션이 있었습니다.

activity-alias 란 말 그대로 Activity에 별칭을 부여할 수 있는 옵션으로, (참고 : https://developer.android.com/guide/topics/manifest/activity-alias-element?hl=ko)

13.png

위 그림과 같이 A라는 Activity가 있을 때, B라는 이름으로도 A Activity를 나타낼 수 있습니다.

이를 바탕으로 아래와 같은 계획을 짜게 됩니다.

14.png

비록 A, B, C는 과거 버전에 존재했던, 현재 버전에는 없는 Activity 명이지만 activity-alias 옵션을 통해 해당 Activity 명들 역시 현재 LauncherActivity를 가리키도록 작업을 진행했습니다.

실제 페이코의 코드를 보면 아래와 같습니다.

15.png

난독화로 인해 PaycoLauncherActivity의 이름이 버전마다 각각 Bl, po, Ul로 변경되었던 이력을 확인하였고, 해당 이름들이 모두 PaycoLauncherActivity를 가리키도록 activity-alias를 설정하였습니다.

해당 옵션을 추가한 결과, 놀랍게도 숏컷이 더이상 사라지지 않았습니다.

16.png

(그저 빛... activity-alias..)

* 숏컷 사라짐 이슈 결론 및 요약

  1. LauncherActivity 명을 변경할 경우 일부 사용자는 숏컷이 사라질 수 있습니다.
  2. 이미 LauncherActivity 명을 변경한 뒤 배포가 나갔다면, activity-alias 옵션을 활용하여 런처를 속여 숏컷이 사라지지 않게 막을 수 있습니다.

어찌 보면 전혀 상관이 없어 보이는 LauncherActivity 명과 숏컷이 사실 긴밀하게 연결되어있다는 사실을 깨달은 이슈였습니다.

마무리

처음 써보는 공유 글이라 여러 가지 부족한 점이 많았지만, 주변에 도움이 되었다고 해주시는 분들이 계셔서 보람찬 공유가 되었던 것 같습니다.

이번 편도 누군가에게 조금이나마 도움이 되었으면 하는 바람을 마지막으로, 또 언제가 될지는 모르겠지만 새로운 주제가 생기면 다시 공유 글을 작성해보도록 하겠습니다 :)

긴 공유 글 읽어주셔서 감사드리며 이만 인사드리겠습니다!

17.png

(이미지 출처)