You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需Firebase,从SQL Server向设备发送Flutter推送通知的实现方法

无需Firebase实现SQL Server到设备的推送通知

完全可以不依赖Firebase,通过自有服务器API对接各平台原生推送服务来实现。核心逻辑是:SQL Server触发推送事件 → 自有API服务器处理请求 → 调用对应平台的推送接口 → 设备接收通知。以下是具体实现步骤:

1. 对接各平台原生推送服务

不同平台的推送机制不同,需分别配置:

  • iOS(APNs):
    • 在苹果开发者后台创建APNs密钥,获取Team ID、Bundle ID和密钥文件。
    • 采用Token认证方式(比证书更易维护),生成JWT令牌用于请求APNs接口。
  • Android:
    • 海外用户:直接调用FCM的HTTP API,无需在服务器集成Firebase SDK,只需在Firebase控制台获取服务器密钥。
    • 国内用户:对接小米、华为、OPPO等厂商推送平台,各厂商有独立的API和认证流程,需在对应开发者平台完成配置。

2. 搭建自有API服务器

作为中间层,负责接收SQL Server的推送请求并转发到对应平台接口。以下是C#实现的核心示例:

APNs推送代码示例

using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

public async Task SendApplePush(string deviceToken, string title, string body)
{
    var apnsAuthKey = Environment.GetEnvironmentVariable("APNS_AUTH_KEY");
    var teamId = Environment.GetEnvironmentVariable("APNS_TEAM_ID");
    var bundleId = Environment.GetEnvironmentVariable("APNS_BUNDLE_ID");

    // 生成APNs JWT令牌
    var securityKey = new SymmetricSecurityKey(Convert.FromBase64String(apnsAuthKey));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
    var jwtToken = new JwtSecurityToken(issuer: teamId, expires: DateTime.UtcNow.AddMinutes(20), signingCredentials: credentials);
    var jwt = new JwtSecurityTokenHandler().WriteToken(jwtToken);

    // 构造推送请求
    using var httpClient = new HttpClient();
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
    httpClient.DefaultRequestHeaders.Add("apns-topic", bundleId);

    var payload = new
    {
        aps = new
        {
            alert = new { title, body },
            sound = "default"
        }
    };
    var jsonPayload = JsonConvert.SerializeObject(payload);
    var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");

    var response = await httpClient.PostAsync($"https://api.push.apple.com/3/device/{deviceToken}", content);
    response.EnsureSuccessStatusCode();
}

Android FCM推送代码示例

public async Task SendAndroidPush(string deviceToken, string title, string body)
{
    var fcmServerKey = Environment.GetEnvironmentVariable("FCM_SERVER_KEY");

    using var httpClient = new HttpClient();
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("key", fcmServerKey);

    var payload = new
    {
        to = deviceToken,
        notification = new { title, body },
        data = new { orderId = "12345" } // 自定义业务数据
    };
    var jsonPayload = JsonConvert.SerializeObject(payload);
    var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");

    var response = await httpClient.PostAsync("https://fcm.googleapis.com/fcm/send", content);
    response.EnsureSuccessStatusCode();
}

3. SQL Server触发推送请求

SQL Server不适合直接调用外部API(易阻塞事务),推荐用任务表+异步处理的方式:

步骤1:创建推送任务表

CREATE TABLE PushTasks (
    Id INT IDENTITY(1,1) PRIMARY KEY,
    DeviceToken NVARCHAR(255) NOT NULL,
    Platform NVARCHAR(10) NOT NULL, -- 标记iOS/Android
    Title NVARCHAR(100) NOT NULL,
    Body NVARCHAR(500) NOT NULL,
    CreatedAt DATETIME DEFAULT GETUTCDATE(),
    IsProcessed BIT DEFAULT 0,
    ProcessedAt DATETIME
);

步骤2:创建触发器插入任务

当业务数据变更时,将推送任务插入到任务表:

CREATE TRIGGER trg_OrderStatusUpdated
ON Orders
AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;
    -- 仅当状态字段更新时触发
    IF UPDATE(Status)
    BEGIN
        INSERT INTO PushTasks (DeviceToken, Platform, Title, Body)
        SELECT 
            c.DeviceToken,
            c.Platform,
            '订单状态更新',
            CONCAT('你的订单 ', i.OrderNumber, ' 已变为: ', i.Status)
        FROM inserted i
        JOIN Customers c ON i.CustomerId = c.Id
        WHERE c.DeviceToken IS NOT NULL;
    END
END

步骤3:异步处理任务

编写独立服务(如.NET Worker Service)或使用SQL Server代理作业,轮询PushTasks表处理未完成的推送任务:

// 简化的轮询逻辑
while (true)
{
    var tasks = GetUnprocessedPushTasks(); // 查询IsProcessed=0的任务
    foreach (var task in tasks)
    {
        try
        {
            if (task.Platform == "iOS")
                await SendApplePush(task.DeviceToken, task.Title, task.Body);
            else if (task.Platform == "Android")
                await SendAndroidPush(task.DeviceToken, task.Title, task.Body);
            
            MarkTaskAsProcessed(task.Id); // 更新任务状态为已处理
        }
        catch (Exception ex)
        {
            // 记录错误日志,可设置重试机制或标记任务失败
            LogError(ex, task.Id);
        }
    }
    await Task.Delay(TimeSpan.FromSeconds(10)); // 每10秒轮询一次
}

关键注意事项

  • 异步优先:禁止在SQL触发器中直接调用外部API,避免阻塞主业务事务,引发性能问题。
  • Token有效性:推送失败时需处理Token过期或无效的情况,及时从数据库移除或更新无效Token。
  • 安全防护:APNs密钥、FCM服务器密钥等敏感信息通过环境变量或配置中心管理,禁止硬编码。
  • 合规性:遵守各平台推送规则,比如iOS需用户授权通知权限,Android需配置通知渠道。

内容的提问来源于stack exchange,提问作者alper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:55:15