{"id":21730064,"url":"https://github.com/nventive/reviewservice-dart","last_synced_at":"2026-05-09T13:04:24.798Z","repository":{"id":239785782,"uuid":"800526637","full_name":"nventive/ReviewService-Dart","owner":"nventive","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-12T14:53:17.000Z","size":45,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-25T21:22:35.405Z","etag":null,"topics":["dart","flutter"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nventive.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-05-14T13:58:14.000Z","updated_at":"2026-01-12T14:53:20.000Z","dependencies_parsed_at":"2024-09-16T19:01:07.280Z","dependency_job_id":"73841ec0-75a3-4fe6-8409-efb43a25d403","html_url":"https://github.com/nventive/ReviewService-Dart","commit_stats":null,"previous_names":["nventive/reviewservice-dart"],"tags_count":0,"template":false,"template_full_name":"nventive/Template","purl":"pkg:github/nventive/ReviewService-Dart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nventive%2FReviewService-Dart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nventive%2FReviewService-Dart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nventive%2FReviewService-Dart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nventive%2FReviewService-Dart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nventive","download_url":"https://codeload.github.com/nventive/ReviewService-Dart/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nventive%2FReviewService-Dart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32820174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter"],"created_at":"2024-11-26T04:11:35.758Z","updated_at":"2026-05-09T13:04:24.780Z","avatar_url":"https://github.com/nventive.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Review Service\n\nThis repository introduces abstractions around native review capabilities to ease code sharing and testability.\nIt also introduces business logic to quickly configure conditions and state tracking to prompt for reviews at the right moment.\n\nTo be replaced by the actual pub.dev tags once merged.\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) ![Version]() ![Downloads]()\n\n## Before Getting Started\n\nBefore getting started, please read the [Android](https://developer.android.com/guide/playcore/in-app-review) and [iOS](https://developer.apple.com/design/human-interface-guidelines/ratings-and-reviews) application review documentation.\n\n## Getting Started\n\n1. Add the `review_service` package to your project.\n\n2. Create an instance of `ReviewService`. We'll cover dependency injection in details later on in this documentation.\n   ```dart\n   var reviewConditionsBuilder = ReviewConditionsBuilderImplementation\n      .empty()\n      .minimumPrimaryActionsCompleted(1);\n\n   var reviewPrompter = LoggingReviewPrompter();\n   var reviewSettingsSource = MemoryReviewSettingsSource\u003cReviewSettings\u003e(() =\u003e const ReviewSettings());\n\n   var reviewService = ReviewService\u003cReviewSettings\u003e(\n      logger: Logger(),\n      reviewPrompter: reviewPrompter,\n      reviewSettingsSource: reviewSettingsSource,\n      reviewConditionsBuilder: reviewConditionsBuilder);\n\n   ```\n\n3. Use the service.\n   - Update the review settings based on application events.\n      ```dart\n      late ReviewService\u003cReviewSettings\u003e _reviewService;\n\n      Future\u003cvoid\u003e doPrimaryAction() async {\n         // Do Primary Action.\n\n         // Track this action.\n         await _reviewService.trackPrimaryActionCompleted();\n      }\n\n      ```\n   - Use the service to request review.\n      ```dart\n      late ReviewService\u003cReviewSettings\u003e _reviewService;\n\n      Future\u003cvoid\u003e onCompletedImportantFlow() async {\n      // Do Meaningful Task.\n\n      // Check if all conditions are satisfied and prompt for review if they are.\n      await _reviewService.tryRequestReview();\n      }\n      ```\n\n## Next Steps\n\n### Persisting Review Settings\n\n`MemoryReviewSettingsSource` is great for automated testing but should not be the implementation of choice for real use-cases. Instead, you should create your own implementation that persists data on the device (so that review settings don't reset when you kill the app).\n\n```dart\n/// Storage implementation of \u003csee cref=\"ReviewSettingsSource{TReviewSettings}\"/\u003e.\nsealed class StorageReviewSettingsSource\u003cReviewSettings\u003e extends ReviewSettings\n    implements ReviewSettingsSource\u003cReviewSettings\u003e {\n  @override\n  Future\u003cReviewSettings\u003e read() {\n    // TODO: Return stored review settings.\n    return Future.value(ReviewSettings());\n  }\n\n  @override\n  Future\u003cvoid\u003e write(ReviewSettings reviewSettings) {\n    // TODO: Update stored review settings.\n    return Future.value();\n  }\n}\n```\n\n### Using Dependency Injection\n\nHere is a simple code that does dependency injection using `get_it`.\n\n```dart\n   GetIt getIt = GetIt.instance;\n\n   // Register the ReviewPrompter implementation with GetIt\n   getIt.registerSingleton\u003cReviewPrompter\u003e(ReviewPrompter());\n```\n\n## Features\n\nNow that everything is setup, Let's see what else we can do!\n\n### Track Application Events\n\nTo track the provided review settings you can use the following `ReviewService` extensions.\n\u003e 💡 The review request count and the last review request are automatically tracked by the service.\n\n- [TrackApplicationLaunched](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_service.extensions.dart#L8) : Tracks that the application was launched (Also tracks if it's the first launch).\n- [TrackPrimaryActionCompleted](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_service.extensions.dart#L22) : Tracks that a primary action was completed.\n- [TrackSecondaryActionCompleted](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_service.extensions.dart#L29) : Tracks that a secondary action was completed.\n\n#### Built-in Tracking Data\n- [PrimaryActionCompletedCount](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L4) : The number of primary actions completed.\n- [SecondaryActionCompletedCount](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L7) : The number of secondary actions completed.\n- [ApplicationLaunchCount](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L10) : The number of times the application has been launched.\n- [FirstApplicationLaunch](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L13) : When the application first started.\n- [RequestCount](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L16) : The number of review requested.\n- [LastRequest](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_settings.dart#L19) : When the last review was requested.\n\n### Configure Conditions\n\nIf you want to use our default review conditions, you can use `ReviewConditionsBuilder.defaultBuilder()` and pass it to the `ReviewService` constructor, or register it as a transient dependency when using dependency injection. Please note that our review conditions are also generic, so they can be used with custom review settings too.\n\nThe `ReviewConditionsBuilder.Default()` extension method uses the following conditions.\n- **3** application launches required.\n- **2** completed primary actions.\n- **5** days since the first application launch.\n- **15** days since the last review request.\n\n#### Built-in Conditions\n- [MinimumPrimaryActionsCompleted](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L12) : Make sure that it prompts for review only if the number of completed primary actions meets the minimum.\n- [MinimumSecondaryActionsCompleted](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L20) : Make sure that it prompts for review only if the number of completed secondary actions meets the minimum.\n- [MinimumApplicationLaunchCount](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L28) : Make sure that it prompts for review only if the number of times the application has been launched meets the required minimum.\n- [MinimumElapsedTimeSinceApplicationFirstLaunch](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L36) : Make sure that it prompts for review only if the elapsed time since the first application launch meets the required minimum.\n- [MinimumElapsedTimeSinceLastReviewRequest](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L45) : Make sure that it prompts for review only if the elapsed time since the last review request meets the required minimum.\n- [Custom](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L54) : Custom condition made with a synchronous lambda function.\n- [CustomAsync](https://github.com/nventive/ReviewService-Dart/blob/56647f03e9625c534e5731a2bc3bd067088652e1/lib/src/review_service/review_conditions_builder.extensions.dart#L60) : Custom asynchronous condition made with an asynchronous lambda function.\n\n### Add Custom Conditions\n\nTo create custom review conditions, you have to use `ReviewConditionsBuilder.custom` and `ReviewConditionsBuilder.customAsync` and provide them with a function directly instead of a condition. Also you can create extensions for `ReviewConditionsBuilder` and add a new condition to the builder. To create a review condition, you can use both `SynchronousReviewCondition` and `AsynchronousReviewCondition` you need to provide them with a function.\n\n```dart\n/// Extensions for ReviewConditionsBuilder\u003cTReviewSettings\u003e.\nextension ReviewConditionsBuilderExtensions\n    on ReviewConditionsBuilder\u003cReviewSettingsCustom\u003e {\n  /// The application onboarding must be completed.\n  ReviewConditionsBuilder applicationOnboardingCompleted(\n      ReviewConditionsBuilder builder) {\n    builder.conditions.add(SynchronousReviewCondition\u003cReviewSettingsCustom\u003e((reviewSettings, currentDateTime) =\u003e reviewSettings.hasCompletedOnboarding == true));\n    return builder;\n  }\n}\n```\n\nHere is a simple code that uses the builder extensions for review conditions.\n\n ```dart\n   var reviewConditionsBuilder = ReviewConditionsBuilder.empty()\n      .minimumPrimaryActionsCompleted(1)\n      .minimumSecondaryActionsCompleted(1)\n      .minimumApplicationLaunchCount(1)\n      .minimumElapsedTimeSinceApplicationFirstLaunch(Duration(days: 1))\n      .custom((reviewSettings, currentDateTime) {\n   return reviewSettings.primaryActionCompletedCount +\n            reviewSettings.secondaryActionCompletedCount \u003e=\n         2;\n   });\n\n```\n\nIt's possible to customize the review conditions used by the service by using `ReviewConditionsBuilder` and passing it to the `ReviewService` constructor or by injecting it as a transient when using dependency injection.\n\n```dart\nvar reviewConditionsBuilder =\n    ReviewConditionsBuilder.empty\u003cReviewSettingsCustom\u003e()\n        .minimumPrimaryActionsCompleted(3)\n        .minimumApplicationLaunchCount(3)\n        .minimumElapsedTimeSinceApplicationFirstLaunch(Duration(days: 5))\n        .custom((reviewSettings, currentDateTime) {\n  return reviewSettings.primaryActionCompletedCount +\n          reviewSettings.secondaryActionCompletedCount \u003e=\n      2;\n});\n\n```\n\n### Add Custom Tracking Data\n\nFirst let's declare a new `ReviewSettings` named `CustomReviewSettings` with a `favoriteJokesCount` to track how many jokes were favorited in an hypothetical dad jokes application\n\n```dart \n  class CustomReviewSettings extends ReviewSettings {\n    final int favoriteJokesCount;\n\n    const CustomReviewSettings({\n      this.favoriteJokesCount = 0,\n      super.primaryActionCompletedCount = 0,\n      super.secondaryActionCompletedCount = 0,\n      super.applicationLaunchCount = 0,\n      super.firstApplicationLaunch,\n      super.requestCount = 0,\n      super.lastRequest,\n    });\n\n    @override\n    CustomReviewSettings copyWith({\n      int? primaryActionCompletedCount,\n      int? secondaryActionCompletedCount,\n      int? applicationLaunchCount,\n      DateTime? firstApplicationLaunch,\n      int? requestCount,\n      DateTime? lastRequest,\n    }) {\n      return CustomReviewSettings(\n        primaryActionCompletedCount:\n            primaryActionCompletedCount ?? this.primaryActionCompletedCount,\n        secondaryActionCompletedCount:\n            secondaryActionCompletedCount ?? this.secondaryActionCompletedCount,\n        applicationLaunchCount:\n            applicationLaunchCount ?? this.applicationLaunchCount,\n        firstApplicationLaunch:\n            firstApplicationLaunch ?? this.firstApplicationLaunch,\n        requestCount: requestCount ?? this.requestCount,\n        lastRequest: lastRequest ?? this.lastRequest,\n        favoriteJokesCount: favoriteJokesCount,\n      );\n    }\n\n    CustomReviewSettings copyWithFavorite(int favoriteCount) {\n      return CustomReviewSettings(\n        primaryActionCompletedCount: super.primaryActionCompletedCount,\n        secondaryActionCompletedCount: super.secondaryActionCompletedCount,\n        applicationLaunchCount: super.applicationLaunchCount,\n        firstApplicationLaunch: super.firstApplicationLaunch,\n        requestCount: super.requestCount,\n        lastRequest: super.lastRequest,\n        favoriteJokesCount: favoriteCount,\n      );\n    }\n  }\n```\n\n\u003e ⚠ Notes : \n\u003e 1. It's important you define a `copyWith` that overrides the one from the `ReviewSettings` class while returning the newly added property. This ensures that the calls made to the `copyWith` method of `ReviewSettings` will be overriden by your implementation\n\u003e 2. You need to define a `copyWith` method that returns the superclass `ReviewSettings` value along with your new property passed as a parameter. This method will be used when you will track your review settings further down the line. \n\nOnce you've defined your new custom review settings, it is recommended to add an extension to the `ReviewConditionsBuilder` for uniformity :\n\n```dart\n  extension CustomReviewConditionsBuilderExtensions\n      on ReviewConditionsBuilder\u003cCustomReviewSettings\u003e {\n    ReviewConditionsBuilder\u003cCustomReviewSettings\u003e minimumJokesFavorited(\n      int minimumJokesFavorited,\n    ) {\n      conditions.add(\n        SynchronousReviewCondition\u003cCustomReviewSettings\u003e(\n          (reviewSettings, currentDateTime) =\u003e\n              reviewSettings.favoriteJokesCount \u003e= minimumJokesFavorited,\n        ),\n      );\n      return this;\n    }\n  }\n```\n\n\u003e ⚠ Notes :\n\u003e You need to specify that the `ReviewConditionsBuilder` takes your new  `CustomReviewSettings` and not the default `ReviewSettings` since you want to use your newly added property. \n\nThen you need to register your service with the extended `ReviewConditionsBuilder` and the new review settings like this :\n```dart\n  var logger = Logger();\n  var reviewConditionsBuilder =\n      ReviewConditionsBuilderImplementation\u003cCustomReviewSettings\u003e()\n          .minimumJokesFavorited(3);\n\n  var reviewSettingsSource =\n    GetIt.I.registerSingleton\u003cReviewSettingsSource\u003cCustomReviewSettings\u003e\u003e(\n      MemoryReviewSettingsSource\u003cCustomReviewSettings\u003e(\n        () =\u003e const CustomReviewSettings(),\n      ),\n    );\n\n  GetIt.I.registerSingleton(\n    ReviewService\u003cCustomReviewSettings\u003e(\n      logger: logger,\n      reviewPrompter: ReviewPrompter(logger: logger),\n      reviewSettingsSource: reviewSettingsSource,\n      reviewConditionsBuilder: reviewConditionsBuilder,\n    ),\n  );\n```\n\n\u003e ⚠ Notes :\n\u003e 1. You need to specify again that you want the conditions builder the settings source and the service to use your `CustomReviewSettings` and not the generic.  \n\u003e 2. We recommend that you define your own interface that wraps `ReviewService\u003cCustomReviewSettings\u003e` to make the usage code leaner and ease any potential refactorings.\n\n  ```dart\n    /// This interface wraps ReviewService\u003cCustomReviewSettings\u003e so that you don't have to repeat the generic parameter everywhere that you would use the review service.\n    /// In other words, you should use this interface in the app instead of ReviewService\u003cCustomReviewSettings\u003e because it's leaner.\n    class CustomReviewService implements ReviewService\u003cCustomReviewSettings\u003e {\n      late ReviewService\u003cCustomReviewSettings\u003e _reviewService;\n\n      CustomReviewService(ReviewService\u003cCustomReviewSettings\u003e reviewService) {\n        _reviewService = reviewService;\n      }\n\n      @override\n      Future\u003cbool\u003e getAreConditionsSatisfied() async {\n        return await _reviewService.getAreConditionsSatisfied();\n      }\n\n      @override\n      Future\u003cvoid\u003e tryRequestReview() async {\n        await _reviewService.tryRequestReview();\n      }\n\n      @override\n      Future\u003cvoid\u003e updateReviewSettings(\n        CustomReviewSettings Function(CustomReviewSettings p1) updateFunction,\n      ) async {\n        await _reviewService.updateReviewSettings(updateFunction);\n      }\n    }\n  ```\n\nAfter creating your own implementation of the ReviewService you just need to register it like this :\n```dart\n  GetIt.I.registerSingleton(\n    CustomReviewService(\n      ReviewService\u003cCustomReviewSettings\u003e(\n        logger: logger,\n        reviewPrompter: ReviewPrompter(logger: logger),\n        reviewSettingsSource: reviewSettingsSource,\n        reviewConditionsBuilder: reviewConditionsBuilder,\n      ),\n    ),\n  );\n```\n\nAnd use it like that :\n```dart\n  await GetIt.I.get\u003cCustomReviewService\u003e().trackFavoriteJokesCount();\n```\n\nNow you're all set to track how many jokes are favorited in your app and prompt for a review once your review conditions are meant (3 favorite jokes in this case).\n\n## Testing\n\nThis is what you need to know before testing and debugging this service. Please note that this may change and you should always refer to the [Apple](https://developer.apple.com/documentation/storekit/skstorereviewcontroller/3566727-requestreview#4278434) and [Android](https://developer.android.com/guide/playcore/in-app-review/test) documentation for the most up-to-date information.\n\n### Android\n\n- You can't test this service while debugging the application, the prompt won't show up. To test it, you need to use the [internal application sharing](https://play.google.com/console/about/internalappsharing/) or the internal testing feature in Google Play Console. See [this](https://developer.android.com/guide/playcore/in-app-review/test) for more details.\n- You can't use a Google Suite account on Google Play to review an application because the prompt will not show up.\n\n### iOS\n\n- You can test on a real device or on a simulator.\n- You can test this service only while debugging the application (It won't show up on TestFlight).\n\n## Acknowledgements\n\nTake a look at [in_app_review](https://github.com/britannio/in_app_review) that we use to prompt for review.\n\n## Breaking Changes\n\nPlease consult [BREAKING_CHANGES.md](BREAKING_CHANGES.md) for more information about version\nhistory and compatibility.\n\n## License\n\nThis project is licensed under the Apache 2.0 license - see the\n[LICENSE](LICENSE) file for details.\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the process for\ncontributing to this project.\n\nBe mindful of our [Code of Conduct](CODE_OF_CONDUCT.md).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnventive%2Freviewservice-dart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnventive%2Freviewservice-dart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnventive%2Freviewservice-dart/lists"}