pwa_installer 0.2.0 copy "pwa_installer: ^0.2.0" to clipboard
pwa_installer: ^0.2.0 copied to clipboard

Platformweb

A Flutter package for PWA installation. Includes install guides, in-app browser detection, and custom install prompt interception.

example/lib/main.dart

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

void main() {
  // Initialize PWA Installer with enable flags
  PwaInstaller.init(
    enableBrowserRedirect: true,
    enableDesktopInstallGuide: true,
    enableMobileInstallGuide: true,
  );
  runApp(const MyApp());
}

/// Example using the unified PwaInstaller approach.
///
/// This automatically handles:
/// - In-app browser detection → InAppBrowserGuide
/// - Desktop browser → DesktopInstallGuide (QR code)
/// - Mobile browser → MobileInstallGuide
/// - Installed PWA → Your app
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PWA Install Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      // Wrap your home with PwaInstaller for automatic handling
      home: PwaInstaller(
        logo: const Icon(Icons.flutter_dash, size: 80, color: Colors.white),
        appName: 'PWA Demo',
        theme: PwaInstallerTheme.defaultTheme,
        child: const MyHomePage(),
      ),
    );
  }
}

/// Routes based on browser/platform detection
class AppRouter extends StatelessWidget {
  const AppRouter({super.key});

  @override
  Widget build(BuildContext context) {
    // 1. If running in an in-app browser, show force browser screen
    if (PwaInstaller.isInAppBrowser()) {
      return InAppBrowserGuide(
        logo:
            const Icon(Icons.flutter_dash, size: 80, color: Color(0xFF6750A4)),
        theme: PwaInstallerTheme.defaultTheme,
        onDismiss: () => Navigator.pushReplacement(
          context,
          MaterialPageRoute(builder: (_) => const MyHomePage()),
        ),
      );
    }

    // 2. If on desktop, show desktop install guide with QR code
    if (PwaInstaller.shouldShowDesktopInstallGuide()) {
      return DesktopInstallGuide(
        logo: const Icon(Icons.flutter_dash, size: 80, color: Colors.white),
        appName: 'PWA Demo',
        theme: PwaInstallerTheme.defaultTheme,
        onDismiss: () => Navigator.pushReplacement(
          context,
          MaterialPageRoute(builder: (_) => const MyHomePage()),
        ),
      );
    }

    // 3. If on mobile browser and not installed as PWA, show install guide
    if (PwaInstaller.shouldShowInstallGuide()) {
      return MobileInstallGuide(
        logo: const Icon(Icons.flutter_dash, size: 80, color: Colors.white),
        theme: PwaInstallerTheme.defaultTheme,
        labels: const PwaInstallerLabels(),
        onDismiss: () => Navigator.pushReplacement(
          context,
          MaterialPageRoute(builder: (_) => const MyHomePage()),
        ),
      );
    }

    // 4. Normal app experience (installed PWA)
    return const MyHomePage();
  }
}

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

  @override
  Widget build(BuildContext context) {
    final detection = PwaInstaller.detectInAppBrowser();
    final isInstalled = PwaInstaller.isInstalledPwa();

    return Scaffold(
      appBar: AppBar(
        title: const Text('PWA Install Demo'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _buildStatusCard(context, detection, isInstalled),
            const SizedBox(height: 16),
            _buildInstallCard(context),
            const SizedBox(height: 16),
            _buildDemoCard(context),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusCard(
      BuildContext context, InAppBrowserDetection detection, bool isInstalled) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Platform Status',
                style: Theme.of(context)
                    .textTheme
                    .titleMedium
                    ?.copyWith(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            _buildStatusRow(
                'In-App Browser',
                detection.isInApp ? detection.browserName : 'No',
                detection.isInApp ? Colors.orange : Colors.green),
            _buildStatusRow('Installed as PWA', isInstalled ? 'Yes' : 'No',
                isInstalled ? Colors.green : Colors.grey),
            _buildStatusRow('iOS Safari',
                PlatformDetection.isIosSafari() ? 'Yes' : 'No', null),
            _buildStatusRow('Safari 26+ (Liquid Glass)',
                PlatformDetection.isSafari26OrNewer() ? 'Yes' : 'No', null),
            _buildStatusRow('Android Chrome',
                PlatformDetection.isAndroidChrome() ? 'Yes' : 'No', null),
          ],
        ),
      ),
    );
  }

  Widget _buildInstallCard(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Install App',
                style: Theme.of(context)
                    .textTheme
                    .titleMedium
                    ?.copyWith(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            ValueListenableBuilder<bool>(
              valueListenable: PwaInstaller.installPromptEnabled,
              builder: (context, enabled, _) {
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    FilledButton.icon(
                      onPressed:
                          enabled ? () => PwaInstaller.promptInstall() : null,
                      icon: const Icon(Icons.download),
                      label: Text(enabled
                          ? 'Install App'
                          : 'Install Prompt Not Available'),
                    ),
                    const SizedBox(height: 8),
                    Text(
                      enabled
                          ? 'Tap to install this app on your device.'
                          : 'The install prompt is only available on supported browsers (e.g., Android Chrome). On iOS, use "Share → Add to Home Screen".',
                      style: Theme.of(context)
                          .textTheme
                          .bodySmall
                          ?.copyWith(color: Colors.grey),
                    ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildDemoCard(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Demo Screens',
                style: Theme.of(context)
                    .textTheme
                    .titleMedium
                    ?.copyWith(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            FilledButton.tonal(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => MobileInstallGuide(
                    logo: const Icon(Icons.flutter_dash,
                        size: 80, color: Colors.white),
                    onDismiss: () => Navigator.pop(context),
                    forcePlatform: ForcePlatform.iosSafari26,
                  ),
                ),
              ),
              child: const Text('Preview iOS Safari 26+ (Liquid Glass)'),
            ),
            const SizedBox(height: 8),
            FilledButton.tonal(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => MobileInstallGuide(
                    logo: const Icon(Icons.flutter_dash,
                        size: 80, color: Colors.white),
                    onDismiss: () => Navigator.pop(context),
                    forcePlatform: ForcePlatform.iosSafariLegacy,
                  ),
                ),
              ),
              child: const Text('Preview iOS Safari Legacy'),
            ),
            const SizedBox(height: 8),
            FilledButton.tonal(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => MobileInstallGuide(
                    logo: const Icon(Icons.flutter_dash,
                        size: 80, color: Colors.white),
                    onDismiss: () => Navigator.pop(context),
                    forcePlatform: ForcePlatform.android,
                  ),
                ),
              ),
              child: const Text('Preview Install Guide Android'),
            ),
            const SizedBox(height: 8),
            FilledButton.tonal(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => DesktopInstallGuide(
                    logo: const Icon(Icons.flutter_dash,
                        size: 80, color: Colors.white),
                    appName: 'PWA Demo',
                    onDismiss: () => Navigator.pop(context),
                  ),
                ),
              ),
              child: const Text('Preview Desktop Install Screen'),
            ),
            const SizedBox(height: 8),
            FilledButton.tonal(
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => InAppBrowserGuide(
                    logo: const Icon(Icons.flutter_dash,
                        size: 80, color: Color(0xFF6750A4)),
                    onDismiss: () => Navigator.pop(context),
                  ),
                ),
              ),
              child: const Text('Preview Force Browser Screen'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusRow(String label, String value, Color? statusColor) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label),
          Row(
            children: [
              if (statusColor != null) ...[
                Container(
                    width: 8,
                    height: 8,
                    decoration: BoxDecoration(
                        color: statusColor, shape: BoxShape.circle)),
                const SizedBox(width: 8),
              ],
              Text(value, style: const TextStyle(fontWeight: FontWeight.w500)),
            ],
          ),
        ],
      ),
    );
  }
}
1
likes
160
points
207
downloads
screenshot

Publisher

verified publishersolodeveloping.com

Weekly Downloads

A Flutter package for PWA installation. Includes install guides, in-app browser detection, and custom install prompt interception.

Repository (GitHub)
View/report issues

Topics

#pwa #web #install #browser-detection

Documentation

API reference

Funding

Consider supporting this project:

buymeacoffee.com

License

MIT (license)

Dependencies

cupertino_icons, flutter, qr_flutter, url_launcher, web

More

Packages that depend on pwa_installer