基于Angular/Ionic+Capacitor Jitsi插件的Firebase来电通知实现咨询
基于Angular/Ionic + Firebase实现来电通知的核心思路
一、基础环境准备
- 完成Angular/Ionic项目与Firebase的集成,重点配置Firebase Cloud Messaging(FCM),安装Capacitor相关插件:
@capacitor/push-notifications:处理FCM消息接收@capacitor/local-notifications:创建带交互按钮的自定义来电通知
- 确保Jitsi插件已正常集成,能通过房间ID发起/加入通话
二、来电发起端逻辑
- 获取被叫方的FCM令牌:提前将用户的FCM令牌存储到Firebase数据库,发起通话时根据被叫方ID查询对应令牌
- 发送FCM数据消息:通过Firebase Cloud Functions(或自建后端)向被叫方发送数据消息(而非普通通知消息,确保后台能拦截处理),消息需包含关键参数:
type: 'incoming_call':标记为来电通知roomId:Jitsi通话房间IDcallerName:发起方昵称callType:语音/视频通话类型
三、被叫端接收与交互处理
- 后台拦截FCM消息:即使APP在后台或被杀死,监听
pushNotificationReceived事件,识别来电类型的消息 - 创建带按钮的本地通知:调用
LocalNotifications.schedule生成来电通知,配置接听、拒绝两个动作按钮,同时将roomId等参数存入通知的extra字段 - 处理按钮点击事件:
- 接听:唤醒APP(通过
foreground: true配置),跳转到自定义通话页面,自动初始化Jitsi并加入目标房间 - 拒绝:调用Firebase Cloud Functions向发起端发送拒绝状态消息,更新发起端界面显示通话被拒绝
- 接听:唤醒APP(通过
四、通话状态同步
- 拒绝/超时处理:发起端监听Firebase实时数据库或Cloud Functions的状态回调,收到拒绝信号后结束通话请求;若被叫方超时未响应,自动终止通话发起
- 通话中状态:接听成功后,双方更新Firebase数据库中的通话状态,避免重复发送通知
关键代码示例
1. Firebase Cloud Functions发送来电消息
const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(); exports.sendCallNotification = functions.https.onCall(async (data, context) => { const { recipientToken, roomId, callerName, callType } = data; const message = { token: recipientToken, data: { type: 'incoming_call', roomId, callerName, callType }, android: { priority: 'high', notification: { title: `${callerName} 来电`, body: callType === 'video' ? '视频通话' : '语音通话' }, channelId: 'call_notifications' }, apns: { payload: { aps: { contentAvailable: true, sound: 'default' } }, headers: { 'apns-priority': '5' } } }; await admin.messaging().send(message); return { success: true }; });
2. 被叫端处理来电通知
import { PushNotifications } from '@capacitor/push-notifications'; import { LocalNotifications } from '@capacitor/local-notifications'; export class CallNotificationService { constructor() { this.initListeners(); } async initListeners() { // 监听FCM来电消息 await PushNotifications.addListener('pushNotificationReceived', async (notification) => { if (notification.data.type === 'incoming_call') { const { roomId, callerName, callType } = notification.data; // 注册通知动作按钮 await LocalNotifications.registerActionTypes({ types: [{ id: 'call_actions', actions: [ { id: 'accept', title: '接听', foreground: true }, { id: 'reject', title: '拒绝', foreground: true } ] }] }); // 生成来电本地通知 await LocalNotifications.schedule({ notifications: [{ id: Date.now(), title: `${callerName} 来电`, body: callType === 'video' ? '视频通话' : '语音通话', sound: 'default', actionTypeId: 'call_actions', extra: { roomId, callerName, callType } }] }); } }); // 监听通知按钮点击 await LocalNotifications.addListener('localNotificationActionPerformed', async (action) => { const { roomId, callType } = action.notification.extra; if (action.actionId === 'accept') { // 跳转到通话页面并加入Jitsi房间 window.location.href = `/call?roomId=${roomId}&type=${callType}`; } else if (action.actionId === 'reject') { // 发送拒绝信号给发起端 this.sendRejectionSignal(action.notification.extra.callerName); } }); } private async sendRejectionSignal(callerName: string) { // 调用Cloud Functions发送拒绝消息逻辑 } }
注意事项
- Android需配置高优先级通知渠道,确保来电通知能弹出;iOS需开启推送权限与后台远程通知、音频模式
- FCM数据消息需设置高优先级,保证APP在后台时能及时接收
- Jitsi房间ID需唯一,通话结束后可设置过期时间或销毁房间
内容的提问来源于stack exchange,提问作者Giamma
相关产品推荐
相关产品推荐

