23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
안녕하세요! 23년 신입으로 입사하여 현재 에이닷의 Android 앱 개발을 하는 안드로이지입니다^^
에이닷 개발에 참여한 지도 1년이 지났는데요, 개발하면서 작성한 제 소소한 개발 일지를 공유하고자 합니다.
이번 글 주제는 바로 '인앱리뷰' 입니다!
인앱리뷰(In-App Review)란 사용자가 마켓(Play Store)에 접속하지 않아도 앱 사용 중에 리뷰를 남길 수 있도록 요청하는 기능입니다.
인앱리뷰는 사용자가 리뷰를 등록하는 과정을 '마켓으로 이동 > 앱 검색 > 앱 선택 > 리뷰 쓰기'에서 '리뷰 쓰기' 단 하나로 줄일 수 있고, 앱 사용 중에 리뷰를 받을 수 있다는 점이 장점입니다.
아래 사진은 에이닷 포토에서 사진을 생성하고 내려받을 때 나타난 실제 인앱리뷰 화면입니다.
별점을 매길 수 있는 별 모양이 나타나고, 별점을 매기면 하단에 리뷰를 남길 수 있는 TextField가 나타납니다.
서비스 이용 중에 리뷰하므로 사용자가 이용한 바로 직후에 의견을 받을 수 있습니다.
현재 에이닷 앱에선 전화와 포토 기능을 사용할 때 인앱리뷰 팝업이 노출됩니다.
특정 시점에서 인앱리뷰를 호출하도록 이벤트를 trigger하고, 이벤트가 감지되면 그때 인앱리뷰를 호출하는 함수를 실행합니다.
BUT >> 함수를 호출하면 항상 이벤트가 trigger 되도록 하지는 않았습니다.
이벤트가 trigger 될 땐 반드시 1) 허용된 경로로 내려진 앱인지, 2) 함수 호출 기간이 한 달 넘었는지 확인한 다음 trigger 되도록 했습니다.
허용된 경로
Play Store를 통해 설치된 앱에서만 띄울 수 있도록 했습니다. context의 packageManager의 함수 중 getInstallSourceInfo 함수를 사용해서 설치 경로를 가져올 수 있습니다.
Play Store에서 내려받으면 설치 경로가 com.android.vending으로 표시됩니다. 이 설치 경로랑 동일한 경우에만 나타나도록 했습니다.
그 이유는 이 설치 경로가 아닐 땐 인앱리뷰를 띄울 수 없다는 에러 로그를 남기기 때문입니다.
API level 29 이하로는 packageManager의 getInstallerPackageName 함수를 통해서 가져올 수 있어서 분기 처리했습니다.
val playStore = "com.android.vending"
val packageManager = context.packageManager
val path = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
packageManager.getInstallSourceInfo(context.packageName).installingPackageName
} else {
packageManager.getInstallerPackageName(context.packageName)
}
return path == playStore함수 호출 기간
인앱리뷰가 한 번 호출된 이후엔 일정 기간이 지나야 재호출할 수 있으며, 일정 기간에 대한 정보는 구글에서 공개하지 않고 있습니다.
공식 문서에선 짧은 기간에 2번 이상 호출하면 팝업이 안 나타날 수 있다고 기재되어 함수 재호출 기간을 정할 필요가 있다고 판단했습니다.
그래서 SharedPreference에 이벤트가 trigger 된 날의 Date 값을 저장하여 저장된 값으로부터 1개월이 지났을 경우 다시 이벤트를 trigger 하도록 했습니다.
그 이전에 함수를 호출할 땐 이벤트 trigger가 되지 않도록 구현했습니다.
// 이벤트 trigger 되었을 경우
val lastTime = System.currentTimeMillis()
saveTimeToSharedPreference(lastTime) // SharedPreference에 저장
// 이벤트 trigger 검사할 경우
val nowTime = System.currentTimeMillis()
val between = (nowTime - lastTime).milliseconds
if (between < 30.days) return false코드는 매우 간단합니다.
// build.gradle
implementation 'com.google.android.play:review-ktx:2.0.1'"com.google.android.play:core"를 implementation 하면 에러가 발생합니다.
core 내 기능들이 모두 각각의 라이브러리로 분리되었기 때문에 review-ktx를 implementation 했습니다.
// 인앱리뷰 코드
val manager = ReviewManagerFactory.create(context) ----- (A)
val request = manager.requestReviewFlow() ----- (B)
request.addOnCompleteListener { task ->
if (task.isSuccessful) {
// We got the ReviewInfo object
val reviewInfo = task.result
val flow = manager.launchReviewFlow(activity, reviewInfo) ----- (C)
flow.addOnSuccessListener { _ -> ----- (D)
log("인앱리뷰 호출하기 성공!")
}
updateDate() ----- (E)
} else {
// There was some problem, log or handle the error code.
@ReviewErrorCode val reviewErrorCode = (task.getException() as ReviewException).errorCode
log(reviewErrorCode)
}
}(A) ReviewManager ReviewManagerFactory.create(context)
ReviewManager의 instance를 생성하는 코드입니다.
ReviewManager란 review flow를 관리하는 interface를 말합니다.
(B) Task<Void> requestReviewFlow()
review flow를 시작하기 위해 필요한 ReviewInfo를 가져옵니다.
(C) Task<Void> launchReviewFlow(activity, reviewInfo)
(B)로부터 ReviewInfo를 받은 후, 여러 조건을 거쳐 UI를 나타냅니다.
만약 사용자가 이미 리뷰를 작성했다면 사용자에게 나타나지 않습니다. 즉 (C)를 호출한다고 해서 항상 나타나는 것은 아닙니다.
(D) addOnSuccessListener
인앱리뷰 호출 후 결과에 관한 Listener이며, OnSuccess 외에 OnFailure, OnComplete 도 있습니다.
위 화면에서 1) dim 처리된 배경 터치, 2) back 버튼 누르기, 3) 별점 매기기나 리뷰 작성, 4) '나중에'와 같은 버튼 클릭.
이렇게 4가지 중 하나를 사용자가 실행했을 때 에러가 발생하지 않는다면 addOnSuccessListener가 실행됩니다.
다만 앱을 강제 종료한 경우는 그 어느 Listener에도 감지되지 않습니다.
addOnSuccessListener가 실행된다고 해서 4가지 중 어떤 행위를 했는지는 알 수 없습니다.
사용자가 '나중에' 버튼을 눌렀는지, 실제로 리뷰를 등록했는지 등 특정 행위에 대한 정보는 알 수 없습니다.
flow.addOnSuccessListener { _ ->
log("인앱리뷰 호출하기 성공! 호출 뒤의 상황은 알 수 없다.")
}.addOnFailureListener { _ ->
log("인앱리뷰 호출하기 실패. ERR 발생")
}.addOnCompleteListener { _ ->
log("인앱리뷰 호출하기 성공 or 실패. 여기서도 강제종료 했는지는 알 수 없다.")
}(E) updateDate()
호출에 성공했으면 오늘의 날짜를 저장합니다. (구글에서 제공하는 함수는 아니고 직접 만든 함수입니다.)
SharedPreference에 현재 시각을 저장하고, 이벤트 trigger 조건을 검사할 때 이때 저장한 값을 참고합니다.
인앱리뷰에는 '할당량'이라는 제약이 있습니다. 각 구글 계정 소유자마다 같은 앱에서 인앱리뷰를 마주치는 기간이 정해져 있습니다.
할당량을 피해서 테스트하는 방법은 2가지가 있습니다.
첫 번째는 FakeReviewManager 입니다. ReviewManagerFactory.create 대신 사용하는데, 실제 인앱리뷰 UI가 보이지 않는다는 단점이 있습니다.
직접 보면서 개발하고 싶었기에 두 번째 방법인 Google Play Console의 내부 테스트를 이용했습니다.
내부 테스트는 인앱리뷰 UI가 보일뿐더러 할당량 제한이 없어서 원하는 만큼 테스트를 할 수 있다는 장점이 있습니다.
내부 테스트에 앱을 등록하기 위해선 Google Play Console에 개발자 계정이 있어야 합니다.
1번) Play Console에서 앱을 등록합니다.
2번) 왼쪽 메뉴에서 내부 테스트를 클릭합니다.
3번) 테스터 탭을 클릭하고 4번) '이메일 목록 만들기'를 눌러서 테스터의 이메일을 등록합니다.
5번) 링크를 복사하여 스마트폰에서 링크를 엽니다.
6번) 클릭하여 테스터 초대를 수락합니다.
다시 링크에 접속하면 사진의 두 번째 화면이 나오고 7번) 누릅니다.
그러면 8번) 화면이 나오면서 설치를 할 수 있는 페이지가 나옵니다. -> 내부 테스트 준비 완료!
개발하다 보니 할당량이 과연 어디에 저장되는 건지 궁금증이 생겼습니다.
인앱리뷰 API의 라이브러리가 com.google.android.play라서 Google Play 서비스, Google Play Store 2개 중 하나와 연관이 있을 것이란 가정을 했습니다.
그리고 리뷰를 작성하지 않은 상태에서 실험했습니다.
우선 인앱리뷰를 호출하면 호출한 날짜를 SharedPreference에 저장하기 때문에, 호출된 적 없는 상태로 만들기 위해 에이닷 앱의 데이터 삭제를 진행했습니다.
그리고 1) Google Play 서비스의 데이터와 2) Google Play Store의 데이터를 각각 삭제해서 확인했습니다.
1)을 실행했을 땐 인앱리뷰가 나타나지 않았지만, 2)를 실행했을 땐 인앱리뷰가 나타났습니다.
그래서 인앱리뷰 API 할당량 관련 데이터는 Google Play Store의 로컬에 저장되어 있음을 알 수 있었습니다.
하지만 리뷰를 작성한 상태에선 위 방법대로 해도 나타나지 않으니 참고하시길 바랍니다.
인앱리뷰가 노출되는 4가지 조건이 있습니다.
Play Store가 설치되어 있고 Android 5 이상을 실행할 수 있는 Android 기기
Play Store를 통해서 내려받은 앱
Play Store에서 내려받은 앱일 경우에만 노출되도록 설정되어 있습니다. APK로 내려받는 경우 안 뜰 수 있기 때문에 설치 경로 확인이 필요합니다.
구글 계정과 연동된 이메일
구글에서 인앱리뷰 노출 여부를 판단할 때 구글 계정 기준으로 측정하기에 테스터 등록은 Gmail인지 확인이 필요합니다.
만약 Gmail이 아니라면 해당 이메일이 구글 계정과 연동되어 있는지, 회사 계정처럼 보호 때문에 막히는 계정이 아닌지 확인해야 합니다.
해당 앱에 리뷰 등록을 안 한 사용자
등록하셨다면 내부 테스트 앱의 페이지(내부 테스트 사진 중 8번)에서 리뷰를 삭제하고, 데이터 삭제까지 진행한 뒤에 재확인하시면 됩니다.
이 조건을 모두 만족해야 인앱리뷰가 노출됩니다.
그리고 내부 테스트로 확인하면서 ACCEPT INVITE를 했는데 안 되는 경우, 테스터로 등록되는 시간이 걸리므로 잠시 대기하거나 앱을 삭제하고 재설치 후 다시 시도 해보시길 바랍니다.
그렇다면 인앱리뷰를 도입한 후 에이닷 리뷰에 어떤 변화가 있었을까요?
24년 2월 인앱리뷰 도입을 시작으로 평점은 3점 대에서 5주 후 4.2가 되었고, 리뷰 개수는 5주 차가 되었을 때 1주 차에 수집된 리뷰 개수의 4배를 넘었습니다.
인앱리뷰 API에선 사용자가 실제로 리뷰를 등록했는지 알려주진 않지만, 인앱리뷰 도입 전후를 비교했을 때 도입 후 리뷰 개수가 증가하고 별점이 오른 결과를 볼 수 있었습니다.
그리고 많은 사용자의 리뷰를 바탕으로 업데이트하여 24년 9월 24일 기준으로 에이닷은 별점 4.5가 되었습니다!
인앱리뷰 코드가 포함된 버전이 배포되었을 때, 바로 확인하고 안도의 숨과 함께 행복한 아침잠을 청했던 기억이 납니다.
그리고 인앱리뷰로 에이닷에 대한 생생한 리뷰가 서비스 개선에 도움이 되어 참으로 뿌듯했습니다!
이 행복한 기억을 양분으로 삼아 더 나은 AI 비서 에이닷이 되도록 Android 개발에 더 정진하겠습니다.
인앱리뷰를 적용하고자 하는 개발자분께 조금이나마 도움이 되는 글이 되기를 바랍니다.
부족한 글 읽어주셔서 감사합니다!
[구글 공식 문서] Google Play In-App Review API
[ProAndroidDev Medium] An Inquiry into Android’s In-App Reviews
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.