Flutter迁移Supabase后如何实现数据库触发的推送通知?
实现数据库变更触发推送通知的方案
核心思路
Supabase本身没有内置推送通知服务,但可以通过PostgreSQL触发器+自定义函数结合外部推送服务(比如你之前用的FCM)实现需求,流程如下:
- 在Supabase数据库存储用户设备令牌
- 编写PostgreSQL函数,在目标表变更时调用外部推送API
- 给目标表绑定触发器,触发上述函数
具体步骤
1. 存储设备令牌
先创建存储令牌的表:
CREATE TABLE user_devices ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, device_token TEXT NOT NULL, platform TEXT CHECK (platform IN ('ios', 'android')) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() );
Flutter端将从firebase_messaging获取的设备令牌插入该表即可。
2. 创建推送函数
以调用FCM API为例,先启用http扩展:
CREATE EXTENSION IF NOT EXISTS http;
再创建推送函数:
CREATE OR REPLACE FUNCTION send_push_notification() RETURNS TRIGGER AS $$ DECLARE target_token TEXT; fcm_api_key TEXT := '你的FCM服务器密钥'; -- 替换为实际密钥 BEGIN -- 根据业务逻辑获取目标用户令牌,这里假设触发表关联user_id SELECT device_token INTO target_token FROM user_devices WHERE user_id = NEW.user_id; IF target_token IS NOT NULL THEN PERFORM http_post( 'https://fcm.googleapis.com/fcm/send', json_build_object( 'to', target_token, 'notification', json_build_object( 'title', '数据更新', 'body', '你的相关内容已变更' ) )::TEXT, ARRAY[ 'Content-Type: application/json', 'Authorization: key=' || fcm_api_key ] ); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER;
3. 绑定触发器到目标表
比如当orders表发生更新时触发推送:
CREATE TRIGGER trigger_order_update AFTER UPDATE ON orders FOR EACH ROW EXECUTE FUNCTION send_push_notification();
替代方案:使用Supabase Edge Functions
若不想用PostgreSQL函数,可基于Deno编写Edge Function处理:
- 创建Edge Function(示例TypeScript代码):
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; serve(async (req) => { const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")! ); const { userId } = await req.json(); const { data: devices } = await supabase .from("user_devices") .select("device_token") .eq("user_id", userId); if (devices && devices.length > 0) { await fetch("https://fcm.googleapis.com/fcm/send", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `key=${Deno.env.get("FCM_API_KEY")}` }, body: JSON.stringify({ to: devices[0].device_token, notification: { title: "数据更新", body: "你的相关内容已变更" } }) }); } return new Response(JSON.stringify({ status: "success" }), { headers: { "Content-Type": "application/json" }, }); });
- 创建触发器调用该Edge Function:
CREATE OR REPLACE FUNCTION call_edge_function() RETURNS TRIGGER AS $$ BEGIN PERFORM http_post( '你的Edge Function URL', json_build_object('userId', NEW.user_id)::TEXT, ARRAY['Content-Type: application/json'] ); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_data_change AFTER INSERT ON your_table FOR EACH ROW EXECUTE FUNCTION call_edge_function();
注意事项
- 推送服务密钥需存入Supabase环境变量,避免硬编码
- 需处理令牌失效场景,比如FCM返回无效令牌时,从
user_devices表删除对应条目 - 批量变更场景需考虑性能,避免频繁调用推送API
内容的提问来源于stack exchange,提问作者tailor
相关产品推荐
相关产品推荐

