1. Başlamadan önce
Bu codelab'de, FlutterFire UI paketini kullanarak Flutter uygulamanıza Firebase Authentication'ı nasıl ekleyeceğinizi öğreneceksiniz. Bu paketle, Flutter uygulamasına hem e-posta/şifre kimlik doğrulamasını hem de Google ile oturum açma kimlik doğrulamasını eklersiniz. Ayrıca, Firebase projesini nasıl oluşturacağınızı ve Flutter uygulamanızda Firebase'i başlatmak için FlutterFire CLI'yi nasıl kullanacağınızı da öğrenirsiniz.
Ön koşullar
Bu codelab'de Flutter deneyiminiz olduğu varsayılır. Aksi takdirde, önce temel bilgileri öğrenmeniz önerilir. Aşağıdaki bağlantılar faydalı olabilir:
- Flutter Widget Çerçevesi Turu
- İlk Flutter Uygulamanızı Yazma, 1. Bölüm codelab'ini deneyin.
Firebase deneyiminiz de olmalıdır ancak Flutter projesine hiç Firebase eklemediyseniz sorun değil. Firebase konsolunu bilmiyorsanız veya Firebase'i kullanmaya yeni başladıysanız öncelikle aşağıdaki bağlantılara göz atın:
Oluşturacağınız içerikler
Bu codelab, kimlik doğrulama için Firebase'i kullanarak bir Flutter uygulamasının kimlik doğrulama akışını oluşturma konusunda size yol gösterir. Uygulamada giriş ekranı, "Kaydol" ekranı, şifre kurtarma ekranı ve kullanıcı profili ekranı bulunur.
Neler öğreneceksiniz?
Bu codelab'de aşağıdaki konular ele alınmaktadır:
- Firebase'i Flutter uygulamasına ekleme
- Firebase Konsolu kurulumu
- Firebase'i uygulamanıza eklemek için Firebase CLI'yi kullanma
- Dart'ta Firebase yapılandırması oluşturmak için FlutterFire CLI'yi kullanma
- Flutter uygulamanıza Firebase Authentication'i ekleme
- Konsolda Firebase Authentication kurulumu
firebase_ui_auth
paketiyle e-posta ve şifreyle oturum açma özelliğini eklemefirebase_ui_auth
paketiyle kullanıcı kaydı ekleme- "Şifrenizi mi unuttunuz?" sayfası ekleme
firebase_ui_auth
ile Google ile oturum açma özelliğini ekleme- Uygulamanızı birden fazla oturum açma sağlayıcısıyla çalışacak şekilde yapılandırma
firebase_ui_auth
paketiyle uygulamanıza kullanıcı profili ekranı ekleme
Bu kod laboratuvarı, özellikle firebase_ui_auth
paketini kullanarak güçlü bir kimlik doğrulama sistemi eklemeyle ilgilidir. Göreceğiniz gibi, yukarıdaki tüm özelliklere sahip bu uygulamanın tamamı yaklaşık 100 satır kodla uygulanabilir.
Gerekenler
- Flutter ve yüklü SDK hakkında bilgi sahibi olma
- Metin düzenleyici (Flutter, JetBrains IDE'leri, Android Studio ve VS Code'u destekler)
- Google Chrome Tarayıcı veya Flutter için tercih ettiğiniz diğer geliştirme hedefi. (Bu kod laboratuvarındaki bazı terminal komutları, uygulamanızı Chrome'da çalıştırdığınızı varsayar.)
2. Firebase projesi oluşturup ayarlama
İlk olarak Firebase'in web konsolunda bir Firebase projesi oluşturmanız gerekir.
Firebase projesi oluşturma
- Firebase'de oturum açın.
- Firebase konsolunda Proje ekle'yi (veya Proje oluştur'u) tıklayın ve Firebase projeniz için bir ad girin (örneğin, "FlutterFire-UI-Codelab").
- Proje oluşturma seçeneklerini tıklayın. İstenirse Firebase şartlarını kabul edin. Bu uygulama için Analytics'i kullanmayacağınız için Google Analytics kurulumunu atlayın.
Firebase projeleri hakkında daha fazla bilgi edinmek için Firebase projelerini anlama başlıklı makaleyi inceleyin.
Firebase Authentication için e-posta ile oturum açma özelliğini etkinleştirme
Geliştirdiğiniz uygulama, kullanıcılarınızın uygulamanızda oturum açmasına izin vermek için Firebase Authentication'i kullanır. Ayrıca yeni kullanıcıların Flutter uygulamasından kaydolmasına olanak tanır.
Firebase Authentication'ın Firebase Konsolu kullanılarak etkinleştirilmesi ve etkinleştirildikten sonra özel yapılandırma gerektirmesi gerekir.
Kullanıcıların web uygulamasında oturum açmasına izin vermek için önce E-posta/Şifre oturum açma yöntemini kullanırsınız. Daha sonra Google ile oturum açma yöntemini ekleyeceksiniz.
- Firebase konsolunda, sol paneldeki Derleme menüsünü genişletin.
- Kimlik doğrulama'yı, ardından Başlayın düğmesini ve Oturum açma yöntemi sekmesini tıklayın (veya doğrudan Oturum açma yöntemi sekmesine gitmek için burayı tıklayın).
- Oturum açma sağlayıcıları listesinde E-posta/Şifre'yi tıklayın, Etkinleştir anahtarını açık konuma getirin ve ardından Kaydet'i tıklayın.
3. Flutter uygulamasını kurma
Başlamadan önce başlangıç kodunu indirmeniz ve Firebase CLI'yi yüklemeniz gerekir.
Başlangıç kodunu alma
GitHub deposunu komut satırından kopyalayın:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
Alternatif olarak, GitHub'ın CLI aracı yüklüyse:
gh repo clone flutter/codelabs flutter-codelabs
Örnek kod, makinenizdeki flutter-codelabs
dizine klonlanmalıdır. Bu dizin, bir kod laboratuvarı koleksiyonunun kodunu içerir. Bu codelab'in kodu flutter-codelabs/firebase-auth-flutterfire-ui
alt dizinindedir.
flutter-codelabs/firebase-auth-flutterfire-ui
dizini iki Flutter projesi içerir. Biri complete
, diğeri ise start
. start
dizini, tamamlanmamış bir proje içerir ve en çok zamanınızı burada geçirirsiniz.
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
İleri atlamak veya bir öğenin tamamlandığında nasıl görüneceğini görmek istiyorsanız çapraz referans için complete adlı dizine bakın.
Codelab'i takip etmek ve kendiniz kod eklemek istiyorsanız flutter-codelabs/firebase-auth-flutterfire-ui/start
adresindeki Flutter uygulamasıyla başlamalı ve codelab boyunca bu projeye kod eklemelisiniz. Bu dizini açın veya tercih ettiğiniz IDE'ye aktarın.
Firebase CLI'yi yükleyin
Firebase CLI, Firebase projelerinizi yönetmenize yönelik araçlar sağlar. CLI, birazdan yükleyeceğiniz FlutterFire CLI için gereklidir.
CLI'yi yüklemenin çeşitli yolları vardır. MacOS veya Linux kullanıyorsanız en kolay yol, terminalinizden şu komutu çalıştırmaktır:
curl -sL https://firebase.tools | bash
CLI'yi yükledikten sonra Firebase ile kimlik doğrulamanız gerekir.
- Aşağıdaki komutu çalıştırarak Google Hesabınızı kullanarak Firebase'e giriş yapın:
firebase login
- Bu komut, yerel makinenizi Firebase'e bağlar ve Firebase projelerinize erişim izni verir.
- Firebase projelerinizi listeleyerek CLI'nin düzgün şekilde yüklenip yüklenmediğini ve hesabınıza erişip erişemediğini test edin. Aşağıdaki komutu çalıştırın:
firebase projects:list
- Gösterilen liste, Firebase Konsolu'nda listelenen Firebase projeleriyle aynı olmalıdır. En az
flutterfire-ui-codelab.
FlutterFire CLI'yi yükleme
FlutterFire CLI, Flutter uygulamanızda desteklenen tüm platformlarda Firebase'in kurulum sürecini kolaylaştırmaya yardımcı olan bir araçtır. Firebase CLI'nin üzerine inşa edilmiştir.
Öncelikle CLI'yi yükleyin:
dart pub global activate flutterfire_cli
CLI'nin yüklü olduğundan emin olun. Aşağıdaki komutu çalıştırın ve KSA'nın yardım menüsünü görüntülediğinden emin olun.
flutterfire -—help
Firebase projenizi Flutter uygulamanıza ekleme
FlutterFire'ı yapılandırma
Firebase'i Flutter uygulamanızda kullanmak için gereken Dart kodunu oluşturmak üzere FlutterFire'i kullanabilirsiniz.
flutterfire configure
Bu komut çalıştırıldığında, kullanmak istediğiniz Firebase projesini ve hangi platformları ayarlamak istediğinizi seçmeniz istenir.
Aşağıdaki ekran görüntülerinde, yanıtlamanız gereken istemler gösterilmektedir.
- Kullanmak istediğiniz projeyi seçin. Bu durumda
flutterfire-ui-codelab
kullanın. - Kullanmak istediğiniz platformları seçin. Bu kod laboratuvarındaki adımlarda, web, iOS ve Android için Flutter'da Firebase Authentication'i yapılandırma adımları verilmiştir ancak Firebase projenizi tüm seçenekleri kullanacak şekilde ayarlayabilirsiniz.
- Bu ekran görüntüsü, sürecin sonunda elde edilen çıkışı gösterir. Firebase'i biliyorsanız konsolda platform uygulamaları (ör. Android uygulaması) oluşturmanız gerekmediğini ve FlutterFire CLI'nin bunu sizin için yaptığını fark edeceksiniz.
Bu işlem tamamlandığında, metin düzenleyicinizdeki Flutter uygulamasına bakın. FlutterFire CLI, firebase_options.dart
adlı yeni bir dosya oluşturdu. Bu dosya, her platform için gereken Firebase yapılandırmasını barındıran statik değişkenler içeren FirebaseOptions adlı bir sınıf içerir. flutterfire configure
'ü çalıştırırken tüm platformları seçtiyseniz web
, android
, ios
ve macos
adlı statik değerler görürsünüz.
firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
// ignore: missing_enum_constant_in_switch
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
}
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
measurementId: 'G-DGF0CP099H',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
Firebase, bir Firebase projesindeki belirli bir platforma yönelik belirli bir derlemeyi belirtmek için uygulama kelimesini kullanır. Örneğin, FlutterFire-ui-codelab adlı Firebase projesinin birden fazla uygulaması vardır: Android, iOS, MacOS ve Web için birer uygulama.
DefaultFirebaseOptions.currentPlatform
yöntemi, uygulamanızın çalıştığı platformu algılamak için Flutter tarafından sunulan TargetPlatform
enum'unu kullanır ve ardından doğru Firebase uygulaması için gereken Firebase yapılandırma değerlerini döndürür.
Firebase paketlerini Flutter uygulamasına ekleme
Kurulumun son adımı, ilgili Firebase paketlerini Flutter projenize eklemektir. Henüz eklenmemiş Firebase paketlerini kullandığı için firebase_options.dart
dosyasında hatalar olabilir. Terminalde, flutter-codelabs/firebase-emulator-suite/start
adresindeki Flutter projesinin kökünde olduğunuzdan emin olun. Ardından aşağıdaki üç komutu çalıştırın:
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth
Şu anda ihtiyacınız olan tek paketler bunlardır.
Firebase'i başlatma
Eklenen paketleri kullanmak için DefaultFirebaseOptions.currentPlatform,
, main.dart
dosyasındaki main
işlevindeki kodu güncelleyin.
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
Bu kod iki işlevi yerine getirir.
WidgetsFlutterBinding.ensureInitialized()
, Flutter'a Flutter çerçevesi tamamen başlatılana kadar uygulama widget kodunu çalıştırmaya başlamamasını söyler. Firebase, çerçevenin çalışmasını gerektiren yerel platform kanallarını kullanır.Firebase.initializeApp
, Flutter uygulamanız ile Firebase projeniz arasında bağlantı kurar.DefaultFirebaseOptions.currentPlatform
, oluşturulanfirebase_options.dart
dosyamızdan içe aktarılır. Bu statik değer, hangi platformda çalıştığınızı algılar ve ilgili Firebase anahtarlarını iletir.
4. İlk Firebase kullanıcı arayüzü kimlik doğrulama sayfasını ekleme
Auth için Firebase kullanıcı arayüzü, uygulamanızdaki ekranların tamamını temsil eden widget'lar sağlar. Bu ekranlar, uygulamanızdaki oturum açma, kayıt, şifremi unuttum, kullanıcı profili gibi farklı kimlik doğrulama akışlarını yönetir. Başlamak için uygulamanıza, ana uygulama için kimlik doğrulama koruyucusu görevi gören bir açılış sayfası ekleyin.
Material veya Cupertino uygulaması
FlutterFire UI, uygulamanızın bir MaterialApp veya CupertinoApp içine sarmalanması gerektiğini belirtir. Kullanıcı arayüzü, seçiminize bağlı olarak Material veya Cupertino widget'larındaki farklılıkları otomatik olarak yansıtır. Bu codelab için app.dart
'te uygulamaya zaten eklenmiş olan MaterialApp
öğesini kullanın.
app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AuthGate(),
);
}
}
Kimlik doğrulama durumunu kontrol etme
Oturum açma ekranı göstermeden önce kullanıcının kimliğinin doğrulanıp doğrulanmadığını belirlemeniz gerekir. Bunu kontrol etmenin en yaygın yolu, Firebase Auth eklentisini kullanarak FirebaseAuth'un authStateChanges etkinliğini dinlemektir.
Yukarıdaki kod örneğinde MaterialApp
, build yönteminde bir AuthGate
widget'ı oluşturuyor. (Bu, FlutterFire kullanıcı arayüzü tarafından sağlanmayan özel bir widget'tır.)
Bu widget'ın, authStateChanges
yayınını içerecek şekilde güncellenmesi gerekiyor.
authStateChanges
API, oturum açmışsa mevcut kullanıcıyı (Stream
) veya oturum açmamışsa null değerini döndürür. Uygulamamızda bu duruma abone olmak için Flutter'ın StreamBuilder widget'ını kullanabilir ve yayını ona iletebilirsiniz.
StreamBuilder
, ilettiğiniz bir akıştaki verilerin en son anlık görüntüsüne göre kendini oluşturan bir widget'tır. Akış yeni bir anlık görüntü yayınladığında otomatik olarak yeniden oluşturulur.
auth_gate.dart
konumundaki kodu güncelleyin.
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [],
);
}
return const HomeScreen();
},
);
}
}
StreamBuilder.stream
, daha önce bahsedilen akış olanFirebaseAuth.instance.authStateChanged
ile iletilir. Bu akış, kullanıcı kimliğini doğruladıysa bir FirebaseUser
nesnesi döndürür. (Aksi takdirdenull
döndürülür.)- Ardından kod, akıştaki değerin
User
nesnesini içerip içermediğini kontrol etmek içinsnapshot.hasData
değerini kullanır. - Aksi takdirde
SignInScreen
widget'ı döndürülür. Şu anda bu ekranda herhangi bir işlem yapılamaz. Bu, sonraki adımda güncellenecektir. - Aksi takdirde, yalnızca kimliği doğrulanmış kullanıcıların erişebildiği uygulamanın ana bölümü olan bir
HomeScreen
döndürür.
SignInScreen
, FlutterFire kullanıcı arayüzü paketinden gelen bir widget'tır. Bu, bu kod laboratuvarının bir sonraki adımında ele alınacaktır. Bu noktada uygulamayı çalıştırdığınızda boş bir oturum açma ekranı görürsünüz.
5. Oturum açma ekranı
FlutterFire kullanıcı arayüzü tarafından sağlanan SignInScreen
widget'ı aşağıdaki işlevleri ekler:
- Kullanıcıların oturum açmasına izin verir
- Kullanıcılar şifrelerini unuttuysa "Şifrenizi mi unuttunuz?" seçeneğine dokunarak şifrelerini sıfırlayabilecekleri bir forma yönlendirilebilirler.
- Henüz kayıtlı olmayan kullanıcılar "Kayıt ol"a dokunarak kaydolmalarını sağlayan başka bir forma yönlendirilebilir.
Bu işlem için de yalnızca birkaç satır kod gerekir. AuthGate widget'ındaki kodu hatırlayın:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(), // new
],
);
}
return const HomeScreen();
},
);
}
}
Yukarıda belirtilen tüm işlevleri elde etmek için gereken tek kod, SignInScreen
widget'ı ve providers
bağımsız değişkenidir. Artık "e-posta" ve "şifre" metin girişlerinin yanı sıra "Oturum aç" düğmesinin bulunduğu bir oturum açma ekranı görürsünüz.
İşlevsel olsa da stil açısından eksik. Widget, oturum açma ekranının görünümünü özelleştirmek için parametreler gösterir. Örneğin, şirketinizin logosunu ekleyebilirsiniz.
Oturum açma ekranını özelleştirme
headerBuilder
SignInScreen.headerBuilder
bağımsız değişkenini kullanarak oturum açma formunun üzerine istediğiniz widget'ları ekleyebilirsiniz. Bu widget yalnızca mobil cihazlar gibi dar ekranlarda gösterilir. Geniş ekranlarda, bu kod laboratuvarının ilerleyen bölümlerinde açıklanan SignInScreen.sideBuilder
seçeneğini kullanabilirsiniz.
auth_gate.dart
dosyasını şu kodla güncelleyin:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
headerBuilder bağımsız değişkeni, FlutterFire kullanıcı arayüzü paketinde tanımlanan HeaderBuilder türü bir işlev gerektirir.
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
Geri çağırma işlevi olduğundan, kullanabileceğiniz BuildContext
ve BoxConstraints
gibi değerleri gösterir ve bir widget döndürmenizi gerektirir. Geri döndürdüğünüz widget ekranın üst kısmında gösterilir. Bu örnekte yeni kod, ekranın üst kısmına bir resim ekler. Başvurunuz aşağıdaki gibi görünecektir.
Altyazı Oluşturucu
Oturum açma ekranı, ekranı özelleştirmenize olanak tanıyan üç ek parametre gösterir: subtitleBuilder
, footerBuilder
ve sideBuilder
.
subtitleBuilder
, geri çağırma bağımsız değişkenlerinin AuthAction
türündeki bir işlem içermesi açısından biraz farklıdır. AuthAction
, kullanıcının bulunduğu ekranın "oturum açma" ekranı mı yoksa "kayıt" ekranı mı olduğunu algılamak için kullanabileceğiniz bir enumdur.
subtitleBuilder'ı kullanmak için auth_gate.dart dosyasında kodu güncelleyin.
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
);
}
return const HomeScreen();
},
);
}
}
Uygulamayı yeniden yükleyin. Uygulama şu şekilde görünecektir:
Altbilgi oluşturucu
footerBuilder bağımsız değişkeni, subtitleBuilder ile aynıdır. Resim yerine metin için tasarlandığından BoxConstraints
veya shrinkOffset
öğelerini göstermez. (İstediğiniz widget'ı ekleyebilirsiniz.)
Bu kodu kullanarak oturum açma ekranınıza bir altbilgi ekleyin.
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
);
}
return const HomeScreen();
},
);
}}
Yan Oluşturucu
SignInScreen.sidebuilder bağımsız değişkeni bir geri çağırma işlevi kabul eder. Bu geri çağırma işlevinin bağımsız değişkenleri bu kez BuildContext
ve double shrinkOffset
'dur. sideBuilder'ın döndürdüğü widget, oturum açma formunun sol tarafında ve yalnızca geniş ekranlarda gösterilir. Bu, widget'ın yalnızca masaüstü ve web uygulamalarında gösterileceği anlamına gelir.
FlutterFire kullanıcı arayüzü, başlık içeriğinin mi (mobil gibi yüksek ekranlarda) yoksa yan içeriğin mi (geniş ekranlarda, masaüstünde veya web'de) gösterileceğini belirlemek için dahili olarak bir kesme noktası kullanır. Daha açık belirtmek gerekirse, ekranın genişliği 800 pikselden fazlaysa kenardaki oluşturucu içeriği gösterilir ve başlık içeriği gösterilmez. Ekran 800 pikselden daha darsa bunun tersi geçerlidir.
sideBuilder widget'ları eklemek için auth_gate.dart dosyasında kodu güncelleyin.
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Pencerenin genişliğini genişlettiğinizde uygulamanız artık şöyle görünecektir (Flutter web veya MacOS kullanıyorsanız).
Kullanıcı oluşturma
Bu noktada, bu ekranın tüm kodu tamamlanmıştır. Ancak oturum açabilmeniz için önce bir kullanıcı oluşturmanız gerekir. Bunu "Kaydol" ekranını kullanarak yapabilir veya Firebase konsolunda kullanıcı oluşturabilirsiniz.
Konsolu kullanmak için:
- Firebase konsolundaki "Kullanıcılar" tablosuna gidin.
- Burayı tıklayın
- "flutterfire-ui-codelab"i (veya farklı bir ad kullandıysanız başka bir projeyi) seçin. Aşağıdaki tabloyu görürsünüz:
- "Kullanıcı ekle" düğmesini tıklayın.
- Yeni kullanıcı için bir e-posta adresi ve şifre girin. Aşağıdaki resimde de görüldüğü gibi, bu sahte bir e-posta ve şifre olabilir. Bu yöntem işe yarar ancak sahte bir e-posta adresi kullanırsanız "Şifrenizi mi unuttunuz?" işlevi çalışmaz.
- "Kullanıcı ekle"yi tıklayın
Artık Flutter uygulamanıza dönebilir ve oturum açma sayfası üzerinden bir kullanıcının oturumunu açabilirsiniz. Uygulamanız aşağıdaki gibi görünmelidir:
6. Profil Ekranı
FlutterFire kullanıcı arayüzü, birkaç kod satırında size birçok işlev sunan bir ProfileScreen
widget'ı da sağlar.
ProfileScreen widget'ını ekleme
Metin düzenleyicinizde home.dart
dosyasına gidin. Aşağıdaki kodla güncelleyin:
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => const ProfileScreen(),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
Notun yeni kodu, IconButton.isPressed method.
adresine iletilen geri çağırma işlevidir. Bu IconButton
düğmesine basıldığında uygulamanız yeni bir anonim rota oluşturur ve bu rotaya gider. Bu rota, MaterialPageRoute.builder
geri çağırma işlevinden döndürülen ProfileScreen
widget'ını gösterir.
Uygulamanızı yeniden yükleyin ve sağ üstteki simgeye (uygulama çubuğunda) basın. Aşağıdaki gibi bir sayfa gösterilir:
Bu, FlutterFire kullanıcı arayüzü sayfası tarafından sağlanan standart kullanıcı arayüzüdür. Tüm düğmeler ve metin alanları Firebase Auth'a bağlanır ve kullanıma hazırdır. Örneğin, "Ad" metin alanına bir ad girebilirsiniz. FlutterFire kullanıcı arayüzü, FirebaseAuth.instance.currentUser?.updateDisplayName
yöntemini çağırır ve bu yöntem, adı Firebase'e kaydeder.
Oturum kapatma
Şu anda "Oturumu kapat" düğmesine basarsanız uygulama değişmez. Oturumunuz kapatılır ancak AuthGate widget'ına geri yönlendirilmezsiniz. Bunu uygulamak için ProfileScreen.actions parametresini kullanın.
Öncelikle home.dart dosyasında kodu güncelleyin.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
Artık ProfileScreen
örneği oluşturduğunuzda ProfileScreen.actions
bağımsız değişkenine bir işlem listesi de iletiyorsunuz. Bu işlemler FlutterFireUiAction
türündedir. FlutterFireUiAction
alt türleri olan birçok farklı sınıf vardır ve bunları genellikle uygulamanıza farklı kimlik doğrulama durumu değişikliklerine tepki vermesini söylemek için kullanırsınız. SignedOutAction, Firebase kimlik doğrulama durumu currentUser null olarak değiştiğinde ona verdiğiniz geri çağırma işlevini çağırır.
SignedOutAction tetiklendiğinde Navigator.of(context).pop()
işlevini çağıran bir geri çağırma işlevi ekleyerek uygulama önceki sayfaya gider. Bu örnek uygulamada yalnızca bir kalıcı rota vardır. Bu rota, oturum açmış bir kullanıcı yoksa oturum açma sayfasını, oturum açmış bir kullanıcı varsa ana sayfayı gösterir. Bu durum, kullanıcı çıkış yaptığında gerçekleştiği için uygulamada Giriş sayfası gösterilir.
Profil sayfasını özelleştirme
Oturum açma sayfasına benzer şekilde profil sayfası da özelleştirilebilir. Öncelikle, mevcut sayfamızda kullanıcı profil sayfasına geldiğinde ana sayfaya geri dönme seçeneği yok. ProfileScreen widget'ına bir AppBar ekleyerek bu sorunu düzeltin.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
ProfileScreen.appBar
bağımsız değişkeni, Flutter Material paketinden bir AppBar
widget'ı kabul eder. Bu nedenle, oluşturduğunuz ve bir Scaffold
'ye ilettiğiniz diğer tüm AppBar
'lar gibi ele alınabilir. Bu örnekte, otomatik olarak "geri" düğmesi ekleme varsayılan işlevi korunur ve ekranda bir başlık bulunur.
Profil ekranına çocuk ekleme
ProfileScreen widget'ında children adlı isteğe bağlı bir bağımsız değişken de vardır. Bu bağımsız değişken, bir widget listesi kabul eder. Bu widget'lar, ProfileScreen'i oluşturmak için zaten dahili olarak kullanılan bir sütun widget'ının içine dikey olarak yerleştirilir. ProfileScreen oluşturma yöntemindeki bu sütun widget'ı, ilettiğiniz çocukları "Oturumu kapat" düğmesinin üzerine yerleştirir.
home.dart dosyasında, oturum açma ekranına benzer şekilde şirket logosunu göstermek için kodu güncelleyin.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
children: [
const Divider(),
Padding(
padding: const EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
),
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
Uygulamanızı yeniden yüklediğinizde ekranda şunu görürsünüz:
7. Çok Platformlu Google Auth ile Oturum Açma
FlutterFire kullanıcı arayüzü, Google, Twitter, Facebook, Apple ve GitHub gibi üçüncü taraf sağlayıcılarla kimlik doğrulama için widget'lar ve işlevler de sağlar.
Google kimlik doğrulamasıyla entegrasyon için resmi firebase_ui_oauth_google eklentisini ve yerel kimlik doğrulama akışını yönetecek olan bağımlılarını yükleyin. Terminalde, Flutter projenizin kök dizinine gidin ve aşağıdaki komutu girin:
flutter pub add google_sign_in flutter pub add firebase_ui_oauth_google
Google ile Oturum Açma sağlayıcısını etkinleştirme
Ardından, Firebase Konsolu'nda Google sağlayıcıyı etkinleştirin:
- Konsolda Kimlik doğrulama oturum açma sağlayıcıları ekranına gidin.
- "Yeni sağlayıcı ekle"yi tıklayın.
- "Google"ı seçin.
- "Etkinleştir" etiketli anahtarı açık konuma getirin ve "Kaydet"e basın.
- Yapılandırma dosyalarının indirilmesiyle ilgili bilgilerin yer aldığı bir modal pencere görünürse "Bitti"yi tıklayın.
- Google ile oturum açma sağlayıcısının eklendiğini onaylayın.
Google ile oturum açma düğmesi ekleme
Google ile oturum açma özelliği etkinleştirildiğinde, stilize bir Google ile oturum açma düğmesi göstermek için gereken widget'ı oturum açma sayfasına ekleyin. auth_gate.dart dosyasına gidin ve kodu aşağıdaki şekilde güncelleyin:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // new
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR_WEBCLIENT_ID"), // new
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Buradaki tek yeni kod, SignInScreen widget yapılandırmasına GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
eklenmiş olmasıdır.
Bu eklendikten sonra uygulamanızı yeniden yükleyin. Google ile oturum açma düğmesini görürsünüz.
Oturum açma düğmesini yapılandırma
Düğme, ek yapılandırma olmadan çalışmaz. Flutter Web ile geliştirme yapıyorsanız bunun çalışması için eklemeniz gereken tek adım budur. Diğer platformlarda ek adımlar gerekir. Bu adımlardan biraz sonra bahsedeceğiz.
- Firebase Console'da Kimlik doğrulama sağlayıcıları sayfasına gidin.
- Google sağlayıcısını tıklayın.
- "Web SDK yapılandırması" genişletme panelini tıklayın.
- "Web istemci kimliği"ndeki değeri kopyalayın
- Metin düzenleyicinize dönün ve bu kimliği
clientId
adlı parametreye ileterekauth_gate.dart
dosyasındakiGoogleProvider
örneğini güncelleyin.
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
Web istemci kimliği girildikten sonra uygulamanızı yeniden yükleyin. "Google ile oturum aç" düğmesine bastığınızda, Google ile oturum açma akışında size yol gösterecek yeni bir pencere açılır (web'i kullanıyorsanız). İlk aşamada şöyle görünür:
iOS'i yapılandırma
Bu özelliğin iOS'te çalışması için ek bir yapılandırma işlemi gerekir.
- Firebase konsolunda Proje Ayarları ekranına gidin. Firebase uygulamalarınızın listesini içeren şuna benzer bir kart görürsünüz:
- iOS'u tıklayın. Uygulamanızın adının benden farklı olacağını unutmayın. Bu codelab'i takip etmek için
flutter-codelabs/firebase-auth-flutterfire-ui/start
projesini kullandıysanız benim "tamamlandı" dediğim yerde sizin "başla" denir. - Gerekli yapılandırma dosyasını indirmek için "GoogleServices-Info.plist" yazan düğmeyi tıklayın.
- İndirilen dosyayı adlı dizine sürükleyip bırakın .
/ios/Runner
dosyasını Flutter projenize ekleyin. - Projenizin kökünden aşağıdaki terminal komutunu çalıştırarak Xcode'u açın:
open ios/Runner.xcworkspace
- Runner dizinini sağ tıklayın ve "Runner"a Dosya Ekle'yi seçin.
- Dosya yöneticisinden GoogleService-Info.plist dosyasını seçin.
- Metin düzenleyicinize (Xcode değil) geri dönüp aşağıdaki CFBundleURLTypes özelliklerini [my_project]/ios/Runner/Info.plist dosyasına ekleyin.
<!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
</array>
</dict>
</array>
<!-- End of the Google Sign-in Section -->
- Web kurulumunda eklediğiniz
GoogleProvider.clientId
değerini, Firebase iOS istemci kimliğinizle ilişkili istemci kimliğiyle değiştirmeniz gerekir. Öncelikle bu kimliğifirebase_options.dart
dosyasında,iOS
sabitinin bir parçası olarak bulabilirsiniz.iOSClientId
parametresine iletilen değeri kopyalar.
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'YOUR API KEY',
appId: 'YOUR APP ID',
messagingSenderId: '',
projectId: 'PROJECT_ID',
storageBucket: 'PROJECT_ID.firebasestorage.app',
iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here.
iosBundleId: 'com.example.BUNDLE',
);
- Bu değeri
AuthGate
widget'ındakiGoogleProvider.clientId
bağımsız değişkenine yapıştırın.
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR IOS CLIENT ID"), // replace String
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Flutter uygulamanız iOS'te zaten çalışıyorsa uygulamayı tamamen kapatıp yeniden çalıştırmanız gerekir. Aksi takdirde uygulamayı iOS'te çalıştırın.
8. Tebrikler!
Flutter için Firebase Auth kullanıcı arayüzü codelab'ini tamamladınız . Bu Codelab'in tamamlanmış kodunu GitHub'daki "complete" dizininde bulabilirsiniz: Flutter Codelabs
İşlediğimiz konular
- Firebase'i kullanacak bir Flutter uygulaması oluşturma
- Firebase konsolunda Firebase projesi oluşturma
- FlutterFire CLI
- Firebase CLI
- Firebase Authentication'ı kullanma
- Flutter uygulamanızda Firebase kimlik doğrulamasını kolayca yönetmek için FlutterFire UI'yi kullanma
Sonraki adımlar
- Flutter'da Firestore ve Kimlik Doğrulama'yı kullanma hakkında daha fazla bilgi edinin: Flutter için Firebase'i tanıma Codelab
- Flutter uygulamanızı oluşturmak için diğer Firebase araçlarını keşfedin:
- Cloud Storage
- Cloud Functions
- Realtime Database
Daha fazla bilgi
- Firebase sitesi: firebase.google.com
- Flutter sitesi: flutter.dev
- FlutterFire Firebase Flutter widget'ları: firebase.flutter.dev
- Firebase YouTube kanalı
- Flutter YouTube kanalı
Sparky, bu mutlu günü sizinle birlikte kutlamak için burada.