Building Progressive Web Apps with Flutter

Flutter, Google’s UI toolkit, enables developers to build natively compiled applications for mobile, web, and desktop from a single codebase. When combined with Progressive Web App (PWA) technologies, Flutter can deliver an exceptional user experience with features like offline support, installability, and push notifications.

What is a Progressive Web App (PWA)?

A Progressive Web App (PWA) is a web application that uses modern web capabilities to deliver an app-like experience to users. PWAs are designed to be reliable, fast, and engaging, making them an attractive option for businesses looking to provide a seamless user experience across different devices.

Why Build PWAs with Flutter?

  • Single Codebase: Flutter’s write-once-run-anywhere capability makes it ideal for creating PWAs along with mobile and desktop apps.
  • Performance: Flutter’s rendering engine ensures fast and smooth performance, crucial for a good PWA experience.
  • Rich UI: Flutter’s widget library allows for the creation of complex and beautiful UIs.
  • Offline Capabilities: Service workers can be easily integrated to provide offline support, making PWAs reliable even without an internet connection.

How to Build a PWA with Flutter

To create a PWA with Flutter, follow these steps:

Step 1: Set Up Your Flutter Project

If you haven’t already, create a new Flutter project:

flutter create my_pwa_app

Make sure Flutter’s web support is enabled:

flutter config --enable-web

Step 2: Build Your Flutter Web App

Develop your Flutter application with a focus on web compatibility. Use responsive layouts to ensure your app looks good on different screen sizes.


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My PWA App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter PWA Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Step 3: Add PWA Functionality

To enable PWA features, you need to add a service worker and a manifest file.

Create a Manifest File (manifest.json)

This file provides metadata about your PWA, like its name, icons, and display properties.


{
  "name": "My Flutter PWA",
  "short_name": "Flutter PWA",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#007BFF",
  "description": "A Flutter Progressive Web App Demo",
  "icons": [
    {
      "src": "icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

Place the manifest.json file in your web directory and make sure to generate icons in various sizes and place them in the web/icons directory.

Register the Manifest in index.html

Link the manifest.json file in your web/index.html:


<head>
    <meta charset="UTF-8">
    <meta content="IE=Edge" http-equiv="X-UA-Compatible">
    <meta name="description" content="A new Flutter project.">

    <!-- Favicon -->
    <link rel="icon" type="image/png" href="favicon.png"/>

    <!-- Manifest -->
    <link rel="manifest" href="manifest.json">

    <title>my_pwa_app</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
Create a Service Worker (service_worker.js)

A service worker enables offline functionality, push notifications, and background sync. Create a service_worker.js file in your web directory.


const cacheName = 'my-pwa-cache-v1';
const assets = [
  '/',
  'index.html',
  'main.dart.js',
  'flutter.js',
  'manifest.json',
  'icons/icon-192x192.png',
  'icons/icon-512x512.png',
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        cache.addAll(assets);
      })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        return response || fetch(event.request);
      })
  );
});

This service worker caches the essential assets for offline use. You can customize the caching strategy based on your specific requirements.

Register the Service Worker in index.html

Add the following script to the end of your web/index.html file:


<script>
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
      navigator.serviceWorker.register('/service_worker.js');
    });
  }
</script>

Step 4: Build and Deploy Your PWA

Build your Flutter web app:

flutter build web

Deploy the contents of the /build/web directory to a web server that supports HTTPS. Popular options include Firebase Hosting, Netlify, and GitHub Pages.

Step 5: Test Your PWA

After deploying your PWA, test it using Chrome DevTools to ensure it meets PWA criteria. Key tests include:

  • HTTPS: The site is served over HTTPS.
  • Service Worker: A service worker is registered and active.
  • Manifest: The manifest file is correctly configured.
  • Installable: The browser prompts to install the PWA.
  • Mobile-Friendly: The site is responsive and works well on mobile devices.

Enhancements and Advanced Features

Push Notifications

For push notifications, you’ll need to use a push notification service like Firebase Cloud Messaging (FCM). This involves setting up FCM, creating a server-side component to send notifications, and integrating the Flutter app to handle notifications.

Background Sync

Background sync allows you to defer actions until the user has a stable network connection. Use the BackgroundSync API in your service worker to handle background tasks.

Conclusion

Building PWAs with Flutter is a powerful way to create high-performance, installable web applications from a single codebase. By adding a manifest file and service worker, you can enhance your Flutter web apps with features like offline support and push notifications, providing users with a superior, app-like experience. Leveraging Flutter’s capabilities, developers can deliver robust and engaging PWAs that work seamlessly across platforms.