britannio / in_app_review

A Flutter plugin for showing the In-App Review/System Rating pop up on Android, IOS, and MacOS. It makes it easy for users to rate your app.
310 stars 79 forks source link

`requestReview` does nothing on Android #127

Open lukehutch opened 1 month ago

lukehutch commented 1 month ago

requestReview does nothing on Android. Here are the logs:

I/InAppReviewPlugin(22895): cacheReviewInfo: Requesting review flow
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : Initiate binding to the service.
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : ServiceConnectionImpl.onServiceConnected(ComponentInfo{com.android.vending/com.google.android.finsky.inappreviewservice.InAppReviewService})
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : linkToDeath
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : Unbind from service.
I/PlayCore(22895): UID: [10195]  PID: [22895] OnRequestInstallCallback : onGetLaunchReviewFlowInfo
I/InAppReviewPlugin(22895): onComplete: Successfully requested review flow
I/InAppReviewPlugin(22895): onMethodCall: requestReview
I/InAppReviewPlugin(22895): requestReview: called
I/InAppReviewPlugin(22895): noContextOrActivity: called
I/InAppReviewPlugin(22895): launchReviewFlow: called
I/InAppReviewPlugin(22895): noContextOrActivity: called

After these logs are printed to the console, requestReview returns from the await without throwing an exception.

Flutter 3.23.0-0.1.pre • channel beta • https://github.com/flutter/flutter.git Framework • revision 2feea7a407 (6 weeks ago) • 2024-06-06 10:19:10 +0700 Engine • revision bb10c54666 Tools • Dart 3.5.0 (build 3.5.0-180.3.beta) • DevTools 2.36.0 Android API 33

HenrikH96 commented 1 month ago

I have a similar Issue. It opened once, and i think this is Intended by the operating System. But it would be nice to get an Error/ Return Object to react to "requestReview" results. Or at least the isAvailable function shouldn't return true if the popup is already called and not available anymore.

It's a bad UX when nothing happens on my Button press.

Any suggestions ?

britannio commented 1 month ago

requestReview does nothing on Android. Here are the logs:

I/InAppReviewPlugin(22895): cacheReviewInfo: Requesting review flow
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : Initiate binding to the service.
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : ServiceConnectionImpl.onServiceConnected(ComponentInfo{com.android.vending/com.google.android.finsky.inappreviewservice.InAppReviewService})
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : linkToDeath
I/PlayCore(22895): UID: [10195]  PID: [22895] ReviewService : Unbind from service.
I/PlayCore(22895): UID: [10195]  PID: [22895] OnRequestInstallCallback : onGetLaunchReviewFlowInfo
I/InAppReviewPlugin(22895): onComplete: Successfully requested review flow
I/InAppReviewPlugin(22895): onMethodCall: requestReview
I/InAppReviewPlugin(22895): requestReview: called
I/InAppReviewPlugin(22895): noContextOrActivity: called
I/InAppReviewPlugin(22895): launchReviewFlow: called
I/InAppReviewPlugin(22895): noContextOrActivity: called

After these logs are printed to the console, requestReview returns from the await without throwing an exception.

Flutter 3.23.0-0.1.pre • channel beta • https://github.com/flutter/flutter.git Framework • revision 2feea7a407 (6 weeks ago) • 2024-06-06 10:19:10 +0700 Engine • revision bb10c54666 Tools • Dart 3.5.0 (build 3.5.0-180.3.beta) • DevTools 2.36.0 Android API 33

Hey, did you see the testing guidelines? https://pub.dev/packages/in_app_review#testing-read-carefully

lukehutch commented 1 month ago

Hey, did you see the testing guidelines? https://pub.dev/packages/in_app_review#testing-read-carefully

The docs appear to be incomplete. They basically imply that the submit button will be disabled if you don't have an app bundle uploaded to at least the "internal app sharing" track. However, that's not the behavior I am reporting: the dialog doesn't even pop up, and no error message is even reported to the console.

Yes, this might be caused by not having an app in production yet (I have several builds uploaded for testing). However, whatever the cause, in_app_review should report an error to the console at a bare minimum, and ideally also show an error message in a dialog, rather than failing silently.

britannio commented 1 month ago
  @override
  Future<void> requestReview() async {
    if (kDebugMode && _platform.isAndroid) {
      print( 'in_app_review must be tested with a build downloaded from the Play Store.');
    }
    return _channel.invokeMethod('requestReview');
  }

Would this suffice? Showing a dialog is fine until I get an issue saying "why is this dialog being shown in production".

britannio commented 1 month ago

Actually, based on https://stackoverflow.com/questions/37539949/detect-if-an-app-is-installed-from-play-store it is possible to detect if the app was installed via the Play Store or via any store.

lukehutch commented 1 month ago

A console message is much better than nothing. Nothing should ever fail silently.

britannio commented 1 month ago

@lukehutch Do you get a log that looks like isAvailable: playStoreAndPlayServicesAvailable: <true/false> before the logs you posted?

lukehutch commented 1 month ago

I didn't notice that in the logs, but on this device Play Services should be available.

(If you need me to test this, it will be a couple of days before I will be able to get to it.)

rsillador commented 2 weeks ago

Any updates on this? I got the same issue.

image
lukehutch commented 1 week ago

In case it helps anyone else, this is what I resorted to doing:

  final startTime = Stopwatch()..start();
  if (await inAppReview.isAvailable()) {
    try {
      await inAppReview.requestReview();
    } catch (e, st) {
      logError(
        message: 'Failed to request app review',
        error: e,
        stacktrace: st,
      );
    }
  }
  final elapsedMilliseconds = startTime.elapsedMilliseconds;
  if (elapsedMilliseconds > 300) {
    // If the above method did not return immediately, assume it
    // succeeded in opening the rating modal, and return
    return;
  }

  // Otherwise if the above method failed, try opening the store listing by URL
  try {
    // Use `url_launcher` rather than `openStoreListing`
    await launchUrl(Uri.parse(Platform.isAndroid
        ? 'https://play.google.com/store/apps/details?id=$androidPackageName'
        : 'https://apps.apple.com/us/app/click-social/id$appStoreId'));
  } catch (e, st) {
    logError(
      message: 'Failed to open app store listing',
      error: e,
      stacktrace: st,
    );
  }

I use launchUrl rather than openStoreListing because I had a report by one user that if openStoreListing is called, they get a version of the Play Store listing that does not allow them to rate the app:

https://github.com/britannio/in_app_review/issues/131

nicolaikol commented 2 days ago

final elapsedMilliseconds = startTime.elapsedMilliseconds; if (elapsedMilliseconds > 300) { // If the above method did not return immediately, assume it // succeeded in opening the rating modal, and return return; }

I just tried your code on iOS simulator, and on iOS physical, and it returns immediately with 0 elapsed time. Does await even do anything on requestReview() ?

Edit: okay sometimes it's like 12 - 16 milliseconds, nowhere near the 300 mark

lukehutch commented 2 days ago

@nicolaikol I didn't test it on iOS, but I did read the source before and it looks like the method is supposed to block until it has a result from user interaction. I could be reading the code wrong though, or possibly the code is returning as soon as the dialogue is open, before the user has tapped on anything.

I picked the 300ms based only on human reaction time, not based on the actual method return time. My assumption was that if there wasn't enough time to pop up a dialogue and have the user tap on a button, then either the dialog must not have opened, or it must have opened and immediately closed without user intervention.

There could be a flaw in the logic here, I am open to other suggestions!