Ionic 2+Firebase应用在前后台/关闭状态下监听数据库变更及WebRTC咨询
嘿,刚好我之前做过类似的Ionic + Firebase + WebRTC项目,来给你拆解下这个问题的核心解决方案,分三部分说清楚:
一、Firebase数据库变更全状态监听(前台/后台/杀死)
要覆盖所有状态,单纯靠Firebase Realtime Database的原生监听是不够的,得结合FCM(Firebase Cloud Messaging)和系统后台权限来实现:
- 前台状态:直接用Firebase的
on('child_added')监听就行,在Ionic的服务或页面组件里初始化监听逻辑,这部分你应该已经在做了,没啥坑。 - 后台状态:
- 先装
cordova-plugin-background-mode插件,让应用在后台保持活跃,避免被系统直接挂起。 - 注意iOS和Android的差异:Android允许后台进程保持网络连接,iOS则需要配置后台模式(比如勾选Xcode里的“Remote notifications”或“Voice over IP”)。
- 为了避免监听延迟,建议同时用FCM做辅助:当数据库有
child_added事件时,后端(或发起方)主动给目标设备发送FCM数据消息,应用后台收到消息后再主动拉取数据库变更,确保不会漏接。
- 先装
- 杀死状态:
这时候应用进程完全没了,只能靠FCM数据消息(不是通知消息)来唤醒。配置步骤:- 用支持后台消息处理的FCM插件(比如
cordova-plugin-fcm-with-dependency-updated)。 - 在插件的后台消息回调里,编写逻辑唤醒应用的核心服务,然后从Firebase数据库读取最新的
child_added数据进行处理。
- 用支持后台消息处理的FCM插件(比如
二、WebRTC通话在应用关闭状态下的运作逻辑
这部分和WhatsApp的思路一致,核心是用FCM(iOS用VoIP推送)唤醒应用,通过Firebase传递WebRTC信令,具体步骤:
1. 发起方流程
- 当用户发起通话时,先在Firebase数据库的
/calls节点写入通话请求数据:包含对方ID、本地SDP、ICE候选、通话类型(音频/视频)等,标记状态为initiated。 - 同时给对方发送FCM推送(iOS必须用VoIP推送,Android用数据消息),附带通话请求的唯一ID。
2. 接收方流程(关闭/后台状态)
- iOS端:VoIP推送会直接唤醒应用的后台进程(不需要用户点击通知),系统会触发
PushKit的回调,你在回调里初始化WebRTC的PeerConnection,从Firebase读取通话请求的SDP和ICE,设置本地媒体流(后台状态下iOS只允许音频,视频需要用户打开应用后再请求权限),然后把自己的SDP和ICE写回Firebase的对应通话节点。 - Android端:FCM数据消息会唤醒后台服务,你在服务里初始化WebRTC连接,同样从Firebase读取信令数据,返回自己的信令,然后可以弹出系统级的来电通知(用
cordova-plugin-local-notification),用户点击后打开应用进入通话界面。
3. 关键注意事项
- iOS必须用VoIP推送:普通推送无法在应用杀死状态下唤醒进程并建立实时连接,VoIP推送是苹果专门为通话类应用开放的通道,需要在Xcode里配置
PushKit权限,用对应的Ionic插件(比如cordova-plugin-voip-push-notification)。 - Android后台权限:需要申请
FOREGROUND_SERVICE权限,并且把处理通话的逻辑放在前台服务里,避免被系统的内存管理机制杀死。 - 信令管理:一定要在Firebase数据库里维护通话状态(发起、接通、挂断、超时),避免重复推送或者连接异常,比如发起方如果超过30秒没收到接收方的回应,就标记通话为
failed。 - WebRTC ICE配置:用稳定的ICE服务器,比如Google的免费服务器:
const iceServers = [ { urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' } ];
三、Ionic 2里的核心代码片段
FCM后台消息处理
import { FCM } from '@ionic-native/fcm/ngx'; import { AngularFireDatabase } from '@angular/fire/database'; constructor(private fcm: FCM, private db: AngularFireDatabase) { // 后台消息回调(应用杀死状态触发) this.fcm.onBackgroundMessage().subscribe(async (data) => { if (data.type === 'call_request') { // 从Firebase读取通话请求详情 const callData = await this.db.object(`/calls/${data.callId}`).valueChanges().toPromise(); // 初始化WebRTC连接 this.initWebRTCConnection(callData); // Android弹出来电通知 this.showIncomingNotification(callData); } }); }
WebRTC连接初始化
initWebRTCConnection(callData) { const peerConnection = new RTCPeerConnection({ iceServers: iceServers }); // 添加远程SDP peerConnection.setRemoteDescription(new RTCSessionDescription(callData.remoteSDP)); // 添加ICE候选 callData.iceCandidates.forEach(candidate => { peerConnection.addIceCandidate(new RTCIceCandidate(candidate)); }); // 创建本地SDP并写回Firebase peerConnection.createAnswer().then(answer => { peerConnection.setLocalDescription(answer); this.db.object(`/calls/${callData.id}`).update({ localSDP: answer }); }); // 监听ICE候选,实时同步到Firebase peerConnection.onicecandidate = (event) => { if (event.candidate) { this.db.list(`/calls/${callData.id}/iceCandidates`).push(event.candidate); } }; // 监听远程媒体流 peerConnection.ontrack = (event) => { // 播放远程音频/视频 this.remoteStream = event.streams[0]; }; }
内容的提问来源于stack exchange,提问作者AppFirl
相关产品推荐
相关产品推荐

