Push-уведомления XMPP вызывают проблемы (задержка + дублирование) в сообщениях

Push-уведомления XMPP вызывают проблемы (задержка + дублирование) в сообщениях.

Я успешно создал приложение для чата, используя XMPP + Ejabberd.

Без push-уведомлений:

Как одиночные, так и групповые сообщения чата работают отлично.

С помощью push-уведомлений:

Иногда все работает отлично. Уведомления срабатывают и сообщения приходят без задержек и дублирований.

Иногда уведомления не запускаются (пока приложение находится в фоновом режиме), но сообщения принимаются отлично.

Иногда уведомления срабатывают, но сообщения приходят с задержкой и с дублированием.

Все на стороне сервера настроено правильно. Они посоветовали исправить ваши проблемы, убедившись, что каждый сеанс подключается к одному постоянному ресурсу, делая соединение стабильным с использованием пробелов, а при потере соединения просто перепривязываясь к тому же ресурсу.

У меня есть управление потоком, xmppStream.enableBackgroundingOnSocket, и приложение обеспечивает включенный фоновый режим служб передачи голоса по IP.

Когда пользователь выходит из системы или приложение закрывается, я отключаю поток и отправляю сообщение о недоступном присутствии.

Ниже приведен мой код для push-уведомлений потока 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;

  }

person iYousafzai    schedule 27.01.2016    source источник
comment
вы получили push-уведомление в плохом состоянии через 60 секунд или ..?   -  person Mo Farhand    schedule 27.01.2016
comment
Какой модуль вы используете для push-уведомлений. В ejabberd Community Edition такого модуля нет. Вы используете ejabberd SaaS?   -  person Mickaël Rémond    schedule 27.01.2016
comment
Да.иногда дважды за одно сообщение.Я почти уверен, что с моим сеансом что-то не так.   -  person iYousafzai    schedule 27.01.2016
comment
@MickaëlRémond да ejabberd SaaS.   -  person iYousafzai    schedule 27.01.2016


Ответы (2)


Вам нужно убедиться, что вы передаете ресурс при подключении к ejabberd. Ресурс должен генерироваться случайным образом при первой установке приложения, и при последующем входе в систему вы всегда должны использовать один и тот же ресурс. В противном случае вы создаете новый длительный отсоединенный сеанс при каждом новом входе в систему на сервере и заставляете сообщения перенаправляться на все ожидающие сеансы. Когда срок их действия истекает, они снова направляются и т. д.

В XMPP ресурс в основном является идентификатором устройства. Вам необходимо сгенерировать JID для входа в систему со строкой формы «user@domain/resource».

person Mickaël Rémond    schedule 27.01.2016
comment
Вы имеете в виду установку следующим образом: [_xmppStream setMyJID:[XMPPJID jidWithString:jabberID]]; jabberID = user@domain/udid и когда пользователь выходит из системы, а другой пользователь позволяет, скажем, пользователю 2 войти в систему, тогда это должно быть похоже на jabberID = user2@domain/udid udid : Генерируется при первой установке. - person iYousafzai; 27.01.2016
comment
Я не рекомендую использовать udid. Просто сгенерируйте короткую случайную строку при первой установке, например, длиной от 6 до 8 символов. Что-то вроде: RX2eE7 например. Udid слишком длинные и потребляют значительно больше пропускной способности. - person Mickaël Rémond; 27.01.2016
comment
Да, я буду генерировать случайное число. Иду на тест и свяжусь с вами. Спасибо. - person iYousafzai; 27.01.2016
comment
о, чувак. Похоже, проблемы с задержкой и дублированием исчезли. Все еще есть некоторые ошибки: 1) иногда я вижу пользователя в сети, даже если я закрыл сеанс и отключился. 2) Push-уведомления получаются, когда пользователь выходит из системы. Может быть из-за этого (NSXMLElement *offline = [NSXMLElement elementWithName:@offline stringValue:@true];). - person iYousafzai; 27.01.2016
comment
Все еще сталкиваюсь с проблемами с push-уведомлениями (приложение в фоновом режиме с вошедшим в систему пользователем) @Mickaël Rémond - person iYousafzai; 27.01.2016
comment
1) иногда я вижу пользователя онлайн, даже если я закрыл сеанс и отключился. -› При нажатии, если вы хотите выйти из сети, вам нужно закрыть сеанс. Отправить сообщение о недоступности и/или явное закрытие потока (стандартный XMPP). Просто закрытие соединения поддерживает сеанс. 2) Действительно, если вы хотите офлайн-сообщение, вы получите его, когда сессия закончится. Если вы хотите удалить учетную запись пользователя с устройства, отмените регистрацию в push-уведомлениях. - person Mickaël Rémond; 28.01.2016
comment
Все еще сталкиваюсь с проблемами с push-уведомлениями (приложение в фоновом режиме с вошедшим в систему пользователем). Что ж, опишите проблему в новой проблеме Stackoverflow. Этот был адрес и ответил. - person Mickaël Rémond; 28.01.2016
comment
Большое спасибо. Вот и новый выпуск. stackoverflow.com/questions/35056452/ - person iYousafzai; 28.01.2016

вы должны уведомить управление потоком об отключении вашего сеанса и вызвать этот метод для отключения в tearDown :

    [self.stream disconnectAfterSending];
person Mo Farhand    schedule 27.01.2016
comment
Это не относится к ejabberd SaaS. - person Mickaël Rémond; 27.01.2016