요약
- 리뷰 API를 호출하더라도, 할당량에 따라 호출되지 않을 수 있음 (Android 1달에 2번, IOS 1년에 3번)
- 사용자가 앱을 충분히 경험한 후 & 경험이 단절되지 않는 위치에 적절히 넣어야 함
- 리뷰를 무조건 달게 하려면 or 문구를 추가하거나 상황에 따라 직접 처리하려면 그냥 수동으로 앱스토어로 이동시켜야 함(=딥링크)
Android
요청 시기
- 사용자가 유용한 의견을 제공할 수 있을 정도로 충분히 앱 또는 게임을 사용한 이후
- 버튼 등으로 유도하는 것은 안됨 (뜨지 않는 경우 앱이 멈추지 않게)
조건
- 사용자는 PlayStore가 설치되어 있고 & API 21 이상이어야 함
- 리뷰 대화상자를 표시할 수 있는 빈도에 관한 시간제한 할당량 有 → 1개월에 최대 2번
-
- 이를 넘어가면 대화상자가 표시되지 않으며, 이는 Google Play에서 정함
- 따라서 버튼 등으로 유도하는 것은 X (뜨지 않는 경우, 단절된 경험)
- 요청 전에 어떤 질문도 해서는 안됨 (ex. ‘앱이 마음에 드십니까?’, '이 앱을 별 5개로 평가하시겠습니까?')
-
- 기존 디자인을 수정하거나, 오버레이를 추가하거나 등 안됨
IOS
조건
- 1년에 최대 3번까지 평가 요청 가능, 같은 버전에서는 2번 이상 뜨지 않음
- 유저 행동을 interrupt 하지 않아야 함 (ex. 앱 처음 시작, 유저 액션의 결과 등)
- 시스템 제공 프롬프트 사용
요청 시기
- 사람들이 앱이나 게임에 대한 참여를 보여준 후에만 요청
- 앱이나 게임에서 등급 요청이 덜 귀찮을 수 있는 자연스러운 중단 또는 중지 지점 선택
- 사람들이 귀하의 경험에 대한 추가 참여를 보여준 후에 다시 메시지를 표시 (최소 1-2주의 간격)
적용 방법 - Android
1. build.gradle에 Google Play Core 라이브러리 추가
dependencies {
// This dependency is downloaded from the Google’s Maven repository.
// So, make sure you also include that repository in your project's build.gradle file.
implementation 'com.google.android.play:review:2.0.1'
}
2. ReviewManager 객체 생성 후, ReviewInfo 객체 요청
ReviewManager manager = ReviewManagerFactory.create(this);
Task<ReviewInfo> request = manager.requestReviewFlow();
request.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
// We can get the ReviewInfo object
ReviewInfo reviewInfo = task.getResult();
} else {
// There was some problem, log or handle the error code.
@ReviewErrorCode int reviewErrorCode = ((ReviewException) task.getException()).getErrorCode();
}
});
3. 인앱 리뷰 실행
*SharedPreference 등으로 마지막 요청한 날짜 등을 확인한 후에 요청
Task<Void> flow = manager.launchReviewFlow(activity, reviewInfo);
flow.addOnCompleteListener(task -> {
// The flow has finished. The API does not indicate whether the user
// reviewed or not, or even whether the review dialog was shown. Thus, no
// matter the result, we continue our app flow.
});
+) 테스트
- PlayStore에 프로덕션 앱이 게시되어 있거나
- 내부 테스트를 통해 테스트하거나 (할당량 한도가 적용되지 않음)
- FakeReviewManager를 사용
- requestInAppReview()
-
- 릴리즈 버전에서만 작동
적용 방법 - IOS
- 앱 버전 비교하여 띄울지 결정 → 리뷰를 안 남겼는데, 버전이 다르면 띄워야 함 → count 비교
- Prompt를 띄우기 전에 delay를 주어 사용자가 하던 일을 방해하지 않도록 처리 必
// If the app doesn't store the count, this returns 0.
var count = UserDefaults.standard.integer(forKey: UserDefaultsKeys.processCompletedCountKey)
count += 1
UserDefaults.standard.set(count, forKey: UserDefaultsKeys.processCompletedCountKey)
print("Process completed \(count) time(s).")
// Keep track of the most recent app version that prompts the user for a review.
let lastVersionPromptedForReview = UserDefaults.standard.string(forKey: UserDefaultsKeys.lastVersionPromptedForReviewKey)
// Get the current bundle version for the app.
let infoDictionaryKey = kCFBundleVersionKey as String
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: infoDictionaryKey) as? String
else { fatalError("Expected to find a bundle version in the info dictionary.") }
// Verify the user completes the process several times and doesn’t receive a prompt for this app version. (해당 버전에서는 최대 4번까지 review prompt 요청 가능)
if count >= 4 && currentVersion != lastVersionPromptedForReview {
Task { @MainActor [weak self] in
// Delay for two seconds to avoid interrupting the person using the app.
// Use the equation n * 10^9 to convert seconds to nanoseconds.
// 화면 interrupt 방지하기 위해 2초 정도 딜레이
try? await Task.sleep(nanoseconds: UInt64(2e9))
if let windowScene = self?.view.window?.windowScene,
self?.navigationController?.topViewController is ProcessCompletedViewController {
SKStoreReviewController.requestReview(in: windowScene)
UserDefaults.standard.set(currentVersion, forKey: UserDefaultsKeys.lastVersionPromptedForReviewKey)
}
}
}
+) 테스트
- develoment mode에서는 항상 뜸
- TestFlight에 배포하면 실제 동작하는 대로 제한 O
적용 방법 - 수동으로 이동
- 버튼을 눌렀을 때 등처럼 무조건 이동해야 하는 경우
- 마켓의 리뷰 달기 화면으로 직접 이동시켜주어야 함
// IOS - 리뷰 입력으로 이동
@IBAction func requestReviewManually() {
guard let writeReviewURL = URL(string: "https://apps.apple.com/app/id<#Your App Store ID#>?action=write-review")
else { fatalError("Expected a valid URL") }
UIApplication.shared.open(writeReviewURL, options: [:], completionHandler: nil)
}
// Android - 마켓으로만 이동
new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.golfzonretail"))
기타 Tips
- 유저가 만족한 경험을 한 후에 넣는 것이 좋음 (ex. 성공적으로 구매 완료)
-
- 사용자가 만족할 만한 경험을 하는 곳이 어딘지 확인해야!
- 앱이 안정화되기 전에는 오히려 역효과일 수 있음
-
- 좋은 경험 < 나쁜 경험에 대해 항의하기 위해 쓰는 경우가 多
- 따라서, 오히려 낮은 별점을 편하게 다는 것(?)을 장려하게 되는 꼴
- In-App Review 대신 수동으로 이동하는 방식도 多 고려함
-
- 만족한 경우는 리뷰로, 불만족한 경우는 문의하기로 넘기고자 하는 경우가 많은데
- In-App Review를 띄우기 전에는 어떤 문구도 띄울 수 X
- 따라서, 설정 메뉴 등에 해당 액션들을 따로 추가하는 방법도 많이들 고려함
- 문구를 가볍게 설정
-
- 평가해 달라는 말 대신 문구를 잘 선택하는 것도 중요
- 친근한 말투도 Good
- 단, 좋은 평점을 받기 위해 보상을 주는 것은 금지되어 있음
- 팝업이 오히려 부정적인 경험을 줄 수 있음
-
- 팝업 대신 화면에 넣는다거나 하는 방식도 있음
In-App Review
- 제약 多
- But, 앱 내에서 바로 리뷰를 입력할 수 있어 편하다
수동 이동
- 피드백, 리뷰를 분기해서 받을 수 있음 & 문구 직접 지정 가능
- 위치를 직접 지정할 수 있다 (팝업이 아니더라도 화면 내에 넣거나...)
- But, 스토어에서 직접 입력해야 하므로 중간에 이탈할 가능성이 높다
'💻 Android' 카테고리의 다른 글
[Android] Android CI/CD 구축하기 (1) - Firebase App Distribution, Play store 테스트 트랙 (0) | 2024.05.25 |
---|---|
[Android] Android 13 마이그레이션 (0) | 2024.03.09 |
[Android] 인스타그램 DM으로 공유하기 기능 만들기 (0) | 2023.09.23 |
[Android/MySQL] 안드로이드에서 JDBC 사용하기 (0) | 2022.11.08 |
[Android/Kotlin] 갤러리에서 이미지 가져오기 (0) | 2022.08.02 |