Android客户端离线后再上线,如何接收FCM已发送的消息?
解决FCM离线消息接收问题
咱们先把问题根源理清楚:你当前发送的是纯Data类型的FCM消息,FCM服务器对这类消息的处理逻辑是——只有客户端在线时才会即时推送;如果客户端离线,消息只会在你设置的time_to_live(当前是120秒)有效期内等待客户端上线,一旦超时就会被直接丢弃。而且就算在有效期内客户端上线,纯Data消息的推送也依赖客户端推送服务是否能正确捕获离线期间的消息,这部分在Delphi默认组件里支持有限。
相比之下,Notification+Data混合消息会由FCM服务器负责缓存,只要在TTL有效期内,客户端上线后就会自动推送,这才是处理离线消息的最优方案。下面结合你的Delphi代码给出具体修改方案:
方案1:切换为Notification+Data混合消息(推荐)
修改服务端的JSON消息结构,加入notification字段,让FCM服务器帮你缓存离线消息:
procedure TForm2.SendClick(Sender: TObject); var R: IHTTPResponse; M: TBytesStream; o: THTTPClient; J: TJSONObject; A: TBytes; S: string; begin Memo1.Lines.Clear; // 新增notification字段,同时保留data字段用于自定义业务数据 // 把time_to_live延长到1天(86400秒),可根据需求调整 S := '{"to":"token","time_to_live":86400,"notification":{"title":"test title","body":"test body"},"data":{"custom_key":"custom_value"}}'; M := TBytesStream.Create; o := THTTPClient.Create; try J := TJSONObject.ParseJSONValue(S) as TJSONObject; if Assigned(J) then begin try A := TEncoding.UTF8.GetBytes(J.ToString); M.Write(A, Length(A)); M.Position := 0; finally J.DisposeOf; end; end; o.AcceptCharSet := 'UTF-8'; o.ContentType := 'application/json'; o.CustomHeaders['Authorization'] := 'key=FirebaseProjectServerKey'; R := o.Post('https://fcm.googleapis.com/fcm/send', M); Memo1.Lines.Add(Format('Status Code=%s' + sLineBreak + 'Status Text=%s' + sLineBreak + 'Content=%s', [R.StatusCode.ToString, R.StatusText, R.ContentAsString])); finally M.DisposeOf; o.DisposeOf; end; end;
这种混合消息的优势很明显:
- 客户端在线时,
OnReceivedNotification事件会正常触发,你可以同时拿到notification的展示内容和data里的自定义业务数据 - 客户端离线时,FCM服务器会缓存消息,直到客户端上线后自动推送,Android系统还会在托盘显示通知(无需额外代码处理)
方案2:优化纯Data消息的接收逻辑(不推荐,仅作补充)
如果你必须用纯Data消息,需要做两点调整:
- 大幅延长
time_to_live时间,给客户端足够的上线窗口 - 在客户端的
OnChange事件中,当检测到连接状态恢复时,主动触发一次消息检查(不过FCM没有提供拉取离线Data消息的API,所以这个方案可靠性很低)
比如修改服务端的time_to_live为86400秒,客户端代码里监听连接状态变化:
procedure TForm1.OnChange(Sender: TObject; AChange: TPushService.TChanges); begin Memo1.Lines.Add('Token=' + FPushService.DeviceTokenValue[TPushService.TDeviceTokenNames.DeviceToken]); // 当连接状态恢复时,可在这里添加自定义的消息拉取逻辑(如果有业务后端支持的话) if TPushService.TChanges.Connectivity in AChange then begin Memo1.Lines.Add('推送服务连接恢复,检查离线消息'); // 这里可以调用自己的后端接口,拉取客户端离线期间的消息 end; end;
额外注意事项
- 确认Firebase项目配置正确:服务端的Server Key和客户端的Sender ID必须严格匹配
- 检查Android客户端的
AndroidManifest.xml,确保包含FCM所需的权限和服务(Delphi的PushNotification组件通常会自动生成,但可以验证是否有com.google.firebase.messaging.FirebaseMessagingService相关配置) - 测试时尽量完全杀死客户端进程,发送消息后再重新打开,验证离线消息接收效果
内容的提问来源于stack exchange,提问作者lmengyew
相关产品推荐
相关产品推荐

