whatsapp_chat_sdk
A Flutter UI SDK for building WhatsApp-style chat experiences inside your own app.
It provides ready-made widgets (chat list, thread screen, bubbles, emoji picker, attachments) and optional local state — not a standalone chat app and not a backend.
Table of contents
- What this package is
- Features
- Requirements
- Installation
- Quick start
- How to use in your app
- Widget reference
- Models
- Controller
- Themes
- Attachments & permissions
- Connect your backend
- Demo data
- Example project
- Platform support
- FAQ
- License
What this package is
| Included | Not included |
|---|---|
| Chat list UI | User authentication |
| Chat thread UI (messages + input) | REST / Firebase / WebSocket server |
| Message bubbles (text, media, contact, etc.) | Push notifications |
| Emoji picker & attachment sheet UI | Message encryption |
| Light / dark themes | Account / contact sync from device |
Optional WhatsAppChatController for local/demo state |
A full clone WhatsApp app shell |
Recommended usage: embed WhatsAppChatsPage and WhatsAppChatScreen in your Scaffold, tabs, or routes.
Optional: WhatsAppChatApp is a pre-built demo shell for prototypes only.
flowchart LR
subgraph your_app [Your Flutter App]
A[Your AppBar / Nav / Auth]
B[WhatsAppChatsPage]
C[WhatsAppChatScreen]
end
subgraph sdk [whatsapp_chat_sdk]
B --> D[WhatsAppChatList]
C --> E[WhatsAppMessageBubble]
C --> F[WhatsAppInputBar]
C --> G[WhatsAppEmojiPicker]
end
subgraph backend [You implement]
H[API / Firebase / Socket]
end
B --> H
C --> H
Features
- Conversation list — avatars, unread count, last message preview, typing indicator on list
- Chat screen — wallpaper, date dividers, auto-scroll, group sender names
- Message types — text, image, video, audio, document, location, contact, sticker, system
- Read receipts — sending, sent ✓, delivered ✓✓, read (blue ✓✓), failed
- Input bar — emoji picker, attach menu, camera shortcut, send / mic button
- Attachments — document, camera, gallery (photo/video), contact (from chat participants), location (demo picker)
- Reply preview — quoted message in composer (wire
replyToon send) - Forwarded label on bubbles
- Themes —
WhatsAppTheme.light()/.dark()or fully custom colors - Controller —
ChangeNotifierfor conversations + messages (swap with your state management later)
Requirements
- Flutter 3.3+
- Dart 3.11+ (see
pubspec.yamlenvironment.sdk) - Your app must declare platform permissions for camera/gallery/files (see Attachments)
Installation
From pub.dev
dependencies:
whatsapp_chat_sdk: ^1.0.0
flutter pub get
From path (local development)
dependencies:
whatsapp_chat_sdk:
path: ../whatsapp_chat_sdk
From Git
dependencies:
whatsapp_chat_sdk:
git:
url: https://github.com/YOUR_USERNAME/whatsapp_chat_sdk.git
ref: main
Import everything from the public library:
import 'package:whatsapp_chat_sdk/whatsapp_chat_sdk.dart';
Quick start
Minimal integration: your MaterialApp, your AppBar, SDK only for the messages body.
import 'package:flutter/material.dart';
import 'package:whatsapp_chat_sdk/whatsapp_chat_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final WhatsAppChatController _controller;
@override
void initState() {
super.initState();
_controller = WhatsAppChatController(
currentUserId: 'me',
conversations: [], // load from your API
messagesByChatId: {},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Messages')),
body: WhatsAppChatsPage(
controller: _controller,
currentUserId: 'me',
theme: WhatsAppTheme.light(),
),
),
);
}
}
Run the bundled example:
cd example
flutter run
How to use in your app
Pattern 1 — Conversation list (recommended)
Use WhatsAppChatsPage inside any parent widget (Scaffold, TabBarView, Drawer, etc.).
WhatsAppChatsPage(
controller: controller,
currentUserId: currentUserId,
theme: WhatsAppTheme.dark(),
header: MyPromoBanner(), // optional widget above list
emptyWidget: MyEmptyChatsWidget(), // optional
onChatTap: (chat) { // optional — default opens chat screen
WhatsAppChatOpener.open(
context,
conversation: chat,
controller: controller,
currentUserId: currentUserId,
);
},
)
Pattern 2 — Open a chat from a button / notification
WhatsAppChatOpener.open(
context,
conversation: conversation,
controller: controller,
currentUserId: 'me',
onSend: (text) => myApi.sendText(conversation.id, text),
onSendMessage: (msg) => myApi.sendMessage(conversation.id, msg),
);
Pattern 3 — Chat screen only (you own the list)
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => WhatsAppChatScreen(
conversation: conversation,
messages: messages,
currentUserId: 'me',
onSend: (text) => sendText(text),
onSendMessage: (msg) => sendFullMessage(msg),
isTyping: remoteUserIsTyping,
typingLabel: 'Alice is typing...',
enableAttachments: true,
),
),
);
Pattern 4 — List widget only (full control)
WhatsAppChatList(
conversations: chats,
currentUserId: 'me',
theme: theme,
onChatTap: (chat) => /* your navigation */,
)
Pattern 5 — Single bubble (custom layout)
WhatsAppMessageBubble(
message: message,
isMe: message.senderId == myUserId,
theme: theme,
showSenderName: isGroup,
senderName: 'Alice',
onLongPress: () => showMessageActions(message),
)
Pattern 6 — Demo shell (prototypes only)
// Includes WhatsApp-style app bar + FAB — not for production branding
WhatsAppChatApp(
currentUserId: 'me',
controller: controller,
title: 'Chats',
)
Widget reference
| Widget | Purpose |
|---|---|
WhatsAppChatsPage |
Main entry — list + listens to controller + opens chat |
WhatsAppChatScreen |
Full thread: app bar, messages, typing, input, attachments |
WhatsAppChatList |
Conversation list only |
WhatsAppChatOpener |
Static helper to Navigator.push chat screen |
WhatsAppInputBar |
Composer with emoji / attach / send |
WhatsAppEmojiPicker |
Standalone emoji panel |
WhatsAppMessageBubble |
Single message bubble |
WhatsAppChatAppBar |
Thread header (avatar, name, actions) |
WhatsAppAvatar |
Circle avatar with optional online dot |
WhatsAppTypingIndicator |
Animated typing dots |
WhatsAppDateDivider |
“Today”, “Yesterday”, date labels |
WhatsAppWallpaper |
Chat background pattern |
WhatsAppAttachmentSheet |
Attach menu bottom sheet |
WhatsAppContactPickerSheet |
Share contact bottom sheet |
WhatsAppAttachmentHandler |
Pick gallery / camera / file / location |
WhatsAppChatApp |
All-in-one demo shell (optional) |
Models
ChatUser
ChatUser(
id: 'user_1',
name: 'Alice',
avatarUrl: 'https://...', // optional
phone: '+1 555-0100', // used when sharing contact
isOnline: true,
)
ChatConversation
ChatConversation(
id: 'chat_1',
title: 'Alice',
participants: [me, alice],
isGroup: false,
unreadCount: 2,
lastMessage: lastMsg,
isTyping: false,
typingUserName: null,
)
ChatMessage
ChatMessage(
id: 'm1',
senderId: 'me',
createdAt: DateTime.now(),
type: MessageType.text, // see MessageType enum
text: 'Hello',
status: MessageStatus.sent,
replyTo: quotedMessage,
mediaUrl: '/path/or/https/url', // image, video, local or network
fileName: 'report.pdf',
contactName: 'Bob',
contactPhone: '+1...',
latitude: 37.77,
longitude: -122.42,
)
MessageType
text · image · video · audio · document · location · contact · sticker · system
MessageStatus
sending · sent · delivered · read · failed
ChatAttachmentResult
Returned by pickers; convert to message:
final result = await WhatsAppAttachmentHandler.pickFromGallery();
if (result != null) {
final message = result.toMessage(
id: uuid,
senderId: myUserId,
);
controller.sendChatMessage(chatId: chatId, message: message);
}
Controller
WhatsAppChatController extends ChangeNotifier. Use with ListenableBuilder, AnimatedBuilder, or your state library.
| Method | Description |
|---|---|
conversations |
Read-only list of chats |
messagesFor(chatId) |
Messages in a thread |
sendMessage(chatId:, text:) |
Send text (demo delivery simulation) |
sendChatMessage(chatId:, message:) |
Send any MessageType |
setConversations(list) |
Replace all chats (e.g. after API fetch) |
setMessages(chatId, list) |
Replace thread messages |
addConversation(chat) |
Add new chat |
updateConversation(chat) |
Update metadata |
markAsRead(chatId) |
Clear unread badge |
setTyping(chatId:, isTyping:, userName:) |
Typing state for list + screen |
Important: sendMessage / sendChatMessage simulate delivery with delays. In production, call setMessages or update status after your API responds.
// Listen to updates
controller.addListener(() => setState(() {}));
// Or
ListenableBuilder(
listenable: controller,
builder: (_, __) => WhatsAppChatsPage(controller: controller, ...),
);
Themes
// Presets
final light = WhatsAppTheme.light();
final dark = WhatsAppTheme.dark();
// Custom
final brand = WhatsAppTheme(
primaryColor: Color(0xFF075E54),
accentColor: Color(0xFF25D366),
sentBubbleColor: Color(0xFFDCF8C6),
receivedBubbleColor: Colors.white,
isDark: false,
);
Pass theme: to WhatsAppChatsPage, WhatsAppChatScreen, WhatsAppChatList, and bubbles.
Color constants: WhatsAppColors.
Attachments & permissions
The SDK uses image_picker and file_picker.
Permissions must be added in your app, not in the package.
Android (android/app/src/main/AndroidManifest.xml)
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32"/>
iOS (ios/Runner/Info.plist)
<key>NSCameraUsageDescription</key>
<string>Used to take photos for chat messages</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to pick photos for chat messages</string>
Attachment flow (built into WhatsAppChatScreen)
- User taps attach →
WhatsAppAttachmentSheet(document, camera, gallery, contact, location). - Handler returns
ChatAttachmentResult. - Screen calls
onSendMessagewith aChatMessage.
Override handlers on the screen or use WhatsAppAttachmentHandler directly for custom UX.
Contact picker uses ChatConversation.participants (excluding current user). Add phone on ChatUser for display.
Connect your backend
The SDK is UI-only. Typical flow:
- Load chats → map API JSON to
List<ChatConversation>→controller.setConversations(...). - Open chat → fetch messages →
controller.setMessages(chatId, list). - Send text → optimistic UI → API → update
MessageStatuson success/failure. - Send media → upload file → set
mediaUrlto CDN URL →sendChatMessage. - Realtime → on socket event,
setMessagesor patch a single message.
Example (pseudo-code):
Future<void> onSendText(String chatId, String text) async {
final tempId = const Uuid().v4();
final optimistic = ChatMessage(
id: tempId,
senderId: myUserId,
text: text,
createdAt: DateTime.now(),
status: MessageStatus.sending,
type: MessageType.text,
);
controller.sendChatMessage(chatId: chatId, message: optimistic);
try {
final saved = await api.postMessage(chatId, text);
final list = controller.messagesFor(chatId).map((m) {
return m.id == tempId
? m.copyWith(id: saved.id, status: MessageStatus.sent)
: m;
}).toList();
controller.setMessages(chatId, list);
} catch (_) {
// mark failed
}
}
Works with Provider, Riverpod, Bloc, GetX, etc. — use the controller as a starting point or bind widgets to your own streams.
Demo data
For prototyping and the example app:
WhatsAppChatController(
currentUserId: WhatsAppDemoData.currentUserId,
conversations: WhatsAppDemoData.conversations(),
messagesByChatId: WhatsAppDemoData.messagesByChat(),
);
Do not ship demo data in production.
Example project
Location: example/
Shows embedding the SDK in a host app with:
- Custom
AppBar(“My App — Messages”) - Bottom navigation (Messages / Settings)
WhatsAppChatsPageon the Messages tab- Chat light/dark toggle (SDK theme only)
git clone <your-repo>
cd whatsapp_chat_sdk/example
flutter pub get
flutter run
Platform support
| Platform | UI | Emoji picker | Gallery / camera | File picker |
|---|---|---|---|---|
| Android | ✅ | ✅ | ✅ (with permissions) | ✅ |
| iOS | ✅ | ✅ | ✅ (with permissions) | ✅ |
| Web | ✅ | ✅ | Limited | ✅ |
| Windows | ✅ | ✅ | ✅ | ✅ |
| macOS | ✅ | ✅ | ✅ | ✅ |
| Linux | ✅ | ✅ | Varies | ✅ |
Local image paths in bubbles use Image.file on IO platforms and network URLs everywhere.
FAQ
Is this a full WhatsApp app?
No. It is a UI kit you place inside your application.
Can I use only the chat screen?
Yes. Use WhatsAppChatScreen + your own list/navigation.
Does it store messages permanently?
Only in memory via WhatsAppChatController. Persist with your database.
Can I change colors and fonts?
Yes, via WhatsAppTheme (fontFamily, bubble colors, app bar, etc.).
How do I disable attachments?
Set enableAttachments: false on WhatsAppChatScreen / WhatsAppChatsPage.
Package name / trademark
This is an unofficial UI toolkit. Ensure your app name and branding comply with store policies and trademarks.
License
MIT — see LICENSE.
Libraries
- whatsapp_chat_sdk
- Complete WhatsApp-style chat UI SDK for Flutter.