104

私はAndroidアプリを開発しています。すべてが正しく機能しています。アプリを起動する準備ができました。しかし、もう 1 つの機能を実装する必要があります。含むポップアップを表示する必要があります

Rate ItRemind me later

ここで、ユーザーが市場でアプリを評価した場合、ポップアップは消えません。Google で検索したところ、リンクが 1 つ見つかりました。これで、知ることは不可能であることを理解しています。だから私はこれに対する提案が必要です。

誰かが以前にこの状況に直面したことがありますか? もしそうなら、これに対する解決策または代替手段はありますか?

4

17 に答える 17

192

私はこれをある程度前に実装しました。評価が通貨になるのを防ぐために、ユーザーがアプリを評価したかどうかを知ることは不可能です (一部の開発者は、「このアプリを評価すると、アプリで無料で取得する」などのオプションを追加する場合があります)。

私が作成したクラスは 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 つのアクティビティに追加するだけで済みます。

于 2013-01-25T03:06:20.053 に答える
8

あなたがやろうとしていることはおそらく非生産的だと思います。

人々がアプリを評価しやすいようにすることは、一般的には良い考えです. 評価の数が市場の評価に影響を与えるという噂があります (ただし、これに関する証拠はほとんどありません)。ナグ画面を介してユーザーに評価を求めるのは、悪い評価を残してナグを解消する可能性があります。

アプリを直接評価する機能を追加したことで、無料版の数値評価がわずかに減少し、有料アプリの数値がわずかに増加しました。無料アプリの場合、4 つ星の評価が 5 つ星の評価よりも高くなりました。これは、私のアプリは良いがあまり良くないと考えていた人々も同様に評価し始めたためです。変化は約-0.2でした。有償は+0.1程度の変動。たくさんのコメントをもらうのが好きな場合を除いて、無料版から削除する必要があります。

評価ボタンを設定 (プリファレンス) 画面に配置しましたが、通常の操作には影響しません。それでも、私の評価率は 4 倍か 5 倍になりました。ユーザーに評価をつけさせようとすると、多くのユーザーが抗議として悪い評価をしてくれることは間違いありません。

于 2013-01-25T03:57:36.260 に答える
3

このライブラリを使用してください. シンプルで簡単です.. https://github.com/hotchemi/Android-Rate

依存関係を追加することによって..

dependencies {
  compile 'com.github.hotchemi:android-rate:0.5.6'
}
于 2016-01-14T12:37:52.617 に答える
2

私はこの簡単な解決策を使用しています。このライブラリを gradle で追加するだけです: https://github.com/fernandodev/easy-rating-dialog

compile 'com.github.fernandodev.easyratingdialog:easyratingdialog:+'
于 2014-08-13T11:41:45.667 に答える
1

リンクした他の投稿からわかるように、ユーザーがレビューを残したかどうかをアプリが知る方法はありません。そして正当な理由があります。

ユーザーがレビューを残したかどうかをアプリが判断できれば、開発者は、ユーザーが 5/5 の評価を残した場合にのみロック解除される特定の機能を制限できます。これにより、Google Play の他のユーザーがレビューを信頼できなくなり、評価システムが弱体化する可能性があります。

私が見た代替ソリューションは、アプリが特定の回数、または設定された間隔で開かれるたびに、評価を送信するようにユーザーに通知することです。たとえば、アプリを開く 10 回ごとに、ユーザーに評価を残して「完了済み」ボタンと「後で通知」ボタンを提供するように依頼します。ユーザーが後で通知することを選択した場合は、このメッセージを表示し続けます。他のアプリ開発者の中には、このメッセージを表示する間隔を増やして (アプリを開く 5 回目、10 回目、15 回目など)、たとえばアプリを開いた 100 回目にユーザーがレビューを残さなかった場合、それはおそらく彼女/彼は1つを離れることはありません。

この解決策は完璧ではありませんが、現時点で最善の解決策だと思います。それはユーザーを信頼することにつながりますが、代替案はアプリ市場のすべての人にとって潜在的に悪い経験を意味することを認識してください.

于 2013-01-25T03:02:43.120 に答える
1

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>
于 2020-03-27T10:41:43.093 に答える
0

Google アプリ内レビュー API を呼び出すことができます。この問題は Google が処理するため、カウントする必要はありません。誰かが以前に星やコメントを付けた場合、Google はこのプロンプトを再度表示しません。

以下のコード スニペットを見てください。

1-) 最初に import 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.
        }
    }
}

Google Doc : アプリ内レビュー

于 2021-10-09T10:25:09.770 に答える
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)
        }
    }
}
于 2021-03-11T16:04:58.690 に答える