【问题标题】:XMPP push notifications causing problems (delay + duplications) in messagesXMPP 推送通知导致消息中出现问题(延迟 + 重复)
【发布时间】:2016-05-04 06:56:18
【问题描述】:

XMPP 推送通知会导致消息出现问题(延迟 + 重复)。

我已经使用 XMPP + Ejabberd 成功创建了一个聊天应用程序。

没有推送通知:

单人聊天和群聊消息都运行良好。

使用推送通知:

有时一切都完美无缺。触发通知并接收消息,没有任何延迟或重复。

有时不会触发通知(当应用程序在后台时),但可以完美接收消息。

有时会触发通知,但收到的消息有延迟和重复。

服务器端的所有内容都已正确配置。他们建议通过确保每个会话连接到一个持久性资源、使用空白保持连接稳定连接以及在连接丢失时重新绑定相同的资源来解决您的问题。

我有流管理、xmppStream.enableBackgroundingOnSocket 和 App 提供启用 IP 语音服务的后台模式。

当用户注销或应用程序终止时,我会关闭流并发送不可用的状态。

下面是我的 xmpp 流推送通知和连接/断开的代码。

我正在为此拔头发。如果你们有任何想法,请告诉我。

谢谢。

#pragma mark - Connect/Disconnect

- (BOOL)connect {

if (!_xmppStream) {
    NSLog(@"Setting up Stream");
    [self setupStream];
}

if (![_xmppStream isDisconnected]) {
    return YES;
}

NSString *jabberID = [[NSUserDefaults standardUserDefaults] stringForKey:@"userID"];
NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:@"userPassword"];


if (jabberID == nil || myPassword == nil) {
    return NO;
}
[_xmppStream setMyJID:[XMPPJID jidWithString:jabberID]];
_password = myPassword;

NSError *error = nil;

if (![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error]){

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[NSString stringWithFormat:@"Can't connect to server! %@", [error localizedDescription]] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    [alert show];
    return NO;
}
 return YES;
 }

- (void)disconnect {

[self goOffline];
[self teardownStream];

}

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {

  [self goOnline];

//Stream Management

NSXMLElement *enable = [NSXMLElement elementWithName:@"enable" xmlns:@"urn:xmpp:sm:3"];
[enable addAttributeWithName:@"resume" stringValue:@"true"];
[_xsm.xmppStream sendElement:enable];

//Push
[self configurePushNotifications];
//

}

-(void)configurePushNotifications{

NSString *jabberID = [[NSUserDefaults standardUserDefaults] stringForKey:@"userID"];

NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
[iq addAttributeWithName:@"type" stringValue:@"set"];
[iq addAttributeWithName:@"id" stringValue:idString];

NSXMLElement *push = [NSXMLElement elementWithName:@"push" xmlns:@"p1:push"];

NSXMLElement *keepalive = [NSXMLElement elementWithName:@"keepalive"];
[keepalive addAttributeWithName:@"max" integerValue:30];

NSXMLElement *session = [NSXMLElement elementWithName:@"session"];
[session addAttributeWithName:@"duration" integerValue:60];

NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
[body addAttributeWithName:@"send" stringValue:@"all"];
[body addAttributeWithName:@"groupchat" stringValue:@"true"];
[body addAttributeWithName:@"from" stringValue:jabberID];

NSXMLElement *status = [NSXMLElement elementWithName:@"status"];
[status addAttributeWithName:@"type" stringValue:[NSString stringWithFormat:@"New message from %@",jabberID]];

NSXMLElement *offline = [NSXMLElement elementWithName:@"offline" stringValue:@"true"];

[push addChild:keepalive];
[push addChild:session];
[push addChild:body];
[push addChild:status];
[push addChild:offline];

NSXMLElement *notification = [NSXMLElement elementWithName:@"notification"];
[notification addChild:[NSXMLElement elementWithName:@"type" stringValue:@"applepush"]];
[notification addChild:[NSXMLElement elementWithName:@"id" stringValue:_userDeviceToken]];

[push addChild:notification];

NSXMLElement *appid = [NSXMLElement elementWithName:@"appid" stringValue:@"appid"];

[push addChild:appid];

[iq addChild:push];

[[self xmppStream] sendElement:iq];


 }

- (void)setupStream {

_xmppStream = [[XMPPStream alloc] init];
_xmppStream.hostName = kHostName;
_xmppStream.hostPort = kHostPort;
_xmppStream.enableBackgroundingOnSocket = YES;
[_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];

//XMPPReconnect

_xmppReconnect = [[XMPPReconnect alloc] init];
[_xmppReconnect activate:_xmppStream];

//Stream Management

_xsm = [[XMPPStreamManagement alloc] init];
[_xsm enableStreamManagementWithResumption:YES maxTimeout:0];
[_xsm activate:_xmppStream];

//Last Activity

_xmppLastActivity = [[XMPPLastActivity alloc] initWithDispatchQueue:dispatch_get_main_queue()];
[_xmppLastActivity addDelegate:self delegateQueue:dispatch_get_main_queue()];
[_xmppLastActivity activate:_xmppStream];

 }

 - (void)goOnline {
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
 }

 - (void)goOffline {
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[[self xmppStream] sendElement:presence];
}

- (void)teardownStream {

[_xmppStream disconnect];

[_xmppStream removeDelegate:self];
[_xmppReconnect removeDelegate:self];

[_xmppLastActivity removeDelegate:self];

[_xmppReconnect deactivate];


_xmppStream = nil;
_xmppReconnect = nil;
_xmppLastActivity = nil;

  }

【问题讨论】:

  • 您是否在 60 秒后收到状态不佳的推送通知?
  • 您使用哪个模块进行推送通知。 ejabberd 社区版中没有这样的模块。您在使用 ejabberd SaaS 吗?
  • 是的。有时一条消息两次。我很确定我的会话有问题。
  • @MickaëlRémond 是的 ejabberd SaaS。

标签: xmpp apple-push-notifications ejabberd xmppframework ejabberd-saas


【解决方案1】:

您需要确保在连接到 ejabberd 时传递了资源。该资源应在首次应用安装和后续登录时随机生成,您应始终使用相同的资源。否则,您会在服务器上的每个新登录时创建一个新的长时间运行的分离会话,并导致消息被路由到所有挂起的会话。当这些过期时,它们会再次路由等等。

在 XMPP 中,资源基本上是设备的标识符。您需要使用“user@domain/resource”形式的字符串生成用于登录的 JID

【讨论】:

  • 你的意思是这样设置:[_xmppStream setMyJID:[XMPPJID jidWithString:jabberID]]; jabberID = user@domain/udid 并且当用户注销并且另一个用户说用户 2 登录时,它应该类似于 jabberID = user2@domain/udid udid :在首次安装时生成。
  • 我不建议使用 udid。只需在首次安装时生成一个简短的随机字符串,如 6 到 8 个字符长。例如:“RX2eE7”。 Udid 太长,会占用更多带宽。
  • 是的,我会生成一个随机数。去测试,会回复你。谢谢。
  • 哦,伙计。看起来延迟和重复问题已经消失了。还有一些错误:1) 有时我可以看到用户在线,即使我已经关闭会话并断开连接。 2)用户注销时收到推送通知。可能是因为这个(NSXMLElement *offline = [NSXMLElement elementWithName:@"offline" stringValue:@"true"];)。
  • 仍然面临推送通知的问题(应用程序在后台登录用户)@MickaëlRémond
【解决方案2】:

您应该通知流管理断开您的会话并 在tearDown 中调用此方法断开连接:

    [self.stream disconnectAfterSending];

【讨论】:

  • 这对 ejabberd SaaS 无效。
猜你喜欢
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
  • 2023-03-06
相关资源
最近更新 更多