Firebase
Firebase Integration
Firebase គឺជា Backend-as-a-Service (BaaS) platform ពី Google។ វាផ្តល់សេវា backend ដែលអ្នកអាចប្រើភ្លាមៗ ដោយមិនចាំបាច់សរសេរ backend code ផ្ទាល់ខ្លួន។
📚 Firebase Architecture Theory
Firebase Ecosystem:
Firebase Platform (15+ Services)
📱 AUTHENTICATION
- Email/Password
- Google Sign-In
- Phone Auth
- Anonymous Auth
�️ DATABASES
- Firestore (NoSQL, real-time)
- Realtime Database (JSON tree)
💾 STORAGE
- Cloud Storage (files, images, videos)
☁️ CLOUD FUNCTIONS
- Serverless backend code
📨 MESSAGING
- Cloud Messaging (Push notifications)
- In-App Messaging
📊 ANALYTICS
- User behavior tracking
- Crash reporting (Crashlytics)
Firebase vs Traditional Backend:
Feature | Firebase | Traditional Backend |
---|---|---|
Setup Time | ✅ Minutes | ❌ Days/Weeks |
Server Management | ✅ No servers needed | ❌ Must manage servers |
Scaling | ✅ Auto-scales | ❌ Manual scaling |
Real-time Data | ✅ Built-in | ❌ Need WebSockets |
Cost (Small Apps) | ✅ Free tier generous | ❌ Server costs from start |
Customization | ⚠️ Limited | ✅ Full control |
🔥 Firebase Services Overview
1. Firebase Authentication
Secure user authentication ជាមួយ methods ជាច្រើន៖
- 📧 Email & Password
- 🔍 Google Sign-In
- 📱 Phone Number (OTP)
- 👤 Anonymous Login
- 📘 Facebook, Twitter, GitHub, etc.
2. Cloud Firestore (Recommended Database)
NoSQL database ដែល support real-time syncing:
- ✅ Real-time listeners (data updates instantly)
- ✅ Offline support (works without internet)
- ✅ Powerful querying & filtering
- ✅ Auto-scaling
- ✅ Security rules for access control
3. Firebase Storage
Store and serve user-generated content:
- 🖼️ Images, Videos
- 📄 Documents, PDFs
- 🎵 Audio files
4. Cloud Messaging (FCM)
Send push notifications ទៅ users:
- 📨 Promotional messages
- 🔔 Real-time alerts
- 💬 Chat notifications
� Firebase Authentication Example
# pubspec.yaml
dependencies:
firebase_core: ^2.24.0
firebase_auth: ^4.15.0
import 'package:firebase_auth/firebase_auth.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// Get current user
User? get currentUser => _auth.currentUser;
// Auth state changes stream
Stream<User?> get authStateChanges => _auth.authStateChanges();
// Sign up with email & password
Future<UserCredential?> signUp({
required String email,
required String password,
}) async {
try {
final credential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return credential;
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
throw Exception('Password ខ្សោយពេក');
} else if (e.code == 'email-already-in-use') {
throw Exception('Email នេះត្រូវបានប្រើរួចហើយ');
}
throw Exception(e.message);
}
}
// Sign in with email & password
Future<UserCredential?> signIn({
required String email,
required String password,
}) async {
try {
return await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
throw Exception('រកមិនឃើញ user');
} else if (e.code == 'wrong-password') {
throw Exception('Password មិនត្រឹមត្រូវ');
}
throw Exception(e.message);
}
}
// Sign out
Future<void> signOut() async {
await _auth.signOut();
}
// Reset password
Future<void> resetPassword(String email) async {
await _auth.sendPasswordResetEmail(email: email);
}
}
📝 Cloud Firestore Examples
# pubspec.yaml
dependencies:
cloud_firestore: ^4.13.0
import 'package:cloud_firestore/cloud_firestore.dart';
// បន្ថែមទិន្នន័យ
Future<void> addUser() async {
await FirebaseFirestore.instance.collection('users').add({
'name': 'សុខា',
'age': 20,
});
}
// អានទិន្នន័យ
Stream<QuerySnapshot> getUsers() {
return FirebaseFirestore.instance.collection('users').snapshots();
}
Complete Firestore CRUD Operations:
import 'package:cloud_firestore/cloud_firestore.dart';
class FirestoreService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
// CREATE - បង្កើតទិន្នន័យថ្មី
Future<String> addProduct(Map<String, dynamic> data) async {
// Auto-generated ID
final docRef = await _db.collection('products').add(data);
return docRef.id;
// Or custom ID
// await _db.collection('products').doc('product_123').set(data);
}
// READ - អានទិន្នន័យ (Real-time listener)
Stream<List<Map<String, dynamic>>> getProducts() {
return _db.collection('products').snapshots().map(
(snapshot) => snapshot.docs.map((doc) {
return {...doc.data(), 'id': doc.id};
}).toList(),
);
}
// READ - អានមួយ document
Future<Map<String, dynamic>?> getProduct(String id) async {
final doc = await _db.collection('products').doc(id).get();
if (doc.exists) {
return {...doc.data()!, 'id': doc.id};
}
return null;
}
// UPDATE - ធ្វើបច្ចុប្បន្នភាព
Future<void> updateProduct(String id, Map<String, dynamic> data) async {
await _db.collection('products').doc(id).update(data);
}
// DELETE - លុប
Future<void> deleteProduct(String id) async {
await _db.collection('products').doc(id).delete();
}
// QUERY - ស្វែងរក & Filter
Stream<List<Map<String, dynamic>>> getProductsByCategory(String category) {
return _db
.collection('products')
.where('category', isEqualTo: category)
.orderBy('price', descending: false)
.limit(10)
.snapshots()
.map((snapshot) => snapshot.docs.map((doc) {
return {...doc.data(), 'id': doc.id};
}).toList());
}
// Complex Query
Future<List<Map<String, dynamic>>> searchProducts({
required String category,
required double minPrice,
required double maxPrice,
}) async {
final snapshot = await _db
.collection('products')
.where('category', isEqualTo: category)
.where('price', isGreaterThanOrEqualTo: minPrice)
.where('price', isLessThanOrEqualTo: maxPrice)
.get();
return snapshot.docs.map((doc) {
return {...doc.data(), 'id': doc.id};
}).toList();
}
}
📸 Firebase Storage Example
# pubspec.yaml
dependencies:
firebase_storage: ^11.5.0
image_picker: ^1.0.4
import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
class StorageService {
final FirebaseStorage _storage = FirebaseStorage.instance;
// Upload image
Future<String> uploadImage(File imageFile, String userId) async {
try {
// Create unique filename
final fileName = DateTime.now().millisecondsSinceEpoch.toString();
final ref = _storage.ref().child('users/' + userId + '/' + fileName);
// Upload file
final uploadTask = ref.putFile(imageFile);
// Wait for upload to complete
final snapshot = await uploadTask;
// Get download URL
final downloadUrl = await snapshot.ref.getDownloadURL();
return downloadUrl;
} catch (e) {
throw Exception('Upload failed: ' + e.toString());
}
}
// Pick and upload image
Future<String?> pickAndUploadImage(String userId) async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
final file = File(pickedFile.path);
return await uploadImage(file, userId);
}
return null;
}
// Delete image
Future<void> deleteImage(String imageUrl) async {
try {
final ref = _storage.refFromURL(imageUrl);
await ref.delete();
} catch (e) {
throw Exception('Delete failed: ' + e.toString());
}
}
// Get all user images
Future<List<String>> getUserImages(String userId) async {
final ref = _storage.ref().child('users/' + userId);
final result = await ref.listAll();
List<String> urls = [];
for (var item in result.items) {
final url = await item.getDownloadURL();
urls.add(url);
}
return urls;
}
}
🔔 Firebase Cloud Messaging (Push Notifications)
# pubspec.yaml
dependencies:
firebase_messaging: ^14.7.0
import 'package:firebase_messaging/firebase_messaging.dart';
class MessagingService {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
// Initialize notifications
Future<void> initialize() async {
// Request permission (iOS)
NotificationSettings settings = await _messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
// Get FCM token
String? token = await _messaging.getToken();
print('FCM Token: ' + (token ?? ''));
// Listen to foreground messages
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got message: ' + (message.notification?.title ?? ''));
// Show local notification
});
// Handle notification tap
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('Notification tapped!');
// Navigate to specific screen
});
}
}
// Subscribe to topic
Future<void> subscribeToTopic(String topic) async {
await _messaging.subscribeToTopic(topic);
}
}
🔒 Firestore Security Rules
Security Rules ត្រួតពិនិត្យថាអ្នកណាអាច read/write data បាន:
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Public read, authenticated write
match /products/{productId} {
allow read: if true; // Anyone can read
allow write: if request.auth != null; // Only logged-in users
}
// Users can only access their own data
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
// Admin-only collection
match /admin/{document=**} {
allow read, write: if request.auth != null
&& get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
}
}
🎯 Real-World Example: Chat App
class ChatService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
final FirebaseAuth _auth = FirebaseAuth.instance;
// Send message
Future<void> sendMessage(String chatId, String text) async {
await _db.collection('chats').doc(chatId).collection('messages').add({
'text': text,
'senderId': _auth.currentUser!.uid,
'senderName': _auth.currentUser!.displayName,
'timestamp': FieldValue.serverTimestamp(),
'isRead': false,
});
}
// Get messages (real-time)
Stream<List<Map<String, dynamic>>> getMessages(String chatId) {
return _db
.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timestamp', descending: true)
.limit(50)
.snapshots()
.map((snapshot) => snapshot.docs.map((doc) {
return {...doc.data(), 'id': doc.id};
}).toList());
}
// Mark message as read
Future<void> markAsRead(String chatId, String messageId) async {
await _db
.collection('chats')
.doc(chatId)
.collection('messages')
.doc(messageId)
.update({'isRead': true});
}
}
💡 Best Practices:
- ✅ Use Security Rules to protect data
- ✅ Index fields used in queries for better performance
- ✅ Use transactions for atomic operations
- ✅ Implement offline persistence for better UX
- ✅ Use batched writes for multiple operations
- ✅ Store large files in Storage, not Firestore
- ✅ Use subcollections for nested data
⚠️ Common Mistakes:
- ❌ Leaving Security Rules in test mode (public access)
- ❌ Not handling offline state properly
- ❌ Making too many small writes (use batches)
- ❌ Storing arrays for lists (use subcollections instead)
- ❌ Not monitoring costs (Firestore charges per read/write)
💡 ជំនួយ: Firebase ងាយប្រើ និងមានសេវាច្រើន។ Firestore support real-time data syncing។ Security Rules ចាំបាច់សម្រាប់ការពារទិន្នន័យ។