如何在Android App中实现Rate It功能

时间:2013-01-25 02:51:45

标签: android google-play

我正在开发Android应用程序。其中一切正常。我的应用已准备好发布。但我需要再实现一个功能。我需要显示一个包含

的弹出窗口

Rate ItRemind me later

如果有任何用户对该应用程序进行评级,那么弹出窗口就不会消失。 我在Google上搜索了一个link。有了这个,我明白它不可能知道。所以我需要一个建议。

以前有人遇到过这种情况吗?如果是这样,是否有任何解决方案或任何替代方案?

16 个答案:

答案 0 :(得分:155)

我在一段时间内实现了这一点。不可能知道用户是否对应用程序进行了评级,以防止评级成为一种货币(一些开发人员可能会添加一个选项,如“评价此应用程序并在应用程序中免费获取”)。

我编写的课程提供了三个按钮,并配置对话框,使其仅在应用程序启动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);

致你的活动。它只需要添加到整个应用程序中的一个Activity。

答案 1 :(得分:32)

我使用这个:https://github.com/kskkbys/Android-RateThisApp - 很好,有点不引人注意的行为。 RateThisApp screenshot from kskkbys

答案 2 :(得分:15)

我使用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();
    }
}

然后在主FragmentActivity的onCreate()中使用它:

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

    RateItDialogFragment.show(this, getFragmentManager());

}

答案 3 :(得分:6)

我认为你要做的事情可能适得其反。

让人们轻松评价应用程序通常是一个好主意,因为大多数人因为喜欢该应用而烦恼。据传,评级数量会影响您的市场评级(尽管我看不到这方面的证据)。通过唠叨屏幕对用户进行评级可能会导致人们通过留下不良评级来清除唠叨。

添加直接为应用评分的功能导致我的免费版本的数字评分略有下降,并且我的付费应用略有增加。对于免费的应用程序,我的4星评级增加超过我的5星评级,因为那些认为我的应用程序很好但不是很好的人开始评价它。变化约为-0.2。对于付费,变化约为+0.1。我应该从免费版本中删除它,除了我喜欢收到很多评论。

我将我的评级按钮放入设置(首选项)屏幕,它不会影响正常操作。它仍然将我的评级率提高了4或5倍。我毫不怀疑,如果我试图唠叨我的用户进行评级,我会让很多用户给我评价不好作为抗议。

答案 4 :(得分:5)

Java和Kotlin解决方案(Google于2020年提供的应用内审核API):

enter image description here

首先,在您的build.gradle(app)文件中,添加以下依赖项(完整设置here

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();

科特林码可以找到here

答案 5 :(得分:4)

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. App推出次数超过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)将确保每次启动应用时都会显示评级请求。 此功能仅适用于开发!
  8. 显示对话框的可选自定义事件要求

    您可以添加其他可选要求以显示对话框。每个需求都可以作为唯一字符串添加/引用。您可以为每个此类事件设置最小计数(例如,“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) {
    
    }
    

答案 6 :(得分:3)

使用此库,简单易用.. https://github.com/hotchemi/Android-Rate

添加依赖项..

dependencies {
  compile 'com.github.hotchemi:android-rate:0.5.6'
}

答案 7 :(得分:2)

我正在使用这个简单的解决方案。 您可以使用gradle添加此库: https://github.com/fernandodev/easy-rating-dialog

compile 'com.github.fernandodev.easyratingdialog:easyratingdialog:+'

答案 8 :(得分:1)

正如您从已发布链接的其他帖子中看到的那样,应用无法知道用户是否已离开评论。并且有充分的理由。

考虑一下,如果应用程序可以判断用户是否已经离开了评论,那么开发人员可能会限制某些功能,这些功能只有在用户离开5/5评级时才会解锁。这会导致Google Play的其他用户不信任评论,并会破坏评级系统。

我看到的替代解决方案是应用程序提醒用户在应用程序打开特定次数或设置间隔时提交评级。例如,应用程序每打开一次,请让用户留下评级并提供“已完成”和“稍后提醒我”按钮。如果用户选择稍后提醒他/她,请继续显示此消息。其他一些应用程序开发人员显示此消息的间隔越来越大(例如,打开应用程序的时间是5,10,15),因为如果用户没有在应用程序打开的第100次上留下评论,那么可能他/她不会离开一个。

这个解决方案并不完美,但我认为这是目前最好的解决方案。它确实引导您信任用户,但意识到替代方案对于应用市场中的每个人来说都意味着更糟糕的体验。

答案 9 :(得分:1)

Android推出了新的应用内评论系统,开发人员可以在不离开应用程序的情况下要求Play商店评论。

要查看设计指南以及何时显示评论卡,请参阅正式文件

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

要实施:

  • 在您的build.gradle文件中将播放核心库添加为依赖项。
implementation 'com.google.android.play:core:1.8.0'
  • 创建一个 ReviewManager 实例并请求 ReviewInfo 对象。要预先缓存的ReviewInfo对象,然后可以触发“ launchReviewFlow” ,向用户出示Review卡。

     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方法可能并不总是显示对话框。它不应与任何点击事件链接。

答案 10 :(得分:1)

确保为应用内评论实施以下内容:

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();
    }
}

答案 11 :(得分:1)

从2020年8月开始,Google Play的应用内审核API可用,根据answer,其直接实现是正确的。

但是,如果您希望在其顶部添加一些显示逻辑,请使用Five-Star-Me库。

在MainActivity的onCreate方法中设置启动时间和安装天数,以配置库。

  FiveStarMe.with(this)
      .setInstallDays(0) // default 10, 0 means install day.
      .setLaunchTimes(3) // default 10
      .setDebug(false) // default false
      .monitor();

然后将以下方法调用放在任何活动/片段的onCreate / onViewCreated方法上,以在满足条件时显示提示。

FiveStarMe.showRateDialogIfMeetsConditions(this); //Where *this* is the current activity.

enter image description here

安装说明:

您可以从jitpack下载。

步骤1: 将此添加到项目(根)build.gradle。

allprojects {
  repositories {
    ...
    maven { url 'https://jitpack.io' }
  }
}

步骤2: 在模块(应用)级别的build.gradle中添加以下依赖项。

dependencies {
  implementation 'com.github.numerative:Five-Star-Me:2.0.0'
}

答案 12 :(得分:1)

现在您可以使用 In App Rating feature by Google

Here is Kotlin/Java integration official guide

<块引用>

Google Play In-App Review API 可让您提示用户提交 Play 商店评分和评论,而无需离开您的应用或游戏。

通常,应用内审核流程(见图 1)可以在 在您的应用程序的整个用户旅程中的任何时间。在流动过程中, 用户可以使用 1 到 5 星系统对您的应用进行评分,并且 添加可选注释。提交后,审核将发送至 Play 商店并最终显示出来。

sc

答案 13 :(得分:0)

拉格夫·苏德的答案的科特琳版

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>

答案 14 :(得分:0)

所有这些库都不是本文中解决该问题的方法。 该库仅打开Goog​​le Play上该应用程序的网页。 相反,此Play核心库具有更一致的界面。

所以我认为这是问题,ProGuard:它足以掩盖某些类 https://stackoverflow.com/a/63650212/10117882

答案 15 :(得分:0)

我使用应用内评论系统和计数器的简单方法。

import android.content.Context
import androidx.core.content.edit
import java.util.concurrent.TimeUnit

object Rater {
    private const val DAYS_UNTIL_PROMPT = 3L//Min number of days
    private const val LAUNCHES_UNTIL_PROMPT = 3//Min number of launches
    private const val RATER_KEY = "rater_key"
    private const val LAUNCH_COUNTER_KEY = "launch_counter_key"
    private const val FIRST_LAUNCH_KEY = "first_launch_key"

    fun Context.appRateCheck(dialog: () -> Unit) {
        val prefs = getSharedPreferences(RATER_KEY, 0)
        val launchesCounter = prefs.getLong(LAUNCH_COUNTER_KEY, 0) + 1
        prefs.edit { putLong(LAUNCH_COUNTER_KEY, launchesCounter) }

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

        if (launchesCounter >= LAUNCHES_UNTIL_PROMPT) {
            if (System.currentTimeMillis() >= firstLaunch + TimeUnit.DAYS.toMillis(DAYS_UNTIL_PROMPT)) {
                dialog()
            }
        }
    }
}

用法:

private val manager: ReviewManager by lazy { ReviewManagerFactory.create(context) }

private fun initInAppReview() {
    context?.appRateCheck {
        manager.requestReviewFlow().addOnSuccessListener {
            manager.launchReviewFlow(requireActivity(), it)
        }
    }
}