How to create real two-friend chat app (not fake replies)

real two-friend chat app (not fake replies).
That means we need a backend to sync messages between two devices.

In Flutter, the easiest way is Firebase Firestore because it gives us:

  • Real-time database (messages sync instantly ).
  • Free tier for small apps.
  • Simple setup with Flutter.

Step 1: Setup Firebase in Your Flutter Project

  1. Go to Firebase Console → Add a new project.
  2. Enable Firestore Database (Start in Test Mode for now).
  3. Add your Android app inside Firebase project:
    • Get your Android package name from android/app/build.gradleapplicationId
    • Example: com.example.chatapp
    • Download the google-services.json and put it inside android/app/.
  4. Add Firebase Flutter packages in pubspec.yaml:
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^2.30.0
  cloud_firestore: ^5.0.0
  1. Run:
flutter pub get
  1. Update android/build.gradle and android/app/build.gradle (Firebase docs will guide you, or I can give step-by-step).

Step 2: Initialize Firebase

In main.dart:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Real Chat App',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: ChatScreen(),
    );
  }
}

Step 3: Build Real Chat UI with Firestore

ChatScreen:

class ChatScreen extends StatefulWidget {
  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _controller = TextEditingController();
  final CollectionReference messages =
      FirebaseFirestore.instance.collection('messages');

  void _sendMessage() {
    if (_controller.text.trim().isEmpty) return;

    messages.add({
      'text': _controller.text.trim(),
      'createdAt': FieldValue.serverTimestamp(),
      'sender': "User1", // later replace with auth user
    });

    _controller.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Real Chat")),
      body: Column(
        children: [
          // Live messages
          Expanded(
            child: StreamBuilder(
              stream: messages.orderBy('createdAt', descending: true).snapshots(),
              builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
                if (!snapshot.hasData) return const Center(child: CircularProgressIndicator());
                var docs = snapshot.data!.docs;
                return ListView.builder(
                  reverse: true,
                  itemCount: docs.length,
                  itemBuilder: (context, index) {
                    var msg = docs[index];
                    bool isMe = msg['sender'] == "User1"; // later dynamic
                    return Align(
                      alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
                      child: Container(
                        margin: const EdgeInsets.all(8),
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: isMe ? Colors.blueAccent : Colors.grey[300],
                          borderRadius: BorderRadius.circular(10),
                        ),
                        child: Text(
                          msg['text'],
                          style: TextStyle(
                            color: isMe ? Colors.white : Colors.black,
                          ),
                        ),
                      ),
                    );
                  },
                );
              },
            ),
          ),

          // input box
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            color: Colors.grey[200],
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: "Type a message...",
                      border: InputBorder.none,
                    ),
                    onSubmitted: (_) => _sendMessage(),
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.send, color: Colors.blue),
                  onPressed: _sendMessage,
                )
              ],
            ),
          )
        ],
      ),
    );
  }
}

Now:

  • Install app on two devices (or emulator + phone).
  • Whatever you type on one device instantly appears on the other device .
  • You have built a real chat app!



Leave a Reply