我正在开发一个 Android 应用程序。其中一切正常。我的应用程序已准备好启动。但是我需要再实现一项功能。我需要显示一个弹出窗口,其中包含
Rate It
和Remind me later
在这里,如果任何用户对市场上的应用程序进行评分,则弹出窗口不会消失。我在 Google 中搜索并找到了一个链接。有了这个,我明白这是不可能知道的。所以我需要一个建议。
以前有人遇到过这种情况吗?如果是这样,是否有任何解决方案或替代方案?
我正在开发一个 Android 应用程序。其中一切正常。我的应用程序已准备好启动。但是我需要再实现一项功能。我需要显示一个弹出窗口,其中包含
Rate It
和Remind me later
在这里,如果任何用户对市场上的应用程序进行评分,则弹出窗口不会消失。我在 Google 中搜索并找到了一个链接。有了这个,我明白这是不可能知道的。所以我需要一个建议。
以前有人遇到过这种情况吗?如果是这样,是否有任何解决方案或替代方案?
在某种程度上,我不久前实施了这一点。无法知道用户是否对应用进行了评分,以防止评分成为货币(一些开发人员可能会添加“评价此应用并在应用中免费获得某某”之类的选项)。
我编写的类提供了三个按钮,并配置了对话框,使其仅在应用程序启动后才显示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 中。
我的一个使用 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());
}
首先,在您的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 代码可以在这里找到
我认为您尝试做的事情可能适得其反。
让人们更容易对应用程序进行评分通常是一个好主意,因为大多数人这样做是因为他们喜欢该应用程序。有传言说评级的数量会影响你的市场评级(尽管我几乎看不到这方面的证据)。骚扰用户进行评分 - 通过唠叨屏幕 - 可能会导致人们通过留下差评来清除唠叨。
添加直接评价应用程序的功能导致我的免费版本的数字评分略有下降,而我的付费应用程序则略有增加。对于免费应用程序,我的 4 星评分比我的 5 星评分增加了更多,因为那些认为我的应用程序很好但不是很好的人也开始给它评分。变化约为-0.2。对于付费,变化约为+0.1。我应该从免费版本中删除它,除非我喜欢得到很多评论。
我将评分按钮放入设置(首选项)屏幕,它不会影响正常操作。它仍然使我的评分率提高了 4 或 5 倍。我毫不怀疑,如果我试图唠叨我的用户进行评分,我会得到很多用户给我差评作为抗议。
AndroidRate是一个库,可通过提示用户在使用几天后对应用进行评分来帮助您推广您的 Android 应用。
模块摇篮:
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);
}
}
显示速率对话框的默认条件如下:
AppRate#setInstallDays(byte)
。AppRate#setLaunchTimes(byte)
。AppRate#setRemindInterval(byte)
。AppRate#setRemindLaunchTimes(byte)
。setShowLaterButton(boolean)
。DialogInterface.OnClickListener#onClick
将在 的参数中传递onClickButton
。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>
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {
}
确保执行以下内容 对于应用内评论:
implementation 'com.google.android.play:core:1.8.0'
创建时
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();
}
}
该解决方案与上述解决方案非常相似。唯一的区别是您将能够在每次启动和天数时延迟评级对话框的提示。如果按下稍后提醒我按钮,那么我将延迟弹出窗口 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>
使用这个库,简单易行.. https://github.com/hotchemi/Android-Rate
通过添加依赖..
dependencies {
compile 'com.github.hotchemi:android-rate:0.5.6'
}
截至 2020 年 8 月,Google Play 的应用内评论 API 可用,并且根据此答案,其直接实施是正确的。
但是,如果您希望在其上添加一些显示逻辑,请使用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.
安装说明:
您可以从 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'
}
我正在使用这个简单的解决方案。您可以使用 gradle 添加此库: https ://github.com/fernandodev/easy-rating-dialog
compile 'com.github.fernandodev.easyratingdialog:easyratingdialog:+'
Google Play 应用内评论 API 可让您提示用户提交 Play 商店评分和评论,而无需离开您的应用或游戏。
通常,应用内审核流程(见图 1)可以在应用的整个用户旅程中随时触发。在流程中,用户可以使用 1 到 5 星系统对您的应用程序进行评分并添加可选评论。提交后,评论将发送到 Play 商店并最终显示。
正如您从已链接的其他帖子中看到的那样,应用程序无法知道用户是否留下了评论。并且有充分的理由。
想一想,如果一个应用程序可以判断用户是否留下了评论,开发人员可以限制某些功能,这些功能只有在用户留下 5/5 评分时才会解锁。这将导致 Google Play 的其他用户不信任评论并破坏评级系统。
我见过的替代解决方案是,每当应用打开特定次数或设定的时间间隔时,应用都会提醒用户提交评分。例如,应用程序每打开 10 次,就要求用户留下评分并提供“已经完成”和“稍后提醒我”按钮。如果用户选择稍后提醒他/她,请继续显示此消息。其他一些应用程序开发人员会以越来越长的间隔显示此消息(例如,应用程序打开的第 5、10、15 次),因为如果用户没有在应用程序打开的第 100 次时留下评论,则很可能他/她不会留下一个。
这个解决方案并不完美,但我认为这是你目前最好的。它确实使您信任用户,但意识到替代方案可能对应用市场中的每个人都意味着更糟糕的体验。
Raghav Sood 答案的 Kotlin 版本
评分者.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()
}
}
}
}
优化答案
评分者.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)
}
}
}
}
常量.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
}
字符串.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>
Android 推出了新的应用内评论系统,开发者可以在不离开应用的情况下询问 Play 商店评论。
要查看设计指南以及何时显示审核卡,请参阅官方文档
实施:
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
}
}
注意:建议在用户充分体验您的应用或游戏后显示评论流程。
何时请求应用内评论:
测试之前的几点:
在测试新功能时,大多数情况下我们会创建一个具有新 ApplicationId 的新项目,确保您提供的 ApplicationId 已经发布并在 Play 商店中可用。
如果您过去曾为您的应用提供过反馈,则应用内评论 API 的launchReviewFlow将不会显示任何评论卡。它只是触发一个成功事件。
由于配额限制,调用 launchReviewFlow 方法可能并不总是显示对话框。它不应与任何点击事件相关联。
所有这些库都不是本文中问题的解决方案。这个库只是在 google play 上打开一个应用程序的网页。相反,这个 Play 核心库有更一致的接口。
所以我认为这是问题所在,ProGuard:它模糊了一些类 https://stackoverflow.com/a/63650212/10117882
我使用应用内评论系统和计数器的简单方法。
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)
}
}
}
您可以调用 Google In-App Review API。你不需要计算,因为谷歌会为你处理这个问题。如果之前有人给过星或评论,Google 将不会再显示此提示。
看看下面的代码片段。
1-) 首先添加导入 ReviewManagerFactory
import com.google.android.play.core.review.ReviewManagerFactory
2-) 在适当的地点和时间添加下面的代码片段。
使用 ReviewInfo 实例启动应用内评论流程。等到用户完成应用内审核流程后,您的应用才会继续正常的用户流程
fun inAppReview() {
val reviewManager = ReviewManagerFactory.create(this)
val requestReviewFlow = reviewManager.requestReviewFlow()
requestReviewFlow.addOnCompleteListener { request ->
if (request.isSuccessful) {
// We got the ReviewInfo object
val reviewInfo = request.result
val flow = reviewManager.launchReviewFlow(this, reviewInfo)
flow.addOnCompleteListener {
// Call back
}
} else {
Log.d("Error: ", request.exception.toString())
// There was some problem, continue regardless of the result.
}
}
}