Tampilan
Bab 27 — Setup Firebase
Sampai sini aplikasimu berjalan sendirian di satu perangkat. Bagian ini mengubahnya: data tersimpan di awan, pengguna bisa masuk, dan perubahan dari satu perangkat langsung terlihat di perangkat lain.
Firebase adalah pilihan yang sangat umum untuk itu, dan bab ini membahas persiapannya — langkah yang kalau salah akan membuat enam bab berikutnya tidak berjalan.
Apa saja yang ada di Firebase
Firebase bukan satu produk, melainkan sekumpulan layanan. Yang akan kita pakai:
| Layanan | Fungsi | Dibahas di |
|---|---|---|
| Authentication | Login email, Google, telepon | Bab 28 |
| Cloud Firestore | Basis data NoSQL waktu nyata | Bab 29 |
| Storage | Menyimpan gambar & berkas | Bab 29 |
| Cloud Messaging | Push notification | Bab 30 |
| Cloud Functions | Kode server tanpa mengelola server | Bab 30 |
| Crashlytics | Laporan crash | Bab 38 |
Arsitekturnya secara garis besar:
┌───────────────────────────────────────────────────────┐
│ APLIKASI FLUTTER │
│ │
│ firebase_auth cloud_firestore firebase_storage │
│ firebase_messaging cloud_functions │
└────────────────────────┬──────────────────────────────┘
│ SDK (bukan HTTP mentah)
┌────────────────────────▼──────────────────────────────┐
│ FIREBASE │
│ │
│ ┌──────────┐ ┌───────────┐ ┌────────┐ ┌────────┐ │
│ │ Auth │ │ Firestore │ │Storage │ │ FCM │ │
│ └──────────┘ └─────┬─────┘ └────────┘ └────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Security Rules │ ← gerbang keamanan │
│ └───────────────────┘ │
└───────────────────────────────────────────────────────┘Perhatikan Security Rules di bagian bawah. Ini bagian yang paling sering diabaikan pemula dan paling berbahaya kalau salah — kita bahas di Bab 29.
Membuat proyek Firebase
- Buka console.firebase.google.com.
- Klik Add project, beri nama (misalnya
aplikasi-polling). - Google Analytics bersifat opsional — kamu bisa mematikannya untuk proyek belajar.
- Tunggu proyek selesai dibuat.
Di dalam proyek, kamu akan melihat daftar layanan di sidebar kiri. Setiap layanan harus diaktifkan satu per satu sebelum bisa dipakai — ini sumber error "permission denied" yang sering membingungkan.
Menghubungkan Flutter dengan FlutterFire CLI
Dulu menghubungkan Flutter ke Firebase berarti mengunduh berkas konfigurasi secara manual untuk Android dan iOS, menaruhnya di folder yang benar, dan mengedit berkas Gradle. Sekarang ada perkakas yang mengurus semuanya.
Memasang perkakas
bash
# Firebase CLI (butuh Node.js)
npm install -g firebase-tools
# Masuk ke akun Google
firebase login
# FlutterFire CLI
dart pub global activate flutterfire_cliPATH untuk paket Dart global
Kalau perintah flutterfire tidak dikenali setelah dipasang, direktori paket global Dart belum ada di PATH.
Di Windows, tambahkan:
C:\Users\<nama-pengguna>\AppData\Local\Pub\Cache\binDi macOS/Linux, tambahkan ke .zshrc atau .bashrc:
bash
export PATH="$PATH":"$HOME/.pub-cache/bin"Menghubungkan proyek
Dari dalam folder proyek Flutter:
bash
flutterfire configurePerintah ini akan:
- Menampilkan daftar proyek Firebase-mu — pilih yang tadi dibuat.
- Menanyakan platform mana yang didukung — pilih Android, iOS, dan lainnya sesuai kebutuhan.
- Mendaftarkan aplikasi ke Firebase secara otomatis.
- Membuat berkas
lib/firebase_options.dartyang berisi seluruh konfigurasi untuk semua platform. - Menaruh
google-services.json(Android) danGoogleService-Info.plist(iOS) di tempat yang benar.
Hasilnya berkas seperti ini:
dart
// lib/firebase_options.dart — DIHASILKAN OTOMATIS, jangan diedit manual
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) return web;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
default:
throw UnsupportedError('Platform belum dikonfigurasi.');
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIza...',
appId: '1:123456789:android:abc123',
messagingSenderId: '123456789',
projectId: 'aplikasi-polling',
storageBucket: 'aplikasi-polling.appspot.com',
);
// ... ios, web
}Apakah kunci ini rahasia?
Berbeda dari kunci API Google Maps di Bab 16, apiKey Firebase tidak rahasia. Ia hanya mengidentifikasi proyekmu, dan memang harus ada di dalam aplikasi.
Yang melindungi datamu adalah Security Rules, bukan kerahasiaan kunci ini. Karena itu firebase_options.dart aman untuk di-commit ke repositori — dan karena itu pula aturan keamanan yang benar menjadi sangat penting.
Memasang paket
yaml
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
# Wajib — fondasi semua layanan Firebase
firebase_core: ^3.8.0
# Sesuai kebutuhan
firebase_auth: ^5.3.3
cloud_firestore: ^5.5.0
firebase_storage: ^12.3.6
firebase_messaging: ^15.1.5
cloud_functions: ^5.1.5
# Pendukung
google_sign_in: ^6.2.2
image_picker: ^1.1.2bash
flutter pub getVersi paket harus cocok
Paket Firebase saling bergantung. Memakai firebase_auth versi lama dengan firebase_core versi baru sering menyebabkan error kompilasi yang tidak jelas.
Kalau kamu mengalaminya, jalankan:
bash
flutter pub upgrade --major-versionsAtau kunjungi firebase.flutter.dev untuk melihat kombinasi versi yang kompatibel.
Inisialisasi di aplikasi
dart
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
// Wajib sebelum memanggil kode platform di main()
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const AplikasiSaya());
}Dua baris itu wajib dan urutannya tidak boleh dibalik. Kalau kamu memanggil layanan Firebase apa pun sebelum initializeApp selesai, kamu mendapat:
[core/no-app] No Firebase App '[DEFAULT]' has been created —
call Firebase.initializeApp()Inisialisasi dengan penanganan kegagalan
Untuk aplikasi produksi, tangani kemungkinan gagalnya:
dart
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const AplikasiSaya());
} catch (kesalahan) {
runApp(LayarGagalMulai(pesan: kesalahan.toString()));
}
}
class LayarGagalMulai extends StatelessWidget {
const LayarGagalMulai({super.key, required this.pesan});
final String pesan;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.cloud_off, size: 64, color: Colors.grey),
const SizedBox(height: 16),
const Text(
'Gagal terhubung ke server',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'Periksa koneksi internetmu, lalu buka ulang aplikasi.',
textAlign: TextAlign.center,
),
],
),
),
),
),
);
}
}Konfigurasi Android
flutterfire configure sudah mengurus sebagian besar. Yang masih perlu kamu periksa ada di android/app/build.gradle:
gradle
android {
namespace "com.contoh.aplikasi_polling"
compileSdk 35
defaultConfig {
applicationId "com.contoh.aplikasi_polling"
// Firebase Auth butuh minimal 21
// Firestore dengan multidex butuh 21 juga
minSdkVersion 23
targetSdkVersion 35
multiDexEnabled true
}
}Error "Cannot fit requested classes in a single dex file"
Ini terjadi ketika aplikasimu melewati batas 64 ribu method — sangat mudah dicapai begitu beberapa paket Firebase ditambahkan.
Perbaikannya: multiDexEnabled true seperti di atas, dan tambahkan dependensinya:
gradle
dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
}SHA-1 untuk Google Sign-In
Kalau kamu berencana memakai login Google (Bab 28), Firebase butuh sidik jari sertifikat aplikasimu.
bash
# Untuk debug (saat pengembangan)
cd android
./gradlew signingReport
# Di Windows
gradlew signingReportSalin nilai SHA-1 dan SHA-256 dari varian debug, lalu tempel di Firebase Console → Project Settings → aplikasi Android → Add fingerprint.
Setelah menambahkannya, unduh ulang google-services.json dan ganti yang lama. Ini langkah yang paling sering terlupakan, dan gejalanya adalah login Google yang gagal diam-diam tanpa pesan error yang jelas.
SHA-1 rilis berbeda dari debug
Ketika kamu membangun versi rilis, sertifikatnya berbeda — jadi SHA-1-nya juga berbeda. Kamu harus menambahkan SHA-1 rilis ke Firebase juga, atau login Google akan berfungsi saat pengembangan tetapi gagal di Play Store.
Kalau memakai Play App Signing, ambil SHA-1 dari Play Console → Setup → App integrity.
Konfigurasi iOS
Buka ios/Podfile dan pastikan versi platform minimalnya cukup:
ruby
platform :ios, '13.0'Lalu pasang dependensinya:
bash
cd ios
pod install
cd ..Kalau pod install gagal, sering kali karena cache yang usang:
bash
cd ios
rm -rf Pods Podfile.lock
pod repo update
pod installBekerja dengan Xcode
Setelah pod install, buka ios/Runner.xcworkspace — bukanRunner.xcodeproj. Membuka yang salah membuat Xcode tidak menemukan dependensi CocoaPods, dan pesan errornya sangat tidak membantu.
Struktur data yang akan kita bangun
Sepanjang Bagian IV kita membangun aplikasi polling: pengguna membuat jajak pendapat, orang lain memberi suara, dan hasilnya tampil waktu nyata.
Struktur Firestore-nya:
firestore/
├── users/ ← koleksi
│ └── {uid}/ ← dokumen, ID = UID dari Auth
│ ├── nama: "Firnanda"
│ ├── email: "..."
│ ├── urlFoto: "https://..."
│ ├── dibuatPada: Timestamp
│ └── fcmToken: "..."
│
├── polls/
│ └── {pollId}/
│ ├── judul: "Bahasa favoritmu?"
│ ├── pemilikId: "{uid}"
│ ├── namaPemilik: "Firnanda"
│ ├── opsi: ["Dart", "Kotlin", "Swift"]
│ ├── jumlahSuara: [12, 8, 5]
│ ├── totalSuara: 25
│ ├── urlGambar: "https://..."
│ ├── unggulan: false
│ ├── unggulanSampai: Timestamp?
│ ├── lokasi: GeoPoint?
│ ├── dibuatPada: Timestamp
│ │
│ └── votes/ ← subkoleksi
│ └── {uid}/
│ ├── indeksOpsi: 0
│ └── padaWaktu: Timestamp
│
└── chats/
└── {uid}/
└── messages/
└── {messageId}/
├── teks: "..."
├── dariAi: false
└── padaWaktu: TimestampBeberapa keputusan desain yang layak diperhatikan sekarang, karena akan dijelaskan lebih dalam nanti:
ID dokumen users sama dengan UID dari Authentication. Ini membuat aturan keamanan menjadi sangat sederhana: request.auth.uid == userId.
jumlahSuara disimpan sebagai array di dokumen poll. Ini denormalisasi — data yang sebenarnya bisa dihitung dari subkoleksi votes, tetapi disimpan langsung agar menampilkan hasil tidak butuh membaca ratusan dokumen.
Subkoleksi votes memakai UID sebagai ID dokumen. Dengan begitu, satu pengguna secara struktural tidak mungkin memberi suara dua kali — bukan karena kita memeriksanya, tetapi karena tidak ada tempat untuk suara keduanya.
Firestore dibahas tuntas di Bab 29.
Struktur proyek
lib/
├── main.dart
├── firebase_options.dart ← dihasilkan flutterfire
│
├── data/
│ ├── models/
│ │ ├── pengguna.dart
│ │ ├── poll.dart
│ │ └── pesan.dart
│ ├── services/
│ │ ├── layanan_auth.dart ← pembungkus FirebaseAuth
│ │ ├── layanan_poll.dart ← pembungkus Firestore
│ │ ├── layanan_storage.dart ← pembungkus Storage
│ │ └── layanan_notifikasi.dart← pembungkus FCM
│ └── repositories/
│ ├── auth_repository.dart
│ └── poll_repository.dart
│
├── providers/ ← atau logic/ kalau memakai BLoC
│ ├── penyedia_auth.dart
│ └── penyedia_poll.dart
│
└── presentation/
├── screens/
└── widgets/Bungkus SDK Firebase, jangan panggil langsung dari UI
Godaan untuk menulis FirebaseFirestore.instance.collection('polls') langsung di dalam widget itu besar — dan itu kesalahan yang akan menyulitkanmu nanti.
Bungkus di kelas layanan seperti struktur di atas. Alasannya sama dengan yang dibahas di Bab 22: kamu bisa mengujinya dengan mock, mengganti implementasinya, dan menemukan semua kode Firebase di satu tempat ketika API-nya berubah.
Emulator lokal
Ini perkakas yang sangat berguna dan jarang dipakai pemula. Firebase Emulator Suite menjalankan Auth, Firestore, Storage, dan Functions di komputermu, sehingga kamu bisa:
- Bereksperimen tanpa mengotori data produksi.
- Bekerja tanpa koneksi internet.
- Menguji aturan keamanan dengan cepat.
- Menghindari biaya kuota saat pengembangan.
bash
# Sekali di folder proyek
firebase init emulators
# Menjalankannya
firebase emulators:startArahkan aplikasi ke emulator saat mode debug:
dart
// lib/main.dart
import 'package:flutter/foundation.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
const _pakaiEmulator = bool.fromEnvironment('USE_EMULATOR');
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
if (kDebugMode && _pakaiEmulator) {
// 10.0.2.2 adalah alamat host dari emulator Android
const host = '10.0.2.2';
await FirebaseAuth.instance.useAuthEmulator(host, 9099);
FirebaseFirestore.instance.useFirestoreEmulator(host, 8080);
await FirebaseStorage.instance.useStorageEmulator(host, 9199);
}
runApp(const AplikasiSaya());
}Menjalankannya:
bash
flutter run --dart-define=USE_EMULATOR=trueAlamat host yang benar
- Emulator Android:
10.0.2.2— alamat khusus yang menunjuk ke komputer host. - Simulator iOS:
localhost. - Perangkat fisik: alamat IP komputermu di jaringan lokal, misalnya
192.168.1.5.
Memeriksa penggunaan dan biaya
Firebase punya paket gratis (Spark) yang cukup murah hati, tetapi ada batasnya. Yang paling mudah terlampaui:
| Layanan | Batas gratis harian |
|---|---|
| Firestore baca | 50.000 dokumen |
| Firestore tulis | 20.000 dokumen |
| Firestore hapus | 20.000 dokumen |
| Storage unduh | 1 GB |
| Cloud Functions | 125.000 pemanggilan/bulan |
Kesalahan yang menghabiskan kuota
Angka 50.000 pembacaan terdengar banyak, tetapi mudah habis kalau kamu:
- Memakai
snapshots()pada koleksi besar tanpalimit()— setiap perubahan membaca ulang seluruh dokumen yang cocok. - Membaca data di dalam
build()tanpa cache. - Membuat listener baru setiap kali widget dibangun ulang.
Aktifkan Budget alerts di Google Cloud Console sejak hari pertama, meskipun kamu masih di paket gratis. Cloud Functions dan beberapa layanan lain butuh paket berbayar (Blaze), dan tagihan yang tak terduga bukan pengalaman yang menyenangkan.
Daftar periksa sebelum lanjut
Sebelum masuk ke bab berikutnya, pastikan semua ini beres:
- Proyek Firebase dibuat di console
- firebase-tools dan flutterfire_cli terpasang
- flutterfire configure dijalankan → lib/firebase_options.dart ada
- firebase_core ada di pubspec.yaml
- Firebase.initializeApp() dipanggil di main() yang async
- WidgetsFlutterBinding.ensureInitialized() dipanggil SEBELUMNYA
- minSdkVersion minimal 23 di android/app/build.gradle
- multiDexEnabled true
- platform :ios, '13.0' di ios/Podfile
- SHA-1 debug ditambahkan (kalau akan memakai Google Sign-In)
- google-services.json diunduh ULANG setelah menambah SHA-1
- Aplikasi berhasil dijalankan tanpa error Firebase
Uji cepat bahwa semuanya tersambung:
dart
// Tambahkan sementara di initState layar pertama
import 'package:firebase_core/firebase_core.dart';
@override
void initState() {
super.initState();
final app = Firebase.app();
debugPrint('✅ Firebase terhubung: ${app.options.projectId}');
}Kalau projectId tercetak dengan benar, kamu siap melanjutkan.
Ikhtisar
- Firebase adalah kumpulan layanan, dan setiap layanan harus diaktifkan satu per satu di console sebelum bisa dipakai.
flutterfire configuremengurus seluruh konfigurasi platform dan menghasilkanlib/firebase_options.dart— jangan mengedit berkas itu manual.apiKeyFirebase tidak rahasia. Yang melindungi datamu adalah Security Rules, bukan kerahasiaan kunci.- Urutan di
main()wajib:WidgetsFlutterBinding.ensureInitialized()→await Firebase.initializeApp()→runApp(). - Android butuh
minSdkVersionminimal 23 danmultiDexEnabled true. - iOS butuh
platform :ios, '13.0'danpod install. BukaRunner.xcworkspace, bukanRunner.xcodeproj. - Untuk Google Sign-In, tambahkan SHA-1 ke Firebase lalu unduh ulang
google-services.json— langkah kedua ini paling sering terlupakan. - SHA-1 rilis berbeda dari debug — tambahkan keduanya, atau login akan gagal di Play Store.
- Bungkus SDK Firebase di kelas layanan, jangan panggil langsung dari widget.
- Firebase Emulator Suite memungkinkan pengembangan tanpa internet, tanpa mengotori data produksi, dan tanpa memakai kuota.
- Aktifkan budget alerts sejak hari pertama.
snapshots()tanpalimit()pada koleksi besar adalah cara tercepat menghabiskan kuota baca.
Berikutnya: Bab 28 — Firebase Authentication.
Transkrip asli
Disintesis dari 4_flutter_ai-chatbot-n-firebase/1_getting-started-with-flutter-and-firebase.md (4 video: arsitektur Flutter & Firebase, instalasi, membuat proyek dan menghubungkan Firebase) dan 1_flutter_core/13_push-notification.md (video 2, 6–7: App & Firebase Setup, Firebase CLI & SDK Setup). Lihat PDF Firebase & AI.