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,
              ),
            ],
          ),
        ),
      ),
    );
  }
}
318
likes
155
points
161
downloads

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

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on app_review

Packages that implement app_review