วิธีใช้คุณสมบัติ Rate It ในแอพ Android


98

ฉันกำลังพัฒนาแอพ Android ซึ่งทุกอย่างทำงานได้ถูกต้อง แอปของฉันพร้อมเปิดตัวแล้ว แต่ที่นั่นฉันต้องใช้คุณสมบัติอีกอย่างหนึ่ง ฉันต้องการแสดงป๊อปอัปที่มีไฟล์

Rate It และ Remind me later

ที่นี่หากผู้ใช้ให้คะแนนแอปในตลาดป๊อปอัปจะไม่หายไป ฉันได้ค้นหาใน Google และพบว่าหนึ่งในการเชื่อมโยง ด้วยเหตุนี้ฉันจึงเข้าใจว่ามันไม่มีทางรู้ได้ ดังนั้นฉันต้องการคำแนะนำสำหรับสิ่งนี้

ใครเคยเผชิญกับสถานการณ์นี้มาก่อนหรือไม่? ถ้าเป็นเช่นนั้นมีวิธีแก้ไขหรือทางเลือกอื่นสำหรับสิ่งนี้หรือไม่?


1
คุณกำลังขอเพียงแค่ให้คะแนน / เตือนฉันในภายหลังหรือคุณกำลังขอให้ทราบว่าผู้ใช้รายใดให้คะแนนแอป Android หรือไม่?
wtsang02

1
ฉันได้ติดตั้งป๊อปอัป แต่จะรู้ได้อย่างไรว่าผู้ใช้ให้คะแนนแอปหรือไม่
Naveen

-1 ฉันไม่เห็นความแตกต่างระหว่างคำถามนี้กับคำถามในลิงก์
wtsang02

2
@ wtsang02 อาจจะเป็นเรื่องจริง แต่ดูคำถาม. Mar 15 2011มันถาม ผ่านไปเกือบ 20 เดือน ฉันคิดว่าบางคนมีทางออกหรือทางเลือกอื่นสำหรับความต้องการของฉัน ที่ยี่โพสต์ที่นี่
Naveen

คุณสามารถใช้ห้องสมุดgithub.com/Vorlonsoft/AndroidRate ( implementation 'com.vorlonsoft:androidrate:1.0.3')
Alexander Savin

คำตอบ:


183

ฉันใช้สิ่งนี้ในขณะที่ย้อนกลับไปในระดับหนึ่ง เป็นไปไม่ได้ที่จะทราบว่าผู้ใช้ให้คะแนนแอปหรือไม่เพื่อป้องกันไม่ให้การให้คะแนนกลายเป็นสกุลเงิน (นักพัฒนาบางรายอาจเพิ่มตัวเลือกเช่น "ให้คะแนนแอปนี้และรับในแอปฟรี")

คลาสที่ฉันเขียนมีปุ่มสามปุ่มและกำหนดค่ากล่องโต้ตอบเพื่อให้แสดงหลังจาก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เพื่อรวมที่อยู่อีเมล Google ในไฟล์key.
stephen

1
สวัสดีฉันมีคำถามเพียงข้อเดียว ทำไมคุณถึงทำให้ทุกอย่างนิ่ง ขอบคุณ Raghav!
Ruchir Baronia

2
สวัสดีฉันกำลังลองใช้รหัสด้านบนของคุณ ฉันใส่ไว้AppRater.app_launched(this);ในonCreate()MainActivity ของฉัน ฉันได้เปลี่ยนจำนวนการเปิดตัวขั้นต่ำที่จำเป็นเป็น 2 ด้วย แต่ฉันไม่เห็นกล่องโต้ตอบหลังจากเปิด 2 แอป คุณช่วยฉันได้ไหม ขอบคุณ!
ข้อยกเว้น

2
ใช้ enum ดีกว่าContext.MODE_PRIVATE-context.getSharedPreferences("apprater", Context.MODE_PRIVATE);
Vivek

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

}

สิ่งที่ดี! ฉันจะใส่ editor.commit () ก่อนที่จะแสดง DialogFragment ในกรณีที่มีข้อผิดพลาดเกิดขึ้นเมื่อโหลด Dialog
narko

@narko ขอบคุณ อัปเดตแล้ว
mixel

หมายเหตุ: อาจทำให้หน่วยความจำรั่วได้หากคุณใช้เพื่อบันทึกค่ากำหนดที่แชร์ หากคุณสังเกตอย่างถี่ถ้วนsetPositiveButtonและsetNegativeButtonเป็นการเขียนถึงการตั้งค่าที่ใช้ร่วมกันโดยใช้การกระทำ แต่ถ้าคุณใช้ apply ซึ่งเป็น async และจะเก็บข้อมูลอ้างอิงไปยังกิจกรรมจนกว่าจะเข้ากันได้และทันทีหลังจากนั้นจะเรียกการปิด การปิดจะพยายามทำลายแฟรกเมนต์ แต่ทำไม่ได้เนื่องจากกิจกรรมถูกระงับ / ใช้โดยการกำหนดค่าตามความชอบที่ใช้ร่วมกันใช้กระบวนการ (ฉันสวมสิ่งนี้เนื่องจาก AndroidStudio จะแจ้งให้ผู้ใช้เปลี่ยนการกระทำที่จะใช้อย่าทำมันเว้นแต่คุณจะ ใช้ตรรกะอื่น ๆ )
ทราย

@mixel จะแก้ไขโค้ดอย่างไรให้สามารถใช้งานในกิจกรรมและไม่มีส่วนย่อยได้?
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. App จะเปิดตัวครั้ง X และ X% 1 = 0 AppRate#setRemindLaunchTimes(byte)เปลี่ยนผ่าน
  5. แอปแสดงกล่องโต้ตอบที่เป็นกลาง (เตือนฉันในภายหลัง) โดยค่าเริ่มต้น เปลี่ยนผ่านsetShowLaterButton(boolean).
  6. เพื่อระบุการโทรกลับเมื่อกดปุ่ม ค่าเช่นเดียวกับอาร์กิวเมนต์ที่สองของจะถูกส่งผ่านในการโต้เถียงของDialogInterface.OnClickListener#onClickonClickButton
  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) {

}

5

โซลูชัน Java & Kotlin (API การตรวจสอบในแอปโดย Google ในปี 2020):

ป้อนคำอธิบายภาพที่นี่

ขั้นแรกใน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 สามารถพบได้ที่นี่


แต่กล่องโต้ตอบบทวิจารณ์นี้แสดงเพียงครั้งเดียวเราจะแสดงกล่องโต้ตอบการตรวจสอบในแอปนี้มากกว่าหนึ่งครั้งในแอปได้อย่างไร
user2162130

@ user2162130 ยังไม่ได้ทดสอบ แต่ฉันคิดว่า Google ต้องทำตามวัตถุประสงค์เพื่อป้องกันไม่ให้กล่องโต้ตอบเปิดมากกว่าหนึ่งครั้งมิฉะนั้นผู้ใช้จะรู้สึกท่วมท้นหากนักพัฒนายังคงขอให้ตรวจสอบ
iDecode

1
สวัสดีฉันพบวิธีแก้ปัญหาแล้วเราสามารถทดสอบแอปโดยใช้การแชร์แอปภายในของ Google ซึ่งเราสามารถอัปโหลด apk เพื่อทดสอบกล่องโต้ตอบการให้คะแนนในแอป หลังจากอัปโหลดเราสามารถทดสอบแอปได้มันจะแสดงกล่องโต้ตอบการให้คะแนนในแอปทุกครั้งตามเงื่อนไขของคุณที่คุณทำในแอป
user2162130

1
@ AG-Developer ยังไม่ได้ตรวจสอบ แต่ฉันแน่ใจว่าต้องเป็น API> = 21
iDecode

3

ใช้ไลบรารีนี้ง่ายและสะดวก .. https://github.com/hotchemi/Android-Rate

โดยเพิ่มการพึ่งพา ..

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

1
คุณสามารถใช้ไลบรารีgithub.com/Vorlonsoft/AndroidRate ( implementation 'com.vorlonsoft:androidrate:1.0.3') เป็นข้อมูลล่าสุด
Alexander Savin

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 สำหรับ "ให้คะแนนแอปพลิเคชันของฉัน"


"Configs" คืออะไรไม่พบเมื่อฉันลอง
Md Imran Choudhury

1
@ Md.ImranChoudhury ขออภัยที่ตอบช้า Configs เป็นคลาสส่วนตัวของฉันที่ฉันใช้สำหรับ Google Analytics คุณสามารถลบคำสั่งนั้นได้โดยไม่มีปัญหา!
Gustavo Baiocchi Costa

คุณควรเชื่อมโยงไปยังคำตอบเดิมหรือให้เครดิตกับเขา stackoverflow.com/a/6920848/563735
Rohit Mandiwal


1

ดังที่คุณเห็นจากโพสต์อื่น ๆ ที่คุณได้เชื่อมโยงไม่มีวิธีใดที่แอปจะทราบได้ว่าผู้ใช้ได้แสดงความเห็นหรือไม่ และด้วยเหตุผลที่ดี

ลองคิดดูว่าหากแอปสามารถบอกได้ว่าผู้ใช้เขียนรีวิวไว้หรือไม่นักพัฒนาสามารถ จำกัด คุณสมบัติบางอย่างที่จะปลดล็อกได้ก็ต่อเมื่อผู้ใช้ให้คะแนน 5/5 สิ่งนี้จะทำให้ผู้ใช้ Google Play คนอื่น ๆ ไม่ไว้วางใจบทวิจารณ์และจะทำลายระบบการให้คะแนน

ทางเลือกอื่นที่ฉันได้เห็นคือแอปจะเตือนให้ผู้ใช้ส่งการให้คะแนนเมื่อใดก็ตามที่เปิดแอปตามจำนวนครั้งที่กำหนดหรือช่วงเวลาที่กำหนด ตัวอย่างเช่นทุกวันที่ 10 ที่เปิดแอปขอให้ผู้ใช้ให้คะแนนและระบุปุ่ม "เสร็จแล้ว" และ "เตือนฉันในภายหลัง" แสดงข้อความนี้ต่อไปหากผู้ใช้เลือกที่จะเตือนเขาในภายหลัง นักพัฒนาแอปอื่น ๆ บางรายแสดงข้อความนี้พร้อมกับช่วงเวลาที่เพิ่มขึ้น (เช่น 5, 10, 15 ครั้งที่เปิดแอป) เนื่องจากหากผู้ใช้ไม่ได้เขียนรีวิวไว้เช่นครั้งที่ 100 ที่เปิดแอป อาจเป็นไปได้ว่าเขา / เขาจะไม่จากไป

โซลูชันนี้ไม่สมบูรณ์แบบ แต่ฉันคิดว่าดีที่สุดที่คุณมีในตอนนี้ มันทำให้คุณไว้วางใจผู้ใช้ แต่ตระหนักดีว่าทางเลือกอื่นอาจหมายถึงประสบการณ์ที่แย่กว่าสำหรับทุกคนในตลาดแอป


1

ระบบตรวจสอบในแอปใหม่ของ Android เปิดตัวซึ่งช่วยให้นักพัฒนาสามารถขอรีวิวจาก Play Store ได้โดยไม่ต้องออกจากแอป

หากต้องการตรวจสอบแนวทางการออกแบบและเวลาที่จะแสดงบัตรตรวจสอบโปรดดูเอกสารอย่างเป็นทางการ

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

วิธีใช้:

  • เพิ่มไลบรารี play-core เป็นการอ้างอิงในไฟล์ build.gradle ของคุณ
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 ที่เปิดตัวแล้วและพร้อมใช้งานใน play store

  • ถ้าคุณได้รับการตอบรับที่ผ่านมาสำหรับแอปของคุณในแอปรีวิวของ API launchReviewFlowจะไม่นำเสนอใด ๆบัตรรีวิว เพียงแค่กระตุ้นเหตุการณ์ความสำเร็จ

  • เนื่องจากข้อ จำกัด โควต้าการเรียกเมธอด launchReviewFlow อาจไม่แสดงกล่องโต้ตอบเสมอไป ไม่ควรเชื่อมโยงกับเหตุการณ์การคลิกใด ๆ


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

1

ในฐานะที่เป็น 2020 สิงหาคมของ Google Play ในแอปรีวิว API มีให้บริการและการดำเนินการตรงไปตรงมาของมันคือการที่ถูกต้องตามนี้คำตอบ

แต่ถ้าคุณต้องการเพิ่มตรรกะการแสดงผลด้านบนให้ใช้ไลบรารีFive-Star-Me

กำหนดเวลาเปิดตัวและวันติดตั้งในonCreateวิธีการของ MainActivity เพื่อกำหนดค่าไลบรารี

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

จากนั้นวางเมธอดด้านล่างเรียกใช้เมธอด onCreate / onViewCreated ของ activity / fragment เพื่อแสดงพรอมต์ทุกครั้งที่ตรงตามเงื่อนไข

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

ป้อนคำอธิบายภาพที่นี่

คำแนะนำในการติดตั้ง:

คุณสามารถดาวน์โหลดจาก jitpack

ขั้นตอนที่ 1: เพิ่มสิ่งนี้ในโปรเจ็กต์ (root) build.gradle

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

ขั้นตอนที่ 2: เพิ่มการอ้างอิงต่อไปนี้ในระดับโมดูล (แอป) build.gradle ของคุณ

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


ฉันทำตามคำอธิบายของคุณและคำที่ผู้เขียนไลบรารีให้ไว้ (ใน github) แต่ฉันไม่ได้รับข้อความ InAppRating ฉันเริ่มต้น Lib ในเมธอด MainActivity # onCreate จากนั้นเรียกมันว่า fragement มีปัญหาเกี่ยวกับชิ้นส่วนหรือไม่
Souf ROCHDI

1
คุณจะต้องอัปโหลด apk ไปยังการแชร์แอปภายในเป็นอย่างน้อยหรือแทร็กการทดสอบภายในจึงจะเห็นข้อความแจ้งนี้ developer.android.com/guide/playcore/in-app-review/test
Michael Hathi

ขอบคุณ @Michael มันใช้งานได้ ฉันไม่ได้ใส่ใจกับส่วนการทดสอบที่อธิบายไว้ในเอกสารอย่างเป็นทางการ
Souf ROCHDI

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

ไลบรารีทั้งหมดไม่ใช่วิธีแก้ปัญหาในโพสต์นี้ ไลบรารีนี้เพียงแค่เปิดหน้าเว็บไปยังแอปบน Google Play แต่ไลบรารีหลักของ Play นี้มีอินเทอร์เฟซที่สอดคล้องกันมากขึ้น

ดังนั้นฉันคิดว่านี่เป็นปัญหา ProGuard: มันทำให้บางชั้นเรียนสับสนพอ https://stackoverflow.com/a/63650212/10117882

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.