
作者:爱吃大芒果
本文所属专栏 Flutter
更多专栏
在移动应用开发中,用户认证、数据存储、文件上传是核心功能模块,手动搭建后端服务不仅耗时耗力,还需应对高并发、安全性等诸多挑战。Firebase 作为 Google 推出的一站式后端云服务平台,提供了认证、实时数据库、云存储等开箱即用的功能,能够快速补齐 Flutter 应用的后端能力,大幅提升开发效率。
本教程将以实战为导向,从环境准备入手,逐步实现 Flutter 与 Firebase 的集成,重点讲解用户认证(邮箱密码登录、Google 第三方登录)、实时数据库(数据增删改查)、云存储(图片上传与展示)三大核心功能,并通过一个完整的示例应用将三者串联,帮助开发者快速掌握 Flutter + Firebase 的开发流程与最佳实践。
首先需要在 Firebase 控制台创建项目,并为 Flutter 应用添加平台配置(Android + iOS),步骤如下:
android/app/build.gradle 中的 applicationId 一致,如「com.example.flutter_fire_demo」),输入应用别名(可选),点击「注册应用」;
google-services.json 文件,将其复制到 Flutter 项目的 android/app 目录下,点击「下一步」;
build.gradle 文件),完成后点击「下一步」,最后点击「继续到控制台」;
ios/Runner.xcodeproj/project.pbxproj 中的 PRODUCT_BUNDLE_IDENTIFIER 一致),输入应用别名(可选),点击「注册应用」;
GoogleService-Info.plist 文件,将其添加到 Flutter 项目的 ios/Runner 目录下(需在 Xcode 中添加,直接复制可能无效),点击「下一步」;
在 Flutter 项目的 pubspec.yaml 文件中,添加 Firebase 相关依赖包,本教程核心依赖如下:

添加完成后,执行 flutter pub get 命令安装依赖。
在 Flutter 应用启动时,需要初始化 Firebase,修改 lib/main.dart 文件,代码如下:
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart'; // 自动生成的文件
import 'screens/login_screen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 Firebase
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Fire Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const LoginScreen(), // 初始页面为登录页
debugShowCheckedModeBanner: false,
);
}
}注意:firebase_options.dart 文件会在执行 flutter pub get 后自动生成,若未生成,可执行 flutter pub run firebase_core:generate_config 命令手动生成。
Firebase Authentication 支持多种认证方式,本教程重点实现「邮箱密码登录」和「Google 第三方登录」,覆盖主流的账号登录场景。
首先需要在 Firebase 控制台启用对应的认证方式:
为了便于代码复用,创建 lib/services/auth_service.dart 文件,封装 Firebase 认证相关操作:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
// 获取当前登录用户
User? get currentUser => _firebaseAuth.currentUser;
// 监听用户登录状态变化
Stream<User?> get authStateChanges => _firebaseAuth.authStateChanges();
// 邮箱密码注册
Future<UserCredential?> signUpWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
final UserCredential userCredential =
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return userCredential;
} on FirebaseAuthException catch (e) {
// 处理注册错误(如邮箱已存在、密码过短等)
print('注册失败:${e.message}');
return null;
}
}
// 邮箱密码登录
Future<UserCredential?> signInWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
final UserCredential userCredential =
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
return userCredential;
} on FirebaseAuthException catch (e) {
// 处理登录错误(如邮箱不存在、密码错误等)
print('登录失败:${e.message}');
return null;
}
}
// Google 登录
Future<UserCredential?> signInWithGoogle() async {
try {
// 触发 Google 登录流程
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
if (googleUser == null) return null; // 用户取消登录
// 获取登录凭证
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// 用凭证登录 Firebase
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(credential);
return userCredential;
} catch (e) {
print('Google 登录失败:$e');
return null;
}
}
// 退出登录
Future<void> signOut() async {
await _firebaseAuth.signOut();
await _googleSignIn.signOut(); // 退出 Google 登录
}
}创建 lib/screens/login_screen.dart 文件,实现登录界面与交互逻辑:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
// 获取当前登录用户
User? get currentUser => _firebaseAuth.currentUser;
// 监听用户登录状态变化
Stream<User?> get authStateChanges => _firebaseAuth.authStateChanges();
// 邮箱密码注册
Future<UserCredential?> signUpWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
final UserCredential userCredential =
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return userCredential;
} on FirebaseAuthException catch (e) {
// 处理注册错误(如邮箱已存在、密码过短等)
print('注册失败:${e.message}');
return null;
}
}
// 邮箱密码登录
Future<UserCredential?> signInWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
final UserCredential userCredential =
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
return userCredential;
} on FirebaseAuthException catch (e) {
// 处理登录错误(如邮箱不存在、密码错误等)
print('登录失败:${e.message}');
return null;
}
}
// Google 登录
Future<UserCredential?> signInWithGoogle() async {
try {
// 触发 Google 登录流程
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
if (googleUser == null) return null; // 用户取消登录
// 获取登录凭证
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// 用凭证登录 Firebase
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(credential);
return userCredential;
} catch (e) {
print('Google 登录失败:$e');
return null;
}
}
// 退出登录
Future<void> signOut() async {
await _firebaseAuth.signOut();
await _googleSignIn.signOut(); // 退出 Google 登录
}
}创建 lib/screens/register_screen.dart 文件,实现用户注册功能,逻辑与登录页面类似:
import 'package:flutter/material.dart';
import 'package:flutter_fire_demo/services/auth_service.dart';
import 'package:flutter_fire_demo/screens/login_screen.dart';
class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key});
@override
State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final AuthService _authService = AuthService();
bool _isLoading = false;
void _handleRegister() async {
setState(() => _isLoading = true);
final String email = _emailController.text.trim();
final String password = _passwordController.text.trim();
if (email.isEmpty || password.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入邮箱和密码')),
);
setState(() => _isLoading = false);
return;
}
final UserCredential? userCredential =
await _authService.signUpWithEmailAndPassword(
email: email,
password: password,
);
setState(() => _isLoading = false);
if (userCredential != null) {
// 注册成功,返回登录页面
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('注册成功,请登录')),
);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const LoginScreen()),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('注册失败,请重试')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('注册')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
labelText: '邮箱',
border: OutlineInputBorder(),
),
enabled: !_isLoading,
),
const SizedBox(height: 16),
TextField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
labelText: '密码(至少6位)',
border: OutlineInputBorder(),
),
enabled: !_isLoading,
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleRegister,
child: _isLoading
? const CircularProgressIndicator(color: Colors.white)
: const Text('注册'),
),
),
const SizedBox(height: 16),
TextButton(
onPressed: _isLoading
? null
: () {
Navigator.pop(context);
},
child: const Text('已有账号?返回登录'),
),
],
),
),
);
}
}为了避免未登录用户直接访问首页,需要在 main.dart 中监听用户登录状态,根据状态动态切换页面:
// 修改 main.dart 中的 MyApp 组件
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Fire Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: StreamBuilder<User?>(
stream: AuthService().authStateChanges,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
// 加载中
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
// 根据登录状态切换页面
return snapshot.hasData ? const HomeScreen() : const LoginScreen();
},
),
debugShowCheckedModeBanner: false,
);
}
}Firebase Realtime Database 是一个云托管的 NoSQL 数据库,数据以 JSON 格式存储,支持实时同步,非常适合构建需要实时更新数据的应用(如聊天、社交、协作工具等)。本章节将实现用户个人信息的增删改查功能。
{ "rules": { ".read": "auth != null", // 已登录用户可读取 ".write": "auth != null" // 已登录用户可写入 } }
创建 lib/services/database_service.dart 文件,封装实时数据库的增删改查操作:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
class DatabaseService {
final FirebaseDatabase _database = FirebaseDatabase.instance;
final String? _uid;
// 构造函数,传入用户ID
DatabaseService({this._uid});
// 获取用户信息节点的引用
DatabaseReference get _userRef => _database.ref('users/$_uid');
// 保存用户信息
Future<void> saveUserInfo({
required String name,
required String phone,
}) async {
try {
await _userRef.set({
'name': name,
'phone': phone,
'uid': _uid,
'createTime': DateTime.now().millisecondsSinceEpoch,
});
} catch (e) {
print('保存用户信息失败:$e');
rethrow;
}
}
// 获取用户信息
Stream<DataSnapshot> getUserInfo() {
return _userRef.onValue;
}
// 更新用户信息
Future<void> updateUserInfo({
String? name,
String? phone,
}) async {
try {
final Map<String, dynamic> updates = {};
if (name != null) updates['name'] = name;
if (phone != null) updates['phone'] = phone;
await _userRef.update(updates);
} catch (e) {
print('更新用户信息失败:$e');
rethrow;
}
}
// 删除用户信息
Future<void> deleteUserInfo() async {
try {
await _userRef.remove();
} catch (e) {
print('删除用户信息失败:$e');
rethrow;
}
}
}创建 lib/screens/profile_screen.dart 文件,实现用户信息的展示、添加、修改和删除功能:
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_fire_demo/services/auth_service.dart';
import 'package:flutter_fire_demo/services/database_service.dart';
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
final AuthService _authService = AuthService();
late DatabaseService _databaseService;
final TextEditingController _nameController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
Map<String, dynamic> _userInfo = {};
bool _isLoading = false;
@override
void initState() {
super.initState();
final User? user = _authService.currentUser;
if (user != null) {
_databaseService = DatabaseService(uid: user.uid);
// 监听用户信息变化
_databaseService.getUserInfo().listen((snapshot) {
if (snapshot.value != null) {
setState(() {
_userInfo = Map<String, dynamic>.from(snapshot.value as Map);
_nameController.text = _userInfo['name'] ?? '';
_phoneController.text = _userInfo['phone'] ?? '';
});
}
});
}
}
// 保存/更新用户信息
void _handleSaveUserInfo() async {
setState(() => _isLoading = true);
final String name = _nameController.text.trim();
final String phone = _phoneController.text.trim();
if (name.isEmpty || phone.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入姓名和手机号')),
);
setState(() => _isLoading = false);
return;
}
try {
if (_userInfo.isEmpty) {
// 新增用户信息
await _databaseService.saveUserInfo(name: name, phone: phone);
} else {
// 更新用户信息
await _databaseService.updateUserInfo(name: name, phone: phone);
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('操作成功')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('操作失败:$e')),
);
} finally {
setState(() => _isLoading = false);
}
}
// 删除用户信息
void _handleDeleteUserInfo() async {
if (_userInfo.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('暂无用户信息可删除')),
);
return;
}
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('确认删除'),
content: const Text('确定要删除用户信息吗?此操作不可恢复。'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () async {
Navigator.pop(context);
setState(() => _isLoading = true);
try {
await _databaseService.deleteUserInfo();
setState(() => _userInfo.clear());
_nameController.clear();
_phoneController.clear();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('删除成功')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('删除失败:$e')),
);
} finally {
setState(() => _isLoading = false);
}
},
child: const Text('删除'),
),
],
),
);
}
// 退出登录
void _handleSignOut() async {
await _authService.signOut();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('个人中心'),
actions: [
TextButton(
onPressed: _isLoading ? null : _handleSignOut,
child: const Text(
'退出登录',
style: TextStyle(color: Colors.white),
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(
labelText: '姓名',
border: OutlineInputBorder(),
),
enabled: !_isLoading,
),
const SizedBox(height: 16),
TextField(
controller: _phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
labelText: '手机号',
border: OutlineInputBorder(),
),
enabled: !_isLoading,
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _isLoading ? null : _handleSaveUserInfo,
child: _isLoading
? const CircularProgressIndicator(color: Colors.white)
: Text(_userInfo.isEmpty ? '保存信息' : '更新信息'),
),
),
const SizedBox(width: 16),
Expanded(
child: OutlinedButton(
onPressed: _isLoading ? null : _handleDeleteUserInfo,
child: const Text('删除信息'),
),
),
],
),
const SizedBox(height: 32),
// 展示用户信息
if (_userInfo.isNotEmpty)
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'用户信息',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
Text('姓名:${_userInfo['name']}'),
Text('手机号:${_userInfo['phone']}'),
Text(
'创建时间:${DateTime.fromMillisecondsSinceEpoch(_userInfo['createTime']).toString().substring(0, 19)}',
),
],
),
),
),
],
),
),
);
}
}Firebase Cloud Storage 用于存储和检索用户生成的内容(如图片、视频、音频等),提供了高可用性和安全性。本章节将实现图片选择、上传到云存储,并展示已上传的图片功能。
{ "rules": { ".read": "auth != null", ".write": "auth != null" } }
创建 lib/services/storage_service.dart 文件,封装图片上传、获取图片URL、删除图片等操作:
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
class StorageService {
final FirebaseStorage _storage = FirebaseStorage.instance;
final String? _uid;
StorageService({this._uid});
// 获取图片存储引用(按用户ID分目录,避免文件名冲突)
Reference get _imageRef => _storage.ref('user_images/$_uid');
// 上传图片
Future<String?> uploadImage(File imageFile) async {
try {
// 生成唯一的文件名(时间戳 + 原文件名)
final String fileName =
'${DateTime.now().millisecondsSinceEpoch}_${imageFile.path.split('/').last}';
// 创建存储引用
final Reference ref = _imageRef.child(fileName);
// 上传文件
final UploadTask uploadTask = ref.putFile(imageFile);
// 等待上传完成,获取下载URL
final TaskSnapshot taskSnapshot = await uploadTask;
final String downloadUrl = await taskSnapshot.ref.getDownloadURL();
return downloadUrl;
} catch (e) {
print('图片上传失败:$e');
return null;
}
}
// 获取用户上传的所有图片URL
Future<List<String>> getImageUrls() async {
try {
final ListResult result = await _imageRef.listAll();
final List<String> urls = [];
for (final Reference ref in result.items) {
final String url = await ref.getDownloadURL();
urls.add(url);
}
return urls;
} catch (e) {
print('获取图片URL失败:$e');
return [];
}
}
// 删除图片
Future<bool> deleteImage(String imageUrl) async {
try {
// 从URL中获取图片引用
final Reference ref = _storage.refFromURL(imageUrl);
await ref.delete();
return true;
} catch (e) {
print('图片删除失败:$e');
return false;
}
}
}创建 lib/screens/image_upload_screen.dart 文件,使用 image_picker 插件选择图片,结合存储工具类实现上传与展示:
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_fire_demo/services/storage_service.dart';
import 'dart:io';
class ImageUploadScreen extends StatefulWidget {
const ImageUploadScreen({super.key});
@override
State<ImageUploadScreen> createState() => _ImageUploadScreenState();
}
class _ImageUploadScreenState extends State<ImageUploadScreen> {
final StorageService _storageService =
StorageService(uid: FirebaseAuth.instance.currentUser?.uid);
final ImagePicker _picker = ImagePicker();
File? _selectedImage;
List<String> _imageUrls = [];
bool _isLoading = false;
@override
void initState() {
super.initState();
// 初始化时获取已上传的图片
_getUploadedImages();
}
// 获取已上传的图片
Future<void> _getUploadedImages() async {
setState(() => _isLoading = true);
final List<String> urls = await _storageService.getImageUrls();
setState(() {
_imageUrls = urls;
_isLoading = false;
});
}
// 选择图片(从相册)
Future<void> _pickImage() async {
final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_selectedImage = File(pickedFile.path);
});
}
}
// 上传图片
Future<void> _uploadImage() async {
if (_selectedImage == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请先选择图片')),
);
return;
}
setState(() => _isLoading = true);
final String? downloadUrl = await _storageService.uploadImage(_selectedImage!);
setState(() => _isLoading = false);
if (downloadUrl != null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('图片上传成功')),
);
// 上传成功后重新获取图片列表
_getUploadedImages();
// 清空选择的图片
setState(() => _selectedImage = null);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('图片上传失败')),
);
}
}
// 删除图片
Future<void> _deleteImage(String imageUrl) async {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('确认删除'),
content: const Text('确定要删除这张图片吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () async {
Navigator.pop(context);
setState(() => _isLoading = true);
final bool success = await _storageService.deleteImage(imageUrl);
setState(() => _isLoading = false);
if (success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('图片删除成功')),
);
// 删除成功后重新获取图片列表
_getUploadedImages();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('图片删除失败')),
);
}
},
child: const Text('删除'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('图片上传与展示')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// 选择并预览图片
if (_selectedImage != null)
Column(
children: [
Image.file(
_selectedImage!,
height: 200,
fit: BoxFit.cover,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoading ? null : _uploadImage,
child: _isLoading
? const CircularProgressIndicator(color: Colors.white)
: const Text('上传图片'),
),
],
)
else
ElevatedButton(
onPressed: _isLoading ? null : _pickImage,
child: const Text('选择图片'),
),
const SizedBox(height: 32),
// 展示已上传的图片
const Text(
'已上传图片',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
if (_isLoading)
const CircularProgressIndicator()
else if (_imageUrls.isEmpty)
const Text('暂无上传的图片')
else
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: _imageUrls.length,
itemBuilder: (context, index) {
final String url = _imageUrls[index];
return Stack(
children: [
Image.network(
url,
height: double.infinity,
width: double.infinity,
fit: BoxFit.cover,
),
Positioned(
top: 8,
right: 8,
child: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: _isLoading
? null
: () => _deleteImage(url),
),
),
],
);
},
),
),
],
),
),
);
}
}为了将认证、数据库、云存储三大功能整合起来,创建首页 home_screen.dart,使用 BottomNavigationBar 实现页面切换:
import 'package:flutter/material.dart';
import 'package:flutter_fire_demo/screens/profile_screen.dart';
import 'package:flutter_fire_demo/screens/image_upload_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _currentIndex = 0;
// 导航页面列表
final List<Widget> _screens = [
const ProfileScreen(),
const ImageUploadScreen(),
];
// 导航标题列表
final List<String> _titles = [
'个人中心',
'图片管理',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(_titles[_currentIndex])),
body: _screens[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '个人中心',
),
BottomNavigationBarItem(
icon: Icon(Icons.photo),
label: '图片管理',
),
],
),
);
}
}在 Android 和 iOS 平台,需要配置对应的权限(如相册访问权限):
android/app/src/main/AndroidManifest.xml,添加相册访问权限: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
ios/Runner/Info.plist,添加相册访问权限描述: <key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册以选择图片</string>
部署到生产环境前,必须修改 Firebase 服务的规则,避免数据泄露:


本教程通过实战案例,详细讲解了 Flutter 与 Firebase 集成的核心流程,包括环境准备、用户认证、实时数据库、云存储四大核心模块,并通过首页导航将三者整合,形成了一个功能完整的应用。通过 Firebase 的集成,开发者无需关注后端服务的搭建与维护,只需专注于前端业务逻辑的实现,大幅提升了开发效率。
后续可进一步扩展功能,如添加邮箱验证、密码重置、实时聊天、推送通知等,充分利用 Firebase 生态的强大能力。同时,在生产环境中,需重点关注数据安全与权限控制,确保应用的稳定性与安全性。