You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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消息,需要做两点调整:

  1. 大幅延长time_to_live时间,给客户端足够的上线窗口
  2. 在客户端的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:42:15