app_review 3.0.0 copy "app_review: ^3.0.0" to clipboard
app_review: ^3.0.0 copied to clipboard

Request and Write Reviews and Open Store Listing for Android and iOS in Flutter.

example/lib/main.dart

import 'dart:io';

import 'package:app_review/app_review.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blueAccent,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.blueAccent,
        brightness: Brightness.dark,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    super.initState();
    AppReview.getAppId().then((onValue) {
      setState(() {
        appID = onValue ?? '';
      });
      log(onValue);
    });
  }

  String appID = "";
  final List<String> _logs = [];
  bool _useAndroidTestMode = true;

  final testAppId = () {
    if (Platform.isAndroid) return 'com.google.android.googlequicksearchbox';
    if (Platform.isIOS || Platform.isMacOS) return '640199958';
    return null;
  }();

  void log(String? message) {
    if (message != null) {
      debugPrint(message);
      setState(() {
        _logs.insert(0, message);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar.large(
            title: const Text('App Review'),
            centerTitle: true,
          ),
          SliverToBoxAdapter(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  if (Platform.isAndroid)
                    SwitchListTile(
                      title: const Text('Use Android Test Mode'),
                      subtitle: const Text('Uses FakeReviewManager'),
                      value: _useAndroidTestMode,
                      onChanged: (value) {
                        setState(() {
                          _useAndroidTestMode = value;
                        });
                      },
                    ),
                  _buildInfoCard(
                    context,
                    title: 'App ID',
                    subtitle: appID.isEmpty ? 'Loading...' : appID,
                    icon: Icons.info_outline,
                    onTap: () {
                      AppReview.getAppId().then(log);
                    },
                  ),
                  const SizedBox(height: 16),
                  Text(
                    'Actions',
                    style: Theme.of(context).textTheme.titleMedium?.copyWith(
                          color: Theme.of(context).colorScheme.primary,
                          fontWeight: FontWeight.bold,
                        ),
                  ),
                  const SizedBox(height: 8),
                  _buildActionCard(
                    context,
                    title: 'View Store Page',
                    subtitle: 'Open the app store listing for this app',
                    icon: Icons.storefront,
                    color: Colors.orange,
                    onTap: () async {
                      try {
                        await AppReview.storeListing(
                          appStoreId: (Platform.isIOS || Platform.isMacOS)
                              ? testAppId
                              : null,
                          playStoreId: Platform.isAndroid ? testAppId : null,
                        );
                        log('Opened Store Listing');
                      } catch (e) {
                        log('Failed to open store listing: $e');
                      }
                    },
                  ),
                  const SizedBox(height: 12),
                  _buildActionCard(
                    context,
                    title: 'Request Review',
                    subtitle: 'Ask the user to rate the app',
                    icon: Icons.star_rate_rounded,
                    color: Colors.amber,
                    onTap: () async {
                      try {
                        await AppReview.requestReview(
                          useAndroidTestMode: _useAndroidTestMode,
                        );
                        log('Requested Review');
                      } catch (e) {
                        log('Request Review failed: $e');
                      }
                    },
                  ),
                  const SizedBox(height: 12),
                  _buildActionCard(
                    context,
                    title: 'Write a New Review',
                    subtitle: 'Navigate to the review page',
                    icon: Icons.rate_review_outlined,
                    color: Colors.green,
                    onTap: () async {
                      try {
                        await AppReview.writeReview(
                          appStoreId: (Platform.isIOS || Platform.isMacOS)
                              ? testAppId
                              : null,
                          playStoreId: Platform.isAndroid ? testAppId : null,
                          useAndroidTestMode: _useAndroidTestMode,
                        );
                        log('Opened Write Review');
                      } catch (e) {
                        log('Write Review failed: $e');
                      }
                    },
                  ),
                  const SizedBox(height: 24),
                  Text(
                    'Log Output',
                    style: Theme.of(context).textTheme.titleMedium?.copyWith(
                          color: Theme.of(context).colorScheme.primary,
                          fontWeight: FontWeight.bold,
                        ),
                  ),
                  const SizedBox(height: 8),
                  Container(
                    height: 200,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(12),
                      border: Border.all(
                        color: Theme.of(context).colorScheme.outlineVariant,
                      ),
                    ),
                    child: _logs.isEmpty
                        ? Center(
                            child: Text(
                              'No logs yet',
                              style: TextStyle(
                                color: Theme.of(context).colorScheme.onSurface,
                              ),
                            ),
                          )
                        : ListView.separated(
                            padding: const EdgeInsets.all(8),
                            itemCount: _logs.length,
                            separatorBuilder: (context, index) =>
                                const Divider(height: 1),
                            itemBuilder: (context, index) {
                              return ListTile(
                                dense: true,
                                title: Text(
                                  _logs[index],
                                  style: TextStyle(
                                    fontFamily: 'monospace',
                                    fontSize: 12,
                                    color:
                                        Theme.of(context).colorScheme.onSurface,
                                  ),
                                ),
                                leading: const Icon(Icons.code, size: 16),
                              );
                            },
                          ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildInfoCard(
    BuildContext context, {
    required String title,
    required String subtitle,
    required IconData icon,
    required VoidCallback onTap,
  }) {
    return Card(
      elevation: 0,
      color: Theme.of(context).colorScheme.secondaryContainer,
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Row(
            children: [
              Icon(
                icon,
                color: Theme.of(context).colorScheme.onSecondaryContainer,
                size: 28,
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: Theme.of(context).textTheme.labelLarge?.copyWith(
                            color: Theme.of(context)
                                .colorScheme
                                .onSecondaryContainer
                                .withValues(alpha: 0.8),
                          ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      subtitle,
                      style: Theme.of(context).textTheme.titleMedium?.copyWith(
                            color: Theme.of(context)
                                .colorScheme
                                .onSecondaryContainer,
                            fontWeight: FontWeight.bold,
                          ),
                    ),
                  ],
                ),
              ),
              Icon(
                Icons.copy,
                size: 18,
                color: Theme.of(context)
                    .colorScheme
                    .onSecondaryContainer
                    .withValues(alpha: 0.5),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildActionCard(
    BuildContext context, {
    required String title,
    required String subtitle,
    required IconData icon,
    required Color color,
    required VoidCallback onTap,
  }) {
    return Card(
      elevation: 2,
      shadowColor: Colors.transparent,
      shape: RoundedRectangleBorder(
        side: BorderSide(
          color: Theme.of(context).colorScheme.outlineVariant,
        ),
        borderRadius: BorderRadius.circular(12),
      ),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Row(
            children: [
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: color.withValues(alpha: 0.1),
                  shape: BoxShape.circle,
                ),
                child: Icon(
                  icon,
                  color: color,
                  size: 24,
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: Theme.of(context).textTheme.titleMedium?.copyWith(
                            fontWeight: FontWeight.bold,
                            color: Theme.of(context).colorScheme.outline,
                          ),
                    ),
                    const SizedBox(height: 2),
                    Text(
                      subtitle,
                      style: Theme.of(context).textTheme.bodySmall?.copyWith(
                            color: Theme.of(context).colorScheme.outline,
                          ),
                    ),
                  ],
                ),
              ),
              Icon(
                Icons.chevron_right,
                color: Theme.of(context).colorScheme.outline,
              ),
            ],
          ),
        ),
      ),
    );
  }
}
319
likes
145
points
416
downloads

Documentation

API reference

Publisher

verified publisherrodydavis.com

Weekly Downloads

Request and Write Reviews and Open Store Listing for Android and iOS in Flutter.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on app_review

Packages that implement app_review