LATEST >>

Welcome Here And Thanks For Visiting. Like Us On Facebook...

EXEIdeas – Let's Your Mind Rock » Mobile / Mobile Development / PC / PC Development » How To Build A Windows Desktop App Using Flutter And Local Database?

How To Build A Windows Desktop App Using Flutter And Local Database?

How-To-Build-A-Windows-Desktop-App-Using-Flutter-And-Local-Database

How To Build A Windows Desktop App Using Flutter And Local Database

Flutter has revolutionized cross-platform development, and with its expanding desktop support, building Windows applications has never been easier. In this comprehensive guide, we’ll walk through creating a fully functional Windows desktop app with local database integration using Flutter’s powerful framework.

“Flutter’s single codebase approach reduces development time by 50% compared to traditional desktop application development methods.” – Google Developer Survey 2023

Why Choose Flutter For Windows Desktop Development?

Before diving into the technical implementation, let’s understand why Flutter stands out for Windows app development:

  • Single Codebase: Build for Windows, macOS, and Linux from one codebase
  • Native Performance: Compiles to native ARM and x64 code
  • Rich Widget Library: Beautiful, customizable UI components
  • Hot Reload: Instant preview of changes during development
  • Growing Ecosystem: Mature package ecosystem including database solutions

Prerequisites For Flutter Windows Development

To follow along with this tutorial, you’ll need:

  • Flutter SDK (version 3.0 or higher)
  • Visual Studio with C++ development tools
  • Windows 10/11 (64-bit)
  • Basic understanding of Dart programming

Setting Up Your Flutter Development Environment

Let’s begin by configuring your system for Flutter desktop development:

Step 1: Install Flutter SDK

Download the latest stable Flutter SDK from the official website and extract it to your preferred location. Add the Flutter bin directory to your system PATH to access Flutter commands globally.

Step 2: Enable Desktop Support

Run the following command in your terminal to enable Windows desktop development:

flutter config --enable-windows-desktop

Step 3: Install Visual Studio

Install Visual Studio 2022 with the following workloads:

  • “Desktop development with C++”
  • Windows 10/11 SDK
Recommended For You:
You Own The App? How To Legally Protect Your App?

Step 4: Verify Installation

Run the doctor command to check your setup:

flutter doctor

All checks should pass before proceeding. If you encounter issues, consult the Flutter documentation for troubleshooting.

Creating Your First Flutter Windows Project

With the environment ready, let’s create our application:

Initialize The Project

Create a new Flutter project with Windows support:

flutter create my_windows_app
cd my_windows_app

Project Structure Overview

Your project contains several important directories:

  • lib/: Main Dart code for your application
  • windows/: Windows-specific runner and configuration
  • pubspec.yaml: Project dependencies and metadata

Running The Default App

Launch the default Flutter counter app on Windows:

flutter run -d windows

This verifies your basic setup is working correctly before we add database functionality.

Integrating A Local Database In Your Flutter App

For data persistence in our Windows application, we’ll use SQLite through the sqflite package, which works excellently for desktop applications.

Adding Database Dependencies

Open pubspec.yaml and add these dependencies:

dependencies:
  sqflite: ^2.0.0+4
  path: ^1.8.0
  path_provider: ^2.0.11

Run flutter pub get to install the packages.

Creating The Database Helper Class

Create a new file database_helper.dart to manage database operations:

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final DatabaseHelper instance = DatabaseHelper._init();
  static Database? _database;

  DatabaseHelper._init();

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('app_database.db');
    return _database!;
  }

  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);
    
    return await openDatabase(path, version: 1, onCreate: _createDB);
  }

  Future _createDB(Database db, int version) async {
    await db.execute('''
      CREATE TABLE notes (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT NOT NULL,
        created_at TEXT NOT NULL
      )
    ''');
  }
}

Implementing CRUD Operations

Extend the DatabaseHelper class with basic CRUD operations:

// Add to DatabaseHelper class
Future<int> createNote(Map<String, dynamic> note) async {
  final db = await instance.database;
  return await db.insert('notes', note);
}

Future<List<Map<String, dynamic>>> readAllNotes() async {
  final db = await instance.database;
  return await db.query('notes', orderBy: 'created_at DESC');
}

Future<int> updateNote(Map<String, dynamic> note) async {
  final db = await instance.database;
  return await db.update(
    'notes',
    note,
    where: 'id = ?',
    whereArgs: [note['id']],
  );
}

Future<int> deleteNote(int id) async {
  final db = await instance.database;
  return await db.delete(
    'notes',
    where: 'id = ?',
    whereArgs: [id],
  );
}

Build-A-Windows-Desktop-App-Using-Flutter-And-Local-Database

Building The User Interface

With our database layer ready, let’s create a UI to interact with it.

Recommended For You:
Which Hybrid Framework Is The First Choice For Developing A Startup Mobile App?

Creating A Note Model

First, define a simple Note model in note_model.dart:

class Note {
  int? id;
  String title;
  String content;
  DateTime createdAt;

  Note({
    this.id,
    required this.title,
    required this.content,
    required this.createdAt,
  });

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'content': content,
      'created_at': createdAt.toIso8601String(),
    };
  }

  factory Note.fromMap(Map<String, dynamic> map) {
    return Note(
      id: map['id'],
      title: map['title'],
      content: map['content'],
      createdAt: DateTime.parse(map['created_at']),
    );
  }
}

Building The Note List Screen

Create a screen to display all notes from the database:

class NotesListScreen extends StatefulWidget {
  @override
  _NotesListScreenState createState() => _NotesListScreenState();
}

class _NotesListScreenState extends State<NotesListScreen> {
  late Future<List<Note>> notesFuture;
  
  @override
  void initState() {
    super.initState();
    notesFuture = _fetchNotes();
  }
  
  Future<List<Note>> _fetchNotes() async {
    final notesList = await DatabaseHelper.instance.readAllNotes();
    return notesList.map((noteMap) => Note.fromMap(noteMap)).toList();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My Notes App'),
        centerTitle: true,
      ),
      body: FutureBuilder<List<Note>>(
        future: notesFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error loading notes'));
          } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
            return Center(child: Text('No notes found'));
          } else {
            return ListView.builder(
              itemCount: snapshot.data!.length,
              itemBuilder: (context, index) {
                final note = snapshot.data![index];
                return ListTile(
                  title: Text(note.title),
                  subtitle: Text(note.content),
                  trailing: Text(DateFormat('MMM dd, yyyy').format(note.createdAt)),
                  onTap: () => _navigateToNoteDetail(context, note),
                );
              },
            );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => _navigateToNoteDetail(context, null),
      ),
    );
  }
  
  void _navigateToNoteDetail(BuildContext context, Note? note) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => NoteDetailScreen(note: note),
      ),
    );
    
    if (result == true) {
      setState(() {
        notesFuture = _fetchNotes();
      });
    }
  }
}

Creating The Note Detail Screen

Implement a screen to create/edit notes:

class NoteDetailScreen extends StatefulWidget {
  final Note? note;
  
  NoteDetailScreen({this.note});
  
  @override
  _NoteDetailScreenState createState() => _NoteDetailScreenState();
}

class _NoteDetailScreenState extends State<NoteDetailScreen> {
  final _formKey = GlobalKey<FormState>();
  late TextEditingController _titleController;
  late TextEditingController _contentController;
  
  @override
  void initState() {
    super.initState();
    _titleController = TextEditingController(text: widget.note?.title ?? '');
    _contentController = TextEditingController(text: widget.note?.content ?? '');
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.note == null ? 'Add Note' : 'Edit Note'),
        actions: [
          if (widget.note != null)
            IconButton(
              icon: Icon(Icons.delete),
              onPressed: _deleteNote,
            ),
        ],
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _titleController,
                decoration: InputDecoration(labelText: 'Title'),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter a title';
                  }
                  return null;
                },
              ),
              SizedBox(height: 16),
              TextFormField(
                controller: _contentController,
                decoration: InputDecoration(labelText: 'Content'),
                maxLines: 5,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter some content';
                  }
                  return null;
                },
              ),
              Spacer(),
              ElevatedButton(
                child: Text('Save'),
                onPressed: _saveNote,
              ),
            ],
          ),
        ),
      ),
    );
  }
  
  Future _saveNote() async {
    if (_formKey.currentState!.validate()) {
      final note = Note(
        id: widget.note?.id,
        title: _titleController.text,
        content: _contentController.text,
        createdAt: widget.note?.createdAt ?? DateTime.now(),
      );
      
      if (note.id == null) {
        await DatabaseHelper.instance.createNote(note.toMap());
      } else {
        await DatabaseHelper.instance.updateNote(note.toMap());
      }
      
      Navigator.pop(context, true);
    }
  }
  
  Future _deleteNote() async {
    final confirmed = await showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Delete Note?'),
        content: Text('Are you sure you want to delete this note?'),
        actions: [
          TextButton(
            child: Text('Cancel'),
            onPressed: () => Navigator.pop(context, false),
          ),
          TextButton(
            child: Text('Delete'),
            onPressed: () => Navigator.pop(context, true),
          ),
        ],
      ),
    );
    
    if (confirmed == true && widget.note?.id != null) {
      await DatabaseHelper.instance.deleteNote(widget.note!.id!);
      Navigator.pop(context, true);
    }
  }
  
  @override
  void dispose() {
    _titleController.dispose();
    _contentController.dispose();
    super.dispose();
  }
}

Testing And Debugging Your Windows App

Before finalizing your application, thorough testing is essential.

Recommended For You:
Convenience At Your Fingertips: The Rise Of On-Demand App Solutions

Running The Application

Launch your app in debug mode:

flutter run -d windows

Common Issues And Solutions

  • Database not initializing: Check file permissions and database path
  • UI not updating: Ensure you’re calling setState() after database operations
  • Performance issues: Consider using isolates for heavy database operations

Debugging Database Operations

Add logging to your database helper:

// Add to _initDB method
print('Database initialized at: $path');

Building For Distribution

Once your app is ready, package it for Windows distribution.

Creating A Release Build

Generate an optimized build:

flutter build windows

Packaging Your Application

The build output is located in build\windows\runner\Release. You can:

  • Distribute the folder as a zip file
  • Create an installer using WiX Toolset or Inno Setup
  • Publish to the Microsoft Store

Advanced Features To Consider

Enhance your Windows application with these professional features:

Database Migrations

Implement versioned database schema changes for future updates.

Offline Synchronization

Add cloud sync capabilities when internet connection is available.

Native Windows Integration

Use the window_size package to customize window behavior.

Conclusion

Building Windows desktop applications with Flutter offers a modern, efficient approach to cross-platform development. By combining Flutter’s powerful UI capabilities with local database persistence, you can create professional-grade applications with a single codebase.

This tutorial covered the complete process from setup to distribution, providing you with a solid foundation for your Flutter Windows development journey. The techniques learned here can be applied to various types of desktop applications requiring local data storage.

As you continue developing, explore additional Flutter packages that can enhance your Windows applications, such as file system access, system tray integration, and more advanced database solutions.

You Like It, Please Share This Recipe With Your Friends Using...

Be the first to write a comment.

Leave a Reply

Your email address will not be published. Required fields are marked *