如何在Flutter应用中检测用户卸载并发送消息?(Firebase与私有数据库)
Flutter应用卸载检测与用户消息推送方案(基于Firebase+私有服务器)
因为Android和iOS都没有提供应用卸载的直接回调接口,所以我们只能通过间接检测机制来实现需求,核心思路是结合Firebase Cloud Messaging(FCM)的令牌有效性验证,搭配私有服务器的心跳监控来判断用户是否卸载应用。以下是具体实现步骤:
一、集成FCM并同步设备令牌到私有数据库
- 在Flutter项目中集成FCM SDK,获取每个用户的唯一设备令牌(
token)。 - 应用启动、令牌刷新时,将
用户ID、FCM令牌、最后活跃时间同步到你的私有数据库。
示例Flutter代码片段:
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:http/http.dart' as http; // 保存/更新FCM令牌到私有服务器 Future<void> syncFCMToken(String userId) async { String? token = await FirebaseMessaging.instance.getToken(); if (token == null) return; // 调用私有服务器API写入数据库 await http.post( Uri.parse('你的服务器地址/api/save-token'), body: { 'user_id': userId, 'fcm_token': token, 'last_active': DateTime.now().toIso8601String(), }, ); // 监听令牌自动刷新,实时更新 FirebaseMessaging.instance.onTokenRefresh.listen((newToken) { http.post( Uri.parse('你的服务器地址/api/update-token'), body: { 'user_id': userId, 'fcm_token': newToken, 'last_active': DateTime.now().toIso8601String(), }, ); }); }
二、私有服务器实现心跳监控与卸载检测
- 在Flutter应用中添加定时心跳任务(比如每12小时一次),调用服务器接口更新当前用户的
最后活跃时间,确保数据库中记录的用户状态是最新的。 - 服务器端设置定时扫描任务(比如每天凌晨执行):
- 筛选出
最后活跃时间超过阈值(比如48小时)的令牌记录; - 调用FCM接口向这些令牌发送静默通知(无弹窗,仅用于验证令牌有效性);
- 如果FCM返回
InvalidRegistration或NotRegistered错误,说明该令牌对应的应用已被卸载,标记用户状态为“已卸载”,并触发消息发送逻辑。
- 筛选出
示例服务器端伪代码(Node.js):
const admin = require('firebase-admin'); const db = require('./你的私有数据库连接'); // 初始化Firebase Admin admin.initializeApp({ credential: admin.credential.cert('./firebase-service-account.json'), }); // 定时检测卸载用户 async function checkUninstalledUsers() { const threshold = Date.now() - 48 * 60 * 60 * 1000; // 48小时无活跃阈值 const inactiveTokens = await db.query( 'SELECT user_id, fcm_token FROM user_tokens WHERE last_active < ?', [threshold] ); for (const { user_id, fcm_token } of inactiveTokens) { try { // 发送静默通知检测令牌有效性 await admin.messaging().send({ token: fcm_token, data: { type: 'heartbeat_check' }, apns: { payload: { aps: { contentAvailable: true } } }, // iOS静默通知配置 android: { priority: 'low' }, // Android低优先级,避免打扰用户 }); // 推送成功,更新活跃时间 await db.query( 'UPDATE user_tokens SET last_active = ? WHERE fcm_token = ?', [Date.now(), fcm_token] ); } catch (error) { // 令牌无效,判定为应用已卸载 if (['messaging/invalid-registration-token', 'messaging/registration-token-not-registered'].includes(error.code)) { // 标记用户为已卸载 await db.query('UPDATE users SET is_uninstalled = 1 WHERE id = ?', [user_id]); // 删除无效令牌 await db.query('DELETE FROM user_tokens WHERE fcm_token = ?', [fcm_token]); // 发送卸载提醒消息(比如邮件/短信) await sendUninstallAlert(user_id); } } } } // 发送卸载提醒的逻辑(示例) async function sendUninstallAlert(userId) { const user = await db.query('SELECT email FROM users WHERE id = ?', [userId]); if (user.length > 0) { // 调用你的邮件API发送提醒 await yourEmailService.send(user[0].email, '我们想念你', '欢迎重新安装我们的应用'); } } // 定时任务(比如用node-schedule每天凌晨2点执行) const schedule = require('node-schedule'); schedule.scheduleJob('0 2 * * *', checkUninstalledUsers);
三、平台特殊注意事项
- iOS:需要在Xcode中开启
Remote notifications后台权限,并且静默通知仅能在应用后台运行时接收。另外iOS用户卸载应用后,FCM令牌会快速失效,检测阈值可以设为24小时。 - Android:部分国产厂商的后台限制可能导致心跳任务无法按时执行,建议用
WorkManager实现可靠的定时任务,确保心跳请求能正常上报到服务器。
四、合规提示
发送卸载提醒前,必须确保用户已同意接收此类消息,严格遵守GDPR、CCPA等隐私法规,避免违规。
内容的提问来源于stack exchange,提问作者ff .n
相关产品推荐
相关产品推荐

