Android 앱에서 Rate It 기능을 구현하는 방법


95

Android 앱을 개발 중입니다. 모든 것이 올바르게 작동합니다. 내 앱을 실행할 준비가되었습니다. 하지만 거기에 하나 이상의 기능을 구현해야합니다. 다음을 포함하는 팝업을 표시해야합니다.

Rate ItRemind me later

여기에서 사용자가 시장에서 앱을 평가하면 팝업이 사라지지 않습니다. Google에서 검색 한 결과 링크가 하나 있습니다. 이것으로 나는 알 수 없다는 것을 이해합니다. 그래서 이것에 대한 제안이 필요합니다.

전에 이런 상황에 직면 한 사람이 있습니까? 그렇다면 이에 대한 해결책이나 대안이 있습니까?


그렇다면 평가 / 나중에 알림 만 요청하는 것입니까, 아니면 특정 사용자가 Android 앱을 평가했는지 확인하는 방법을 묻는 것입니까?
wtsang02 2013 년

1
팝업을 구현했습니다. 사용자가 응용 프로그램 평가 아닌지하지만 방법을 알고
나빈

-1이 질문과 링크에있는 질문의 차이를 보지 못했습니다.
wtsang02 2013-01-25

2
@ wtsang02, 사실 일 수 있습니다. 그러나 질문을보십시오. 그것에 물었다 Mar 15 2011. 거의 20 개월이 지났습니다. 내 요구 사항에 대한 해결책이나 대안이 있다고 생각합니다. 여기에 게시 된 yi입니다.
Naveen 2013 년

당신은 라이브러리를 사용할 수 있습니다 github.com/Vorlonsoft/AndroidRate ( implementation 'com.vorlonsoft:androidrate:1.0.3')
알렉산더 아버님 께 구원

답변:


182

나는 이것을 얼마 전에 구현했습니다. 평점이 통화가되는 것을 방지하기 위해 사용자가 앱을 평가했는지 여부를 알 수 없습니다 (일부 개발자는 "이 앱을 평가하고 앱에서 무료로 받기"와 같은 옵션을 추가 할 수 있음).

내가 작성한 클래스는 3 개의 버튼을 제공하고 앱이 실행 된 후에 만 ​​표시되도록 대화 상자를 구성합니다 n(사용자가 앱을 조금 전에 사용한 적이 있다면 앱을 평가할 가능성이 더 높습니다. 대부분은 가능성이 낮습니다). 첫 번째 실행에서 무엇을하는지 알기 위해) :

public class AppRater {
    private final static String APP_TITLE = "App Name";// App Name
    private final static String APP_PNAME = "com.example.name";// Package Name

    private final static int DAYS_UNTIL_PROMPT = 3;//Min number of days
    private final static int LAUNCHES_UNTIL_PROMPT = 3;//Min number of launches

    public static void app_launched(Context mContext) {
        SharedPreferences prefs = mContext.getSharedPreferences("apprater", 0);
        if (prefs.getBoolean("dontshowagain", false)) { return ; }

        SharedPreferences.Editor editor = prefs.edit();

        // Increment launch counter
        long launch_count = prefs.getLong("launch_count", 0) + 1;
        editor.putLong("launch_count", launch_count);

        // Get date of first launch
        Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0);
        if (date_firstLaunch == 0) {
            date_firstLaunch = System.currentTimeMillis();
            editor.putLong("date_firstlaunch", date_firstLaunch);
        }

        // Wait at least n days before opening
        if (launch_count >= LAUNCHES_UNTIL_PROMPT) {
            if (System.currentTimeMillis() >= date_firstLaunch + 
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)) {
                showRateDialog(mContext, editor);
            }
        }

        editor.commit();
    }   

    public static void showRateDialog(final Context mContext, final SharedPreferences.Editor editor) {
        final Dialog dialog = new Dialog(mContext);
        dialog.setTitle("Rate " + APP_TITLE);

        LinearLayout ll = new LinearLayout(mContext);
        ll.setOrientation(LinearLayout.VERTICAL);

        TextView tv = new TextView(mContext);
        tv.setText("If you enjoy using " + APP_TITLE + ", please take a moment to rate it. Thanks for your support!");
        tv.setWidth(240);
        tv.setPadding(4, 0, 4, 10);
        ll.addView(tv);

        Button b1 = new Button(mContext);
        b1.setText("Rate " + APP_TITLE);
        b1.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME)));
                dialog.dismiss();
            }
        });        
        ll.addView(b1);

        Button b2 = new Button(mContext);
        b2.setText("Remind me later");
        b2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        ll.addView(b2);

        Button b3 = new Button(mContext);
        b3.setText("No, thanks");
        b3.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (editor != null) {
                    editor.putBoolean("dontshowagain", true);
                    editor.commit();
                }
                dialog.dismiss();
            }
        });
        ll.addView(b3);

        dialog.setContentView(ll);        
        dialog.show();        
    }
}

클래스 통합은 다음을 추가하는 것만 큼 간단합니다.

AppRater.app_launched(this);

당신의 활동에. 전체 앱에서 하나의 활동에만 추가하면됩니다.


1
이것은 동일한 장치를 사용하는 여러 사용자를 지원하지 않습니다.
AsafK

1
@AsafK 예,하지만 동일한 장치를 사용하는 여러 사용자는 apprater인증 후 대화 상자를 표시 shared preference하고 key.
스티븐

1
안녕하세요, 질문이 하나뿐입니다. 왜 모든 것을 정적으로 만들었습니까? 감사합니다 Raghav!
Ruchir Baronia

2
안녕하세요, 위의 코드를 시도하고 있습니다. MainActivity AppRater.app_launched(this);안에 넣었습니다 onCreate(). 또한 필요한 최소 실행 횟수를 2로 변경했습니다. 그러나 2 개의 앱 실행 후 대화 상자가 표시되지 않습니다. 도와 주실 수 있나요? 감사!
예외

1
더 나은 열거를 사용 Context.MODE_PRIVATE-context.getSharedPreferences("apprater", Context.MODE_PRIVATE);
비벡

18

DialogFragment를 사용하는 내 것 :

public class RateItDialogFragment extends DialogFragment {
    private static final int LAUNCHES_UNTIL_PROMPT = 10;
    private static final int DAYS_UNTIL_PROMPT = 3;
    private static final int MILLIS_UNTIL_PROMPT = DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000;
    private static final String PREF_NAME = "APP_RATER";
    private static final String LAST_PROMPT = "LAST_PROMPT";
    private static final String LAUNCHES = "LAUNCHES";
    private static final String DISABLED = "DISABLED";

    public static void show(Context context, FragmentManager fragmentManager) {
        boolean shouldShow = false;
        SharedPreferences sharedPreferences = getSharedPreferences(context);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        long currentTime = System.currentTimeMillis();
        long lastPromptTime = sharedPreferences.getLong(LAST_PROMPT, 0);
        if (lastPromptTime == 0) {
            lastPromptTime = currentTime;
            editor.putLong(LAST_PROMPT, lastPromptTime);
        }

        if (!sharedPreferences.getBoolean(DISABLED, false)) {
            int launches = sharedPreferences.getInt(LAUNCHES, 0) + 1;
            if (launches > LAUNCHES_UNTIL_PROMPT) {
                if (currentTime > lastPromptTime + MILLIS_UNTIL_PROMPT) {
                    shouldShow = true;
                }
            }
            editor.putInt(LAUNCHES, launches);
        }

        if (shouldShow) {
            editor.putInt(LAUNCHES, 0).putLong(LAST_PROMPT, System.currentTimeMillis()).commit();
            new RateItDialogFragment().show(fragmentManager, null);
        } else {
            editor.commit();
        }
    }

    private static SharedPreferences getSharedPreferences(Context context) {
        return context.getSharedPreferences(PREF_NAME, 0);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.rate_title)
                .setMessage(R.string.rate_message)
                .setPositiveButton(R.string.rate_positive, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getActivity().getPackageName())));
                        getSharedPreferences(getActivity()).edit().putBoolean(DISABLED, true).commit();
                        dismiss();
                    }
                })
                .setNeutralButton(R.string.rate_remind_later, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dismiss();
                    }
                })
                .setNegativeButton(R.string.rate_never, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        getSharedPreferences(getActivity()).edit().putBoolean(DISABLED, true).commit();
                        dismiss();
                    }
                }).create();
    }
}

그런 다음 onCreate()기본 FragmentActivity 에서 사용하십시오 .

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    RateItDialogFragment.show(this, getFragmentManager());

}

잘 했어! Dialog를로드 할 때 문제가 발생하는 경우를 대비하여 DialogFragment를 표시하기 전에 editor.commit ()을 넣을 것입니다.
narko 2015 년

@narko 감사합니다. 업데이트되었습니다.
mixel

참고 : 공유 환경 설정을 저장하기 위해 적용하는 경우 메모리 누수가 발생할 수 있습니다. setPositiveButton및 에서주의 깊게 알아 차리면 setNegativeButton커밋을 사용하여 공유 환경 설정에 쓰고 있지만 적용을 사용하면 비동기이며 완료 될 때까지 활동에 대한 참조를 유지하고 즉시 해제를 호출합니다. Dismiss는 프래그먼트를 파괴하려고 시도하지만 공유 환경 설정 적용 프로세스에 의해 활동이 유지 / 사용되기 때문에 할 수 없습니다 (AndroidStudio가 사용자에게 적용 할 커밋을 변경하라는 메시지를 표시하기 때문에 이것을 착용했습니다. 다른 논리를 사용하십시오)
Sai

@mixel 조각없이 Activity에서 사용할 수 있도록 코드를 수정하는 방법은 무엇입니까?
user1090751

7

나는 당신이하려는 것이 아마도 비생산적이라고 생각합니다.

사람들이 앱을 쉽게 평가할 수 있도록하는 것이 일반적으로 좋은 생각입니다. 대부분의 사람들이 앱을 좋아하기 때문에 평가하기 때문입니다. 등급의 수가 시장 등급에 영향을 미친다는 소문이 있습니다 (이에 대한 증거는 거의 보이지 않지만). 사용자가 잔소리 화면을 통해 등급을 매기는 것은 사람들이 나쁜 등급을 남김으로써 잔소리를 없애 게 할 수 있습니다.

앱을 직접 평가하는 기능을 추가하면 무료 버전의 평점 수치가 약간 감소하고 유료 앱이 약간 증가했습니다. 무료 앱의 경우 내 앱이 훌륭하다고 생각했지만 좋지 않다고 생각하는 사람들도 평가하기 시작하면서 내 별 4 개 평점이 5 개 별 평점보다 높았습니다. 변화는 약 -0.2였습니다. 유료의 경우 변동은 약 +0.1입니다. 댓글을 많이받는 것을 좋아한다는 점을 제외하고는 무료 버전에서 삭제해야합니다.

평가 버튼을 설정 (기본 설정) 화면에 넣어 정상적인 작동에 영향을주지 않습니다. 여전히 내 평가율을 4 또는 5 배 증가 시켰습니다. 사용자에게 등급을 매기도록 잔소리를한다면 많은 사용자가 나에게 나쁜 평가를 내놓는 항의를 받게 될 것입니다.


100 % 사실입니다. 내 무료 앱에서도 같은 일이 일어났습니다.
akash varlani

6

AndroidRate 는 앱을 며칠 동안 사용한 후 사용자에게 평가를 요청하여 Android 앱을 홍보하는 데 도움이되는 라이브러리입니다.

모듈 Gradle :

dependencies {
  implementation 'com.vorlonsoft:androidrate:1.0.8'
}

MainActivity.java :

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  AppRate.with(this)
      .setStoreType(StoreType.GOOGLEPLAY) //default is GOOGLEPLAY (Google Play), other options are
                                          //           AMAZON (Amazon Appstore) and
                                          //           SAMSUNG (Samsung Galaxy Apps)
      .setInstallDays((byte) 0) // default 10, 0 means install day
      .setLaunchTimes((byte) 3) // default 10
      .setRemindInterval((byte) 2) // default 1
      .setRemindLaunchTimes((byte) 2) // default 1 (each launch)
      .setShowLaterButton(true) // default true
      .setDebug(false) // default false
      //Java 8+: .setOnClickButtonListener(which -> Log.d(MainActivity.class.getName(), Byte.toString(which)))
      .setOnClickButtonListener(new OnClickButtonListener() { // callback listener.
          @Override
          public void onClickButton(byte which) {
              Log.d(MainActivity.class.getName(), Byte.toString(which));
          }
      })
      .monitor();

  if (AppRate.with(this).getStoreType() == StoreType.GOOGLEPLAY) {
      //Check that Google Play is available
      if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {
          // Show a dialog if meets conditions
          AppRate.showRateDialogIfMeetsConditions(this);
      }
  } else {
      // Show a dialog if meets conditions
      AppRate.showRateDialogIfMeetsConditions(this);
  }
}

속도 대화 상자를 표시하는 기본 조건은 다음과 같습니다.

  1. 앱이 설치보다 10 일 이상 늦게 실행됩니다. 다음을 통해 변경AppRate#setInstallDays(byte) .
  2. 앱이 10 회 이상 실행되었습니다. 다음을 통해 변경AppRate#setLaunchTimes(byte) .
  3. 중립 버튼을 클릭 한 후 1 일이 지난 후 앱이 실행됩니다. 다음을 통해 변경AppRate#setRemindInterval(byte) .
  4. 앱이 X 번 실행되고 X % 1 = 0입니다. AppRate#setRemindLaunchTimes(byte) 입니다..
  5. 앱은 기본적으로 중립 대화 상자 (나중에 알림)를 표시합니다. 다음을 통해 변경setShowLaterButton(boolean) .
  6. 버튼을 눌렀을 때 콜백을 지정합니다. 의 두 번째 인수와 동일한 값이의 인수에 DialogInterface.OnClickListener#onClick전달됩니다.onClickButton .
  7. 설정 AppRate#setDebug(boolean)하면 앱이 실행될 때마다 등급 요청이 표시됩니다. 이 기능은 개발 전용입니다! .

대화 상자 표시를위한 선택적 사용자 지정 이벤트 요구 사항

대화 상자를 표시하기위한 추가 선택적 요구 사항을 추가 할 수 있습니다. 각 요구 사항은 고유 한 문자열로 추가 / 참조 할 수 있습니다. 이러한 각 이벤트에 대해 최소 횟수를 설정할 수 있습니다 (예 : "action_performed"3 회, "button_clicked"5 회 등).

AppRate.with(this).setMinimumEventCount(String, short);
AppRate.with(this).incrementEventCount(String);
AppRate.with(this).setEventCountValue(String, short);

대화 상자 표시 플래그 지우기

대화 상자를 다시 표시하려면을 호출하십시오 AppRate#clearAgreeShowDialog().

AppRate.with(this).clearAgreeShowDialog();

버튼을 누르면

전화 AppRate#showRateDialog(Activity).

AppRate.with(this).showRateDialog(this);

사용자 지정보기 설정

전화 AppRate#setView(View).

LayoutInflater inflater = (LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.custom_dialog, (ViewGroup)findViewById(R.id.layout_root));
AppRate.with(this).setView(view).monitor();

특정 테마

특정 테마를 사용하여 대화 상자를 부 풀릴 수 있습니다.

AppRate.with(this).setThemeResId(int);

사용자 정의 대화 상자

고유 한 대화 레이블을 사용하려면 애플리케이션에서 문자열 xml 리소스를 재정의합니다.

<resources>
    <string name="rate_dialog_title">Rate this app</string>
    <string name="rate_dialog_message">If you enjoy playing this app, would you mind taking a moment to rate it? It won\'t take more than a minute. Thanks for your support!</string>
    <string name="rate_dialog_ok">Rate It Now</string>
    <string name="rate_dialog_cancel">Remind Me Later</string>
    <string name="rate_dialog_no">No, Thanks</string>
</resources>

Google Play를 사용할 수 있는지 확인

if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {

}


3

이 솔루션은 위에 제시된 솔루션과 매우 유사합니다. 유일한 차이점은 실행 및 날짜별로 평가 대화 상자의 프롬프트를 지연 할 수 있다는 것입니다. 나중에 알림 버튼을 누르면 팝업이 3 일 동안 지연되고 10 번 실행됩니다. 평가하기로 선택한 사람들에게도 똑같이 적용되지만 지연 시간이 더 길어집니다 (사용자가 실제로 앱을 평가 한 경우 너무 빨리 사용자를 괴롭히지 않습니다. 다시 표시되지 않도록 변경할 수 있습니다. 코드를 원하는대로 변경하십시오). 누군가에게 도움이되기를 바랍니다!

public class AppRater {
    private final static String APP_TITLE = "your_app_name";
    private static String PACKAGE_NAME = "your_package_name";
    private static int DAYS_UNTIL_PROMPT = 5;
    private static int LAUNCHES_UNTIL_PROMPT = 10;
    private static long EXTRA_DAYS;
    private static long EXTRA_LAUCHES;
    private static SharedPreferences prefs;
    private static SharedPreferences.Editor editor;
    private static Activity activity;

    public static void app_launched(Activity activity1) {
        activity = activity1;

        Configs.sendScreenView("Avaliando App", activity);

        PACKAGE_NAME = activity.getPackageName();

        prefs = activity.getSharedPreferences("apprater", Context.MODE_PRIVATE);
        if (prefs.getBoolean("dontshowagain", false)) 
            return;

        editor = prefs.edit();

        EXTRA_DAYS = prefs.getLong("extra_days", 0);
        EXTRA_LAUCHES = prefs.getLong("extra_launches", 0);

        // Increment launch counter
        long launch_count = prefs.getLong("launch_count", 0) + 1;
        editor.putLong("launch_count", launch_count);

        // Get date of first launch
        Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0);
        if (date_firstLaunch == 0) {
            date_firstLaunch = System.currentTimeMillis();
            editor.putLong("date_firstlaunch", date_firstLaunch);
        }

        // Wait at least n days before opening
        if (launch_count >= (LAUNCHES_UNTIL_PROMPT + EXTRA_LAUCHES))
            if (System.currentTimeMillis() >= date_firstLaunch + (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000) + EXTRA_DAYS)
                showRateDialog();

        editor.commit();
    }   

    public static void showRateDialog() {
        final Dialog dialog = new Dialog(activity);
        dialog.setTitle("Deseja avaliar o aplicativo " + APP_TITLE + "?");

        LinearLayout ll = new LinearLayout(activity);
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setPadding(5, 5, 5, 5);

        TextView tv = new TextView(activity);
        tv.setTextColor(activity.getResources().getColor(R.color.default_text));
        tv.setText("Ajude-nos a melhorar o aplicativo com sua avaliação no Google Play!");
        tv.setWidth(240);
        tv.setGravity(Gravity.CENTER);
        tv.setPadding(5, 5, 5, 5);
        ll.addView(tv);

        Button b1 = new Button(activity);
        b1.setTextColor(activity.getResources().getColor(R.color.default_text));
        b1.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b1.setTextColor(Color.WHITE);
        b1.setText("Avaliar aplicativo " + APP_TITLE + "!");
        b1.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Avaliar", activity);

                activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + PACKAGE_NAME)));
                delayDays(60);
                delayLaunches(30);
                dialog.dismiss();
            }
        });        
        ll.addView(b1);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) b1.getLayoutParams();
        params.setMargins(5, 3, 5, 3);
        b1.setLayoutParams(params);

        Button b2 = new Button(activity);
        b2.setTextColor(activity.getResources().getColor(R.color.default_text));
        b2.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b2.setTextColor(Color.WHITE);
        b2.setText("Lembre-me mais tarde!");
        b2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Avaliar Mais Tarde", activity);
                delayDays(3);
                delayLaunches(10);
                dialog.dismiss();
            }
        });
        ll.addView(b2);
        params = (LinearLayout.LayoutParams) b2.getLayoutParams();
        params.setMargins(5, 3, 5, 3);
        b2.setLayoutParams(params);

        Button b3 = new Button(activity);
        b3.setTextColor(activity.getResources().getColor(R.color.default_text));
        b3.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b3.setTextColor(Color.WHITE);
        b3.setText("Não, obrigado!");
        b3.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Não Avaliar", activity);

                if (editor != null) {
                    editor.putBoolean("dontshowagain", true);
                    editor.commit();
                }
                dialog.dismiss();
            }
        });
        ll.addView(b3);
        params = (LinearLayout.LayoutParams) b3.getLayoutParams();
        params.setMargins(5, 3, 5, 0);
        b3.setLayoutParams(params);

        dialog.setContentView(ll);        
        dialog.show();        
    }

    private static void delayLaunches(int numberOfLaunches) {
        long extra_launches = prefs.getLong("extra_launches", 0) + numberOfLaunches;
        editor.putLong("extra_launches", extra_launches);
        editor.commit();
    }

    private static void delayDays(int numberOfDays) {
        Long extra_days = prefs.getLong("extra_days", 0) + (numberOfDays * 1000 * 60 * 60 * 24);
        editor.putLong("extra_days", extra_days);
        editor.commit();
    }
}

버튼에는 특정 색상과 배경이 있습니다. 배경은 다음 xml 파일에 표시된 것과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="10dp"
    android:shape="rectangle" >

    <solid android:color="#2E78B9" />

    <corners
        android:bottomLeftRadius="6dp"
        android:bottomRightRadius="6dp"
        android:topLeftRadius="6dp"
        android:topRightRadius="6dp" />

</shape>

출처 : "내 애플리케이션 평가"에 대한 Android 접근 방식


내가 시도 할 때 찾을 수없는 "구성"이란 무엇입니까?
Md Imran Choudhury

1
@ Md.ImranChoudhury 답장이 늦어서 죄송합니다. 구성은 Google 분석에 사용하는 개인용 클래스입니다. 문제없이 해당 진술을 제거 할 수 있습니다!
Gustavo Baiocchi Costa 2016

원래 답변에 연결하거나 그에게 크레딧을 제공해야합니다. stackoverflow.com/a/6920848/563735
Rohit Mandiwal 2017 년


1

링크 한 다른 게시물에서 알 수 있듯이 앱이 사용자가 리뷰를 남겼는지 여부를 알 수있는 방법이 없습니다. 그리고 그럴만 한 이유가 있습니다.

앱이 사용자가 리뷰를 남겼는지 여부를 알 수 있다면 개발자는 사용자가 5/5 평점을 남길 때만 잠금 해제되는 특정 기능을 제한 할 수 있습니다. 이로 인해 Google Play의 다른 사용자가 리뷰를 신뢰하지 않고 등급 시스템을 훼손 할 수 있습니다.

내가 본 대안은 앱이 특정 횟수 또는 설정된 간격으로 앱을 열 때마다 사용자에게 등급을 제출하도록 상기시키는 것입니다. 예를 들어, 앱이 열릴 때마다 사용자에게 평점을 남기고 "이미 완료"및 "나중에 알림"버튼을 제공하도록 요청합니다. 사용자가 나중에 알림을 선택한 경우이 메시지를 계속 표시합니다. 일부 다른 앱 개발자는 앱이 열릴 때 5, 10, 15n 번과 같이 사용자가 리뷰를 남기지 않은 경우 (예 : 앱을 열었을 때) 아마 그 / 그는 하나를 떠나지 않을 것입니다.

이 솔루션은 완벽하지 않지만 현재로서는 최선이라고 생각합니다. 사용자를 신뢰하게 만들지 만 대안이 앱 시장의 모든 사람에게 잠재적으로 더 나쁜 경험을 의미 할 수 있음을 인식하십시오.


1

자바 및 Kotlin 솔루션 (2020 년 Google의 인앱 리뷰 API) :

여기에 이미지 설명 입력

먼저 build.gradle(app)파일에 다음 종속성을 추가 하십시오 ( 여기에서 전체 설정 ).

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:core:1.8.0'
}

이 방법을에 추가하십시오 Activity.

void askRatings() {
    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();
            Task<Void> flow = manager.launchReviewFlow(this, reviewInfo);
            flow.addOnCompleteListener(task2 -> {
                // 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.
            });
        } else {
            // There was some problem, continue regardless of the result.
        }
    });
}

다른 방법과 같이 호출하십시오.

askRatings();

Kotlin 코드는 여기 에서 찾을 수 있습니다 .


0

Raghav Sood의 답변 Kotlin 버전

Rater.kt

    class Rater {
      companion object {
        private const val APP_TITLE = "App Name"
        private const val APP_NAME = "com.example.name"

        private const val RATER_KEY = "rater_key"
        private const val LAUNCH_COUNTER_KEY = "launch_counter_key"
        private const val DO_NOT_SHOW_AGAIN_KEY = "do_not_show_again_key"
        private const val FIRST_LAUNCH_KEY = "first_launch_key"

        private const val DAYS_UNTIL_PROMPT: Int = 3
        private const val LAUNCHES_UNTIL_PROMPT: Int = 3

        fun start(mContext: Context) {
            val prefs: SharedPreferences = mContext.getSharedPreferences(RATER_KEY, 0)
            if (prefs.getBoolean(DO_NOT_SHOW_AGAIN_KEY, false)) {
                return
            }

            val editor: Editor = prefs.edit()

            val launchesCounter: Long = prefs.getLong(LAUNCH_COUNTER_KEY, 0) + 1;
            editor.putLong(LAUNCH_COUNTER_KEY, launchesCounter)

            var firstLaunch: Long = prefs.getLong(FIRST_LAUNCH_KEY, 0)
            if (firstLaunch == 0L) {
                firstLaunch = System.currentTimeMillis()
                editor.putLong(FIRST_LAUNCH_KEY, firstLaunch)
            }

            if (launchesCounter >= LAUNCHES_UNTIL_PROMPT) {
                if (System.currentTimeMillis() >= firstLaunch +
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)
                ) {
                    showRateDialog(mContext, editor)
                }
            }

            editor.apply()
        }

        fun showRateDialog(mContext: Context, editor: Editor) {
            Dialog(mContext).apply {
                setTitle("Rate $APP_TITLE")

                val ll = LinearLayout(mContext)
                ll.orientation = LinearLayout.VERTICAL

                TextView(mContext).apply {
                    text =
                        "If you enjoy using $APP_TITLE, please take a moment to rate it. Thanks for your support!"

                    width = 240
                    setPadding(4, 0, 4, 10)
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "Rate $APP_TITLE"
                    setOnClickListener {
                        mContext.startActivity(
                            Intent(
                                Intent.ACTION_VIEW,
                                Uri.parse("market://details?id=$APP_NAME")
                            )
                        );
                        dismiss()
                    }
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "Remind me later"
                    setOnClickListener {
                        dismiss()
                    };
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "No, thanks"
                    setOnClickListener {
                        editor.putBoolean(DO_NOT_SHOW_AGAIN_KEY, true);
                        editor.commit()
                        dismiss()
                    };
                    ll.addView(this)
                }

                setContentView(ll)
                show()
            }
        }
    }
}

최적화 된 답변

Rater.kt

class Rater {
    companion object {
        fun start(context: Context) {
            val prefs: SharedPreferences = context.getSharedPreferences(RATER_KEY, 0)
            if (prefs.getBoolean(DO_NOT_SHOW_AGAIN_KEY, false)) {
                return
            }

            val editor: Editor = prefs.edit()

            val launchesCounter: Long = prefs.getLong(LAUNCH_COUNTER_KEY, 0) + 1;
            editor.putLong(LAUNCH_COUNTER_KEY, launchesCounter)

            var firstLaunch: Long = prefs.getLong(FIRST_LAUNCH_KEY, 0)
            if (firstLaunch == 0L) {
                firstLaunch = System.currentTimeMillis()
                editor.putLong(FIRST_LAUNCH_KEY, firstLaunch)
            }

            if (launchesCounter >= LAUNCHES_UNTIL_PROMPT) {
                if (System.currentTimeMillis() >= firstLaunch +
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)
                ) {
                    showRateDialog(context, editor)
                }
            }

            editor.apply()
        }

        fun showRateDialog(context: Context, editor: Editor) {
            Dialog(context).apply {
                setTitle("Rate $APP_TITLE")
                LinearLayout(context).let { layout ->
                    layout.orientation = LinearLayout.VERTICAL
                    setDescription(context, layout)
                    setPositiveAnswer(context, layout)
                    setNeutralAnswer(context, layout)
                    setNegativeAnswer(context, editor, layout)
                    setContentView(layout)
                    show()       
                }
            }
        }

        private fun setDescription(context: Context, layout: LinearLayout) {
            TextView(context).apply {
                text = context.getString(R.string.rate_description, APP_TITLE)
                width = 240
                setPadding(4, 0, 4, 10)
                layout.addView(this)
            }
        }

        private fun Dialog.setPositiveAnswer(
            context: Context,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.rate_now)
                setOnClickListener {
                    context.startActivity(
                        Intent(
                            Intent.ACTION_VIEW,
                            Uri.parse(context.getString(R.string.market_uri, APP_NAME))
                        )
                    );
                    dismiss()
                }
                layout.addView(this)
            }
        }

        private fun Dialog.setNeutralAnswer(
            context: Context,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.remind_later)
                setOnClickListener {
                    dismiss()
                };
                layout.addView(this)
            }
        }

        private fun Dialog.setNegativeAnswer(
            context: Context,
            editor: Editor,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.no_thanks)
                setOnClickListener {
                    editor.putBoolean(DO_NOT_SHOW_AGAIN_KEY, true);
                    editor.commit()
                    dismiss()
                };
                layout.addView(this)
            }
        }
    }
}

Constants.kt

object Constants {

    const val APP_TITLE = "App Name"
    const val APP_NAME = "com.example.name"

    const val RATER_KEY = "rater_key"
    const val LAUNCH_COUNTER_KEY = "launch_counter_key"
    const val DO_NOT_SHOW_AGAIN_KEY = "do_not_show_again_key"
    const val FIRST_LAUNCH_KEY = "first_launch_key"

    const val DAYS_UNTIL_PROMPT: Int = 3
    const val LAUNCHES_UNTIL_PROMPT: Int = 3

}

strings.xml

<resources>
    <string name="rate_description">If you enjoy using %1$s, please take a moment to rate it. Thanks for your support!</string>
    <string name="rate_now">Rate now</string>
    <string name="no_thanks">No, thanks</string>
    <string name="remind_later">Remind me later</string>
    <string name="market_uri">market://details?id=%1$s</string>
</resources>

0

개발자가 앱을 종료하지 않고도 Play 스토어 리뷰를 요청할 수있는 Android의 새로운 인앱 리뷰 시스템이 출시되었습니다.

디자인 지침 및 리뷰 카드 표시시기를 확인하려면 공식 문서를 참조하십시오.

https://developer.android.com/guide/playcore/in-app-review

구현:

  • build.gradle 파일에 play-core 라이브러리를 종속성으로 추가합니다.
implementation 'com.google.android.play:core:1.8.0'
  • 크리에이트 ReviewManager의 인스턴스를하고 요청 ReviewInfo의 개체를. ReviewInfo 개체는 미리 캐시 된 다음 "launchReviewFlow" 를 트리거 하여 사용자에게 리뷰 카드를 제공 할 수 있습니다.

     private var reviewInfo: ReviewInfo? = null
    
     val manager = ReviewManagerFactory.create(context)
    
     val request = manager.requestReviewFlow()
    
     requestFlow.addOnCompleteListener { request ->
         if (request.isSuccessful) {
             //Received ReviewInfo object
             reviewInfo = request.result
         } else {
             //Problem in receiving object
             reviewInfo = null
         }
    
     reviewInfo?.let {
         val flow = reviewManager.launchReviewFlow(this@MainActivity, it)
         flow.addOnCompleteListener {
             //Irrespective of the result, the app flow should continue
         }
     }

참고 : 사용자가 앱이나 게임을 충분히 경험 한 후에 검토 흐름을 표시하는 것이 좋습니다.

인앱 검토를 요청하는 경우 :

  • 사용자가 유용한 피드백을 제공하기에 충분한 앱 또는 게임을 경험 한 후 인앱 검토 흐름을 트리거합니다.
  • 사용자에게 과도하게 검토를 요청하지 마십시오. 이 접근 방식은 사용자의 불만을 최소화하고 API 사용을 제한하는 데 도움이됩니다 (할당량 섹션 참조).
  • 앱은 사용자의 의견에 대한 질문 (예 : "앱이 마음에 드십니까?") 또는 예측 질문 (예 : "이 앱을 별 5 개로 평가 하시겠습니까?"등)을 포함하여 등급 버튼 또는 카드를 표시하기 전이나 제시하는 동안 사용자에게 질문해서는 안됩니다. ”).

이것을 테스트하기 전에 몇 가지 사항 :

  • 새로운 기능을 테스트하는 동안 대부분은 새로운 ApplicationId가있는 새 프로젝트를 생성합니다. 이미 출시되어 플레이 스토어에서 사용 가능한 ApplicationId를 제공해야합니다.

  • 이전에 앱에 대한 피드백을 제공 한 경우 인앱 리뷰 API의 launchReviewFlow리뷰 카드를 표시하지 않습니다 . 단순히 성공 이벤트를 트리거합니다.

  • 할당량 제한으로 인해 launchReviewFlow 메서드를 호출하면 항상 대화 상자가 표시되지 않을 수 있습니다. 클릭 이벤트와 연결되어서는 안됩니다.


0

인앱 리뷰의 경우 아래가 구현되어 있는지 확인하세요.

implementation 'com.google.android.play:core:1.8.0'

OnCreate

public void RateApp(Context mContext) {
    try {
        ReviewManager manager = ReviewManagerFactory.create(mContext);
        manager.requestReviewFlow().addOnCompleteListener(new OnCompleteListener<ReviewInfo>() {
            @Override
            public void onComplete(@NonNull Task<ReviewInfo> task) {
                if(task.isSuccessful()){
                    ReviewInfo reviewInfo = task.getResult();
                    manager.launchReviewFlow((Activity) mContext, reviewInfo).addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(Exception e) {
                            Toast.makeText(mContext, "Rating Failed", Toast.LENGTH_SHORT).show();
                        }
                    }).addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            Toast.makeText(mContext, "Review Completed, Thank You!", Toast.LENGTH_SHORT).show();
                        }
                    });
                }

            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(Exception e) {
                Toast.makeText(mContext, "In-App Request Failed", Toast.LENGTH_SHORT).show();
            }
        });
    } catch (ActivityNotFoundException e) {
        e.printStackTrace();
    }
}

0

이 모든 라이브러리는이 게시물의 문제에 대한 해결책이 아닙니다. 이 라이브러리는 Google Play에서 앱에 대한 웹 페이지를 엽니 다. 대신이 Play 코어 라이브러리에는보다 일관된 인터페이스가 있습니다.

나는이 문제라고 생각합니다 그래서, ProGuard에서 : 그것은 충분히 어떤 클래스 obfscates https://stackoverflow.com/a/63650212/10117882을

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.