基于Flutter与ASP.NET Core的Firebase Cloud Messaging配置求助
糕点店订单系统 Firebase + ASP.NET Core + Flutter 完整配置方案
一、Firebase 基础配置
- 登录Firebase控制台,创建新项目(命名如「糕点店订单系统」),按需禁用Google Analytics,完成项目创建。
- 添加两类应用:
- Web应用:用于ASP.NET Core后端集成,复制生成的
firebaseConfig配置内容备用。 - Android/iOS应用:用于Flutter端,分别下载
google-services.json(Android)和GoogleService-Info.plist(iOS),保存到对应项目目录。
- Web应用:用于ASP.NET Core后端集成,复制生成的
- 启用Firebase Cloud Messaging(FCM):在控制台左侧菜单进入「Cloud Messaging」,完成基础配置(如设置通知图标)。
- 生成Admin SDK密钥:进入「项目设置」→「服务账户」,点击「生成新的私钥」,下载JSON密钥文件,保存到ASP.NET Core项目的安全目录。
二、ASP.NET Core 后端配置(订单提交触发FCM通知)
- 安装依赖包
在项目中执行以下NuGet命令:
Install-Package FirebaseAdmin Install-Package Microsoft.EntityFrameworkCore.SqlServer
- 初始化Firebase Admin SDK
在Program.cs中添加初始化代码:
var firebaseOptions = new FirebaseAdmin.AppOptions { Credential = FirebaseAdmin.Auth.FirebaseCredential.FromFile("你的密钥文件路径.json") }; FirebaseAdmin.FirebaseApp.Create(firebaseOptions);
- 配置SQL Server与订单实体
创建订单实体类:
public class Order { public int Id { get; set; } public string CustomerName { get; set; } public string TelephoneNumber { get; set; } public string PastryName { get; set; } public int Quantity { get; set; } public string Address { get; set; } public DateTime CreateTime { get; set; } = DateTime.Now; }
创建数据库上下文:
public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<Order> Orders { get; set; } }
在Program.cs中配置SQL Server连接:
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
在appsettings.json中添加连接字符串:
"ConnectionStrings": { "DefaultConnection": "Server=你的服务器地址;Database=PastryShopDB;Trusted_Connection=True;TrustServerCertificate=True;" }
- 编写订单接口与FCM通知逻辑
创建API控制器:
[ApiController] [Route("api/[controller]")] public class OrdersController : ControllerBase { private readonly AppDbContext _dbContext; private readonly FirebaseAdmin.Messaging.FirebaseMessaging _fcmMessaging; public OrdersController(AppDbContext dbContext) { _dbContext = dbContext; _fcmMessaging = FirebaseAdmin.Messaging.FirebaseMessaging.DefaultInstance; } [HttpPost] public async Task<IActionResult> SubmitOrder(Order order) { if (!ModelState.IsValid) return BadRequest(ModelState); // 保存订单到SQL Server _dbContext.Orders.Add(order); await _dbContext.SaveChangesAsync(); // 构建FCM通知内容 var notificationMessage = new FirebaseAdmin.Messaging.Message() { Notification = new FirebaseAdmin.Messaging.Notification() { Title = "新订单提醒", Body = $"客户:{order.CustomerName}\n手机号:{order.TelephoneNumber}\n糕点:{order.PastryName}\n数量:{order.Quantity}\n地址:{order.Address}" }, // 替换为店主设备的FCM令牌(需提前从Flutter端获取并存储) Token = "店主的FCM_TOKEN" }; // 发送通知 try { await _fcmMessaging.SendAsync(notificationMessage); } catch (Exception ex) { // 记录发送失败日志 Console.WriteLine($"FCM通知发送失败:{ex.Message}"); } return Ok(new { OrderId = order.Id, Message = "订单提交成功" }); } }
额外新增店主令牌存储接口:
[ApiController] [Route("api/owner")] public class OwnerController : ControllerBase { // 可将令牌存储到数据库或配置文件,示例仅做演示 private static string _shopOwnerToken; [HttpPost("token")] public IActionResult SaveToken([FromBody] TokenRequest request) { _shopOwnerToken = request.Token; return Ok(new { Message = "令牌保存成功" }); } public class TokenRequest { public string Token { get; set; } } }
三、Flutter 前端配置(客户下单 + 店主获取FCM令牌)
- 添加依赖
在pubspec.yaml中添加以下依赖:
dependencies: flutter: sdk: flutter firebase_core: ^2.15.0 firebase_messaging: ^14.6.5 http: ^1.1.0
执行flutter pub get完成安装。
- 初始化Firebase
在main.dart中初始化:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp(const MyApp()); }
- Android:将
google-services.json放入android/app目录。 - iOS:将
GoogleService-Info.plist放入ios/Runner目录,并在Xcode中添加到项目。
- 客户订单提交页面
编写下单UI与逻辑:
class OrderSubmitPage extends StatefulWidget { const OrderSubmitPage({super.key}); @override State<OrderSubmitPage> createState() => _OrderSubmitPageState(); } class _OrderSubmitPageState extends State<OrderSubmitPage> { final _formKey = GlobalKey<FormState>(); final _nameCtrl = TextEditingController(); final _phoneCtrl = TextEditingController(); final _pastryCtrl = TextEditingController(); final _quantityCtrl = TextEditingController(); final _addressCtrl = TextEditingController(); Future<void> _submit() async { if (_formKey.currentState!.validate()) { final orderData = { 'customerName': _nameCtrl.text, 'telephoneNumber': _phoneCtrl.text, 'pastryName': _pastryCtrl.text, 'quantity': int.parse(_quantityCtrl.text), 'address': _addressCtrl.text, }; try { final response = await http.post( Uri.parse('http://你的后端地址/api/orders'), headers: {'Content-Type': 'application/json'}, body: jsonEncode(orderData), ); if (response.statusCode == 200) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('订单提交成功!')), ); _formKey.currentState!.reset(); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('提交失败,请重试')), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('网络错误:$e')), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('提交订单')), body: Padding( padding: const EdgeInsets.all(16), child: Form( key: _formKey, child: Column( children: [ TextFormField( controller: _nameCtrl, decoration: const InputDecoration(labelText: '客户姓名'), validator: (val) => val!.isEmpty ? '请输入姓名' : null, ), TextFormField( controller: _phoneCtrl, decoration: const InputDecoration(labelText: '手机号'), validator: (val) => val!.isEmpty ? '请输入手机号' : null, ), TextFormField( controller: _pastryCtrl, decoration: const InputDecoration(labelText: '糕点名称'), validator: (val) => val!.isEmpty ? '请输入糕点名称' : null, ), TextFormField( controller: _quantityCtrl, decoration: const InputDecoration(labelText: '数量'), keyboardType: TextInputType.number, validator: (val) => val!.isEmpty ? '请输入数量' : null, ), TextFormField( controller: _addressCtrl, decoration: const InputDecoration(labelText: '配送地址'), validator: (val) => val!.isEmpty ? '请输入地址' : null, maxLines: 3, ), const SizedBox(height: 20), ElevatedButton(onPressed: _submit, child: const Text('提交订单')), ], ), ), ), ); } }
- 店主端获取FCM令牌
编写令牌获取与上传逻辑:
class ShopOwnerPage extends StatefulWidget { const ShopOwnerPage({super.key}); @override State<ShopOwnerPage> createState() => _ShopOwnerPageState(); } class _ShopOwnerPageState extends State<ShopOwnerPage> { String? _fcmToken; @override void initState() { super.initState(); _fetchAndUploadToken(); } Future<void> _fetchAndUploadToken() async { final token = await FirebaseMessaging.instance.getToken(); setState(() => _fcmToken = token); if (token != null) { try { await http.post( Uri.parse('http://你的后端地址/api/owner/token'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'token': token}), ); } catch (e) { print('令牌上传失败:$e'); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('店主端')), body: Center(child: Text('FCM令牌:$_fcmToken')), ); } }
四、测试流程
- 店主打开Flutter店主端,获取并上传FCM令牌到后端。
- 客户打开订单页面,填写信息提交订单。
- 后端将订单保存到SQL Server,同时触发FCM通知发送到店主设备。
- 店主设备收到包含完整订单信息的通知。
内容的提问来源于stack exchange,提问作者Vitor Malaquias
相关产品推荐
相关产品推荐

