Pull to refresh

Comments 44

didRegisterForRemoteNotificationsWithDeviceToken: возвращает ниакак не строку, а 32 байта бинарных данных. Потом эти 32 байта участвуют в коммуникации с сервером APN.
И именно по этой причине при NSLog объекта NSData с бинарными данными, он выводится заключённый в "<" и ">" и пробелами, разделяющие каждые 4 байта.

Отчистка токена вообще простая:

appToken = [[appToken stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];

В одну строку кода.
Спасибо. Опимизация это всегда хорошо.
А еще лучше -substringWithRange
Range надо вычислять или использовать «magic numbers», я сторонник гибкости и даже если Apple изменит по каким-то причинам длинну получаемого токена, подход с тримом сработает сам по себе.
а если description у NSData изменится? и вместо угловых скобок и пробелов появятся другие паразитные символы?
Не появятся, так с покон веков NSString выводил NSData
Статья немного вводит в заблуждение:
Токен приходит в бинарном виде и в бинарном виде используется в протоколе APN. То, что автор решил получить из него строку — это лишь его проблема.

Пруф из документации:
image
не то слово. такое ощущение, что rtfm никто не осуществляет. нашел либу пхпшную и давай туда совать что не попадя. а, вот это подошло и ок
Я не знаю как давно Вы занимаетесь программированием, но подскажите мне пожалуйста как Вы передадите NSData в PHP, так чтобы PHP, это дальше тоже передал как NSData?
Ваша компетенция оставляет желать лучшего. Уж простите. Не в «пхп», а в http-запросе. Как завернуть бинарные данные — универсальный способ — base64, в данном случае, вы нашли библиотечку на пхп, в нее надо сунуть строку в хексах, вы нашли самый небезопасный способ это сделать. Молодец. А если бы не нашли библиотеку, то глядишь, узнали бы побольше о протоколе хттп, узнали бы как устроен протокол пуш-уведомлений (а он простой как копейка) и были бы сейчас на моем месте и ставили бы минусы сами себе.
Нда. тогда у меня к вам вопрос. если данные бинарные, регистр символов играет роль?
Вы ещё скажите, что вы отправляете токен методом POST? Перед этим упаковав его base64.
Если Вы так хорошо разбираетесь, тогда напишите свою статью, где все это будет описано, как надо по уму. Либо можете предложить как дополнить, чтобы было как надо. Тогда это будет конструктивно.
Ох… Ну какой к чертям регистр символов в бинарных данных?! Регистр нулей и единиц?
По поводу токена, я вам уже говорил, что передаю его в виде строки хексов, как и вы. И говорю конструктивно еще раз: ликвидируйте метод description из вашего кода. Уберите вот этот ужас:

 NSMutableString *tokenString = [NSMutableString stringWithString:  
                                    [[deviceToken description] uppercaseString]];  
    [tokenString replaceOccurrencesOfString:@"<"  
                                 withString:@""  
                                    options:0  
                                      range:NSMakeRange(0, tokenString.length)];  
    [tokenString replaceOccurrencesOfString:@">"  
                                 withString:@""  
                                    options:0  
                                      range:NSMakeRange(0, tokenString.length)];
    [tokenString replaceOccurrencesOfString:@" "  
                                 withString:@""  
                                    options:0  
                                      range:NSMakeRange(0, tokenString.length)];     
    NSLog(@"Token: %@", tokenString);  


Хотите сериализовать бинарные данные как строку из хексов — пишите это явно, хотите base64 — тоже пишите явно. Ну нельзя делать приложение зависящим от метода description, поведение которого может измениться в любой момент. И про который в документации сказано «Returns an NSString object that contains a hexadecimal representation of the receiver’s contents.» Угловые скобки и пробелы не документированы, разумеется, поскольку метод предназначен не для того, чтобы конвертировать двоичные данные в хекс строку.
И я имел ввиду именно PHP, http в даном случае только траспорт. а PHP все равно какой тип переменной, NSData или NSString.
нет, вы имели в виду не PHP, а конкрентное приложение, на нем написанное. И это приложение требует сериализовать бинарный токен в побайтовый хекс. Если бы оно потребовало base64 и POST — сделали бы как миленький.
Давайте не будем дальше спорить, уберите бяку из статьи. Избавьтесь от фраз типа:

«При старте приложения вызывается метод didRegisterForRemoteNotificationsWithDeviceToken который, если есть подключение к интернет возвращает 64 символьную строку Token. С этой стройкой есть нюанс: она почему-то приходит с символами «<» и «>» в начале и конце и пробелами в средине. Поэтому стоит почистить строку от этих символов.»

… которые демонстрируют полное ваше непонимание происходящего. В этот метод передается 32-байтный токен в бинарном виде. 64 байта получатся если взять побайтный хекс в строковом представлении. Но использовать для этого description не следует. Не учите новичков, на которых ориентирован ваш текст, применять архитектурные решения, смысла которых они не понимают.
Самое удивительное, что cohe4ko кто-то плюсует… Слов нет, мало, что кто-то не разбирается в нюансах, так его в этом еще и поддерживают…
Самое удивительное, что те, кто «разбираются в нюансах» только критикуют.
Если Вам что либо не нравится, напишите статью и опишите «как надо».
Тогда люди смогут выбрать и мне поставят минусы, а вам — плюсы.
Но всегда проще потреблять и критиковать чем что-либо давать.
Причем тут это? Я искренне признателен Вам за статью, с удовольствием прочитал, поставил плюсик.

Просто не понимаю, почему дельное и обоснованное замечание Вы не принимаете. Оно же поможет сделать Вашу статью лучше и точнее. Не понимаю почему Вы так яростно отстаиваете свою ошибку.
Пришлите мне ссылку на Вашу статью, где будет написано как это сделать, и я лично, и всех своих друзей на хабре попрошу Вам кармы накинуть, и плюсовать буду.
Ну что за детский сад?! Плюсы, карма, друзей попрошу. Никто Вам минусы никуда не ставил и в карму не гадил. Минусы ставите Вы. Вам же просто указали на неточности. Ответили на невысказнный вопрос: «С этой стройкой есть нюанс: она почему-то приходит с символами «<» и «>» в начале и конце и пробелами в средине.». Сказали откуда эти паразитные символы и что никто не гарантирует в дальнейшем от появления других паразитных символов. Указали как надо сделать, чтобы гарантированно все работало.
Хочу отметить, что при переключении между Development и Production environment необходимо чистить список всех девайсов. Apple рвет коннекшн без объяснения причин (если не использовать extended схему), если айди девайса оказался невалидным или от другого приложения/сертификата. Так можно запросто запороть отправку пушей, если кто-то отправил по URL неправильный токен. К сожалению, подводных камней там более чем хватает.

Рекомендую посмотреть еще топик — habrahabr.ru/blogs/mobiledev/130381/
Поясните, зачем выбрасывать из токена символы скобок и пробел?
потому что серверу Apple надо слать чистую строку. Можно конечно это делать на стороне сервера. Но я делал это в приложении.
Апупеть. Аппловское апи возвращает токен, который надо послать аппловскому же серверу для регистрации. При этом надо самому ручками лишнее из токена выбросить. Это не по-аппловски, как минимум. Зачем лишние символы в строке, убей меня бог не пойму. Или что-то не знаю.
Причина в форматах.
Apple приылает NSData а отправляем скрипту NSString во время преобразования появляются пробелы и скобки. вот и все. Можно было бы какими-то путями отправлять в виде NSData, но так проще.
Э-э… Да, deviceToken — это бинарные данные. И посылать его надо строкой хексов каждого байта. По крайнем мере я так понял из документации, которую когда-то читал.

const char* data = [deviceToken bytes];
NSMutableString* token = [NSMutableString string];
 
for (int i = 0; i < [deviceToken length]; i++) {
[token appendFormat:@"%02.2hhX", data[i]];
}
Нееееет :-) здесь Вы не правы.
отсылать его надо просто как строку, не хексовой, а простой строкой.
Как минимум у меня так точно работает.
приведенный мной код тоже работает. Мне кажется странным, как и многоуважаемому PapaBubaDiop, зачем нужно выбрасывать символы из токена. Вот сходил сейчас специально и почитал документацию: «The device returns the device token to the requesting application as an NSData object. The application then must then deliver the device token to its provider in either binary or hexadecimal format. ». Заметьте, никакие скобки никто выбрасывать не просит.
Я с Вами согласен. Но есть нюанс. Как Вы через URL будете передавать PHP NSData?
У PHP такого нету.
Если бы мы отправляли как-то по-другому — тогда наверное были бы варианты.
Вы посмотрите внимательно. Я вам привел код преобразования бинарного токена в строку, которую можно передать в http-запросе. Ваш же код основан на методе description у NSData, который возвращает хекс-строку в угловых скобках с пробелами после каждых двух символов. И вы их вырезаете. Однако никто вам не гарантирует, что через год такое поведение description останется неизменным.
Так «binary format» в итоге должен будет разобраться скриптом и отправится строкой или хексом на сервера APNю Дело в том, что «provider» в этой фразе — это фаш сервер, который потом набрав батч для отправки подымает коннект и пушит туда все накопленные для батча сообщениями.
Я знаю. Если бы я ни разу не реализовывал пуш, я бы тут не писал :)
устройство должно передать на сервер идентификатор токена, который является 32-байтным набором бинарных данных. Далее сервер шлет это в службу пуш-аведомлений эппл. Достаточно один раз на устройстве преобразовать это хозяйство в хекс-строку и далее всюду ее передавать без каких-либо транформаций. О чем явно написано в документации. Тут предлагается использовать метод [NSData description] — он возвращает хекс строку соответствующую бинарным данным, заключенную в угловые скобки и содержащую пробелы после каждого байта. Затем оттуда удаляются скобки и пробелы — и вуаля — хекс строка. Возникает 2 вопроса:
1) а если формат выдачи description изменится?
2) почему не сделать сразу по-человечески?
1) Сомнительно та и смысл каков, функционального ничего не изменится.
2) По-человечески — это с созданием ещё одной переменной и циклом с применением формата на каждом байте? Не знаю, может и такое хорошо.
1) блажен, кто верует
2) а description по-вашему как работает? Вы же делаете еще больше работы. Это все равно, что я сейчас в цикле напишу + ' ' на каждой итерации, а потом все эти пробелы вырежу.
Бред какой-то
Упертость страшная вещь. rafuck говорит правильные вещи, но видимо люди любят переписывать код при каждом апдейте sdk.
Спасибо за статью, оказалась как нильзя кстати. Только-что начал разбираться с APN.
Я правильно понимаю, что Токен нужно получать каждый раз при запуске приложения и каждый раз отправлять новый Токен для запоминания Серверу?
Нет, он выдается каждый раз тот самый.
Даже если удалить приложение, а потом снова установить всё равно токен будет тот самый.
Вы написали еще про механизм для чистки базы токенов от адресов, которые уже не действительны. А можно немного осветить этот момент, что за база токенов?
 Вам же токены нужно где-то сохранять? Лучше всего это делать в базе данных. Например, MySQL.
Но если внести в базу просто — в примере это описано, то удалить из базы это проблемма. Потому что, если проиложение удалил пользователь, он же вам не сообщает «мне больше ничего не шлите». Для этого нужно периодично опрашивать сервер Apple, он выдает список устаревших токенов. Их то и нужно удалить из своей базы.
Спасибо, теперь понял о чем речь.
Токен всегда надо запрашиватиь, т.к. он может сменится в любой момент!

Из доков: «If the user restores backup data to a new device or reinstalls the operating system, the device token changes.»

И это далеко не единственный случай, когда токен может сменится.
Небольшое замечание по коду:
Нет необходимости делать вызов [connection start], так как connectionWithRequest:delegate: делает это внутри себя.
Еще мелкий фикс по предложенному исходнику:

NSURL *registrationURL = [NSURL URLWithString:[NSString stringWithFormat:
urlFormat, tokenString]];


пропущена вторая закрывающая скобка "]" в конце.
Sign up to leave a comment.

Articles