Это будет последняя часть этого урока, которая уже была довольно завершена в предыдущем разделе. У нас могут быть дополнительные взносы, в основном для покрытия улучшений, таких как «пригласить друга» и другие подобные возможности, но это, вероятно, такое же хорошее место, как и любое другое, чтобы закончить приложение и позволить вам попробовать его вживую.
Родной толчок
До сих пор мы использовали PubNub для реализации функциональности push, что отлично, особенно если вы выбираете платную опцию, которая также может сохранять сообщения и предлагает довольно много дополнительных привилегий для такого приложения, как это. Тем не менее, когда приложение не работает, PubNub не может что-либо выдвинуть, и в этом случае для отправки сообщения нам понадобится собственное нажатие ОС.
Очевидный вопрос: «Почему бы не использовать встроенную поддержку ОС для всего?».
Это возможно, но встроенная поддержка ОС не такая гибкая, портативная, быстрая и надежная, как PubNub. С ним больно работать, и пользователь может преднамеренно или непреднамеренно прервать его, не согласившись с приглашением операционной системы и т. Д. Как вы увидите из оставшейся части учебника, где мы возвращаемся к принудительной загрузке собственной ОС, когда PubNub не может достичь нашей цели, ее нет панацеи
Интерфейс PushCallback
Мы начнем с реализации интерфейса PushCallback
в нашем основном классе, это должен быть фактический основной класс, иначе push не будет работать:
1
|
public class SocialChat implements PushCallback { |
Затем нам нужно реализовать следующие методы:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Override public void push(String value) { // its a JSON message, otherwise its a notice to the user if (value.startsWith( "{" ) || value.startsWith( "[" )) { try { JSONObject obj = new JSONObject(value); // this is still early since we probably didn't login yet so add the messages to the list of pending messages java.util.List<Message> pendingMessages = (java.util.List<Message>)Storage.getInstance().readObject( "pendingMessages" ); if (pendingMessages == null ) { pendingMessages = new ArrayList<>(); } Message m = new Message(obj); pendingMessages.add(m); Storage.getInstance().writeObject( "pendingMessages" , pendingMessages); addMessage(m); } catch (JSONException err) { err.printStackTrace(); } } } @Override public void registeredForPush(String deviceId) { } @Override public void pushRegistrationError(String error, int errorCode) { } |
Вы заметите следующие вещи здесь:
- Нам ничего не нужно в
registeredForPush
pushRegistrationError
илиpushRegistrationError
. Поскольку мы используем PubNub, даже если push не работает, приложение все равно будет работать нормально.Push.getPushKey()
обычно используется для получения нажимной клавиши (которая не является аргументом, переданным этому методу, этоPush.getPushKey()
) и отправляет его на ваши серверы, чтобы вы могли инициировать нажатие на это устройство. Так как здесь у нас нет реального сервера, мы не используем этот метод. - Метод
push
делает тяжелую обработку push-сообщений. Он может быть вызван в любое время и принимает обратные вызовы. Он получает как видимые, так и скрытые push-сообщения и решает, что с ними делать, основываясь на их содержимом. - Мы не показываем сообщение во время обратного вызова. Он будет вызван до того, как пользователь успел войти в систему, поэтому мы хотим просто сохранить объекты
Message
и обработать их позже. Мы по-прежнему добавляем их в общий магазин на тот случай, если пользователь решит убить приложение, прежде чем войти в систему.
Новые константы и регистрация
Нам нужно добавить следующие переменные в класс, чтобы продолжить, я замаскировал и изменил значения. Мы рассмотрим их один за другим:
1
2
3
4
5
6
7
8
|
private static final String PUSH_TOKEN = "********-****-****-****-*************" ; private static final String GCM_SENDER_ID = "99999999999999" ; private static final String GCM_SERVER_API_KEY = "******************-********************" ; private static final boolean ITUNES_PRODUCTION_PUSH = false ; private static final String ITUNES_PRODUCTION_PUSH_CERT_PASSWORD = "ProdPassword" ; private static final String ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD = "DevPassword" ; |
PUSH_TOKEN
является самым простым, просто войдите в Codename One и выберите вкладку учетной записи. Он должен появиться прямо над кнопкой « Update Details
. Если его там нет, попробуйте выйти и снова войти в систему.
Вы можете очень легко получить GCM_SENDER_ID
& GCM_SERVER_API_KEY
от Google. Это предполагает, что вы следовали нашим инструкциям по созданию проекта Google во второй части руководства. Если вы пропустили это (поскольку вам не требовалось входить в учетную запись G +), просто создайте новый проект в консоли API Google на основе инструкций в части 2.
Чтобы сгенерировать их, просто перейдите на https://developers.google.com/mobile/add и нажмите «выбрать платформу»:
Выберите «Android App»
Введите данные для приложения и пакета
Нажмите «Облачные сообщения», затем нажмите «Включить Google Cloud Messaging».
Теперь у вас должны быть значения для GCM_SENDER_ID
и GCM_SERVER_API_KEY
как показано ниже
Благодаря нашему новому мастеру сертификатов генерация части этих флагов для iOS теперь совершенно легкая!
Мы просто пройдем через мастер сертификатов и отметим флаг, чтобы включить push:
Включить толчок мастера
После завершения работы мастера и проверки флажка включения push убедитесь, что в разделе iOS также установлен флажок «Включить push». В текущем плагине есть ошибка, когда он не включается автоматически.
Вы должны получить инструкции по отправке по электронной почте, которые должны содержать ссылки, которые вы можете просто вставить на место, и пароли. Это должно быть довольно легко.
Другие изменения кода
Когда вы нажимаете на устройство, вам нужно иметь ключ устройства, который является уникальным идентификатором устройства, на которое вы хотите отправить push. К сожалению, поскольку у нас нет сервера, нам нужно как-то передать этот ключ от человека, с которым мы общаемся. Хитрость заключается в том, чтобы встроить этот ключ в объект Message и, таким образом, обновить его при получении сообщения. Это означает, что мы можем отправить push-сообщение только тому человеку, который писал нам в прошлом. Неплохая особенность всего и вся, но все же ограничение …
Для этого нам нужно сделать два простых изменения в классе Message
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public Message(JSONObject obj) { try { time = Long.parseLong(obj.getString( "time" )); senderId = obj.getString( "fromId" ); recepientId = obj.getString( "toId" ); message = obj.getString( "message" ); name = obj.getString( "name" ); picture = obj.getString( "pic" ); // update the push id for the given user if (obj.has( "pushId" )) { String pushId = obj.getString( "pushId" ); if (pushId != null ) { Preferences.set( "pid-" + senderId, pushId); } } } catch (JSONException ex) { // will this ever happen? Log.e(ex); } } public JSONObject toJSON() { String pushId = Push.getPushKey(); if (pushId != null ) { JSONObject obj = createJSONObject( "fromId" , senderId, "toId" , recepientId, "name" , name, "pic" , picture, "time" , Long.toString(System.currentTimeMillis()), "message" , message, "pushId" , pushId); return obj; } JSONObject obj = createJSONObject( "fromId" , senderId, "toId" , recepientId, "name" , name, "pic" , picture, "time" , Long.toString(System.currentTimeMillis()), "message" , message); return obj; } |
Это эффективно добавляет push-идентификатор к каждому отправляемому нами сообщению, если оно доступно, и обновляет push-идентификатор контактов для использования позже.
Теперь нам нужно зарегистрироваться для push, в конце метода start()
в SocialChat.java
добавим:
1
2
3
4
5
6
7
8
|
// let the login form show before we register the push so the permission screen doesn't appear on a white // background Display.getInstance().callSerially(() -> { // registering for push after the UI appears Hashtable args = new Hashtable(); args.put(com.codename1.push.Push.GOOGLE_PUSH_KEY, GCM_SENDER_ID); Display.getInstance().registerPush(args, true ); }); |
Мы делаем это таким образом, чтобы пользовательский интерфейс появился первым.
Ранее в методе showChatForm
мы только что отправили сообщение через PubNub, теперь мы хотим, чтобы был запасной вариант, который отправит сообщение с помощью push. Для этого нам нужно знать, что сообщение не было получено другой стороной. Чтобы обнаружить, что теперь мы добавляем в PubNub ответное сообщение под названием «ACK», которое будет подтверждать получение сообщения, если ACK не получен, это означает, что сообщение должно быть отправлено с помощью собственного push… Для этого мы добавляем класс поле:
1
2
3
4
|
/** * Includes messages that received ACK notices from the receiver */ private ArrayList<String> pendingAck = new ArrayList<>(); |
Мы автоматически удаляем ACK в методе listenToMessages
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private void listenToMessages() { try { pb = new Pubnub( "pub------------------------------" , "sub-------------------------------" ); pb.subscribe(tokenPrefix + uniqueId, new Callback() { @Override public void successCallback(String channel, Object message, String timetoken) { if (message instanceof String) { pendingAck.remove(channel); return ; } Message m = new Message((JSONObject)message); pb.publish(tokenPrefix + m.getSenderId(), "ACK" , new Callback() {}); Display.getInstance().callSerially(() -> { addMessage(m); respond(m); }); } }); } catch (PubnubException err) { Log.e(err); Dialog.show( "Error" , "There was a communication error: " + err, "OK" , null ); } } |
В методе showChatForm
нам нужно использовать showChatForm
к push, это немного большой метод, поэтому я showChatForm
здесь только соответствующий раздел:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
final Message messageObject = new Message(tokenPrefix + uniqueId, tokenPrefix + d.uniqueId, imageURL, fullName, text); JSONObject obj = messageObject.toJSON(); String pid = Preferences.get( "pid-" + tokenPrefix + d.uniqueId, null ); if (pid != null ) { // if we have a push address for the contact we can send them a push if they aren't reachable... UITimer timeout = new UITimer(() -> { if (pendingAck.contains(tokenPrefix + d.uniqueId)) { pendingAck.remove(tokenPrefix + d.uniqueId); // send two messages, one hidden with the data as JSON for parsing on the client // the other one visible with the text that should appear to the user who isn't running // the app, this will allow him to launch the app and then receive the hidden message immediately // within the app String cert = ITUNES_DEVELOPMENT_PUSH_CERT; String pass = ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD; if (ITUNES_PRODUCTION_PUSH) { cert = ITUNES_PRODUCTION_PUSH_CERT; pass = ITUNES_PRODUCTION_PUSH_CERT_PASSWORD; } if (Push.sendPushMessage(PUSH_TOKEN, text + ";" + obj.toString(), ITUNES_PRODUCTION_PUSH, GCM_SERVER_API_KEY, cert, pass, 3 , pid)) { t.getUnselectedStyle().setOpacity( 255 ); t.repaint(); addMessage(messageObject); } else { chatArea.removeComponent(t); chatArea.revalidate(); Dialog.show( "Error" , "We couldn't reach " + d.name + " thru push" , "OK" , null ); } } }); timeout.schedule( 10000 , false , write.getComponentForm()); if (!pendingAck.contains(tokenPrefix + d.uniqueId)) { pendingAck.add(tokenPrefix + d.uniqueId); } } |
Как это работает, довольно просто:
- Если у нас есть идентификатор push, то мы создаем 10 секундный таймер
- Когда таймер истекает, мы проверяем, находится ли pendingAck в ожидании, если это так, мы должны отступить, чтобы нажать
- У нас есть кнопка устройства из класса
Message
выше, поэтому отправка push-сообщения довольно проста относительно - Мы отправляем push типа 3, который включает в себя как видимую, так и невидимую полезную нагрузку, разделенную двоеточием (;). Видимая полезная нагрузка — это просто текст сообщения, тогда как невидимая полезная нагрузка — это строка JSON, которую мы хотим добавить в базу данных сообщений.
И это в значительной степени это для приложения чата!
Последнее слово
- Вы можете проверить окончательный исходный код этого руководства здесь, window = ”_ blank” .
Когда я начинал с этого урока, я еще не был знаком с интеграцией Parse для Codename One. После того, как я немного поиграл с ним и был бы поражен этим, я бы спроектировал все это приложение поверх него и немного упростил процесс. Это также позволило бы мне отслеживать сохраненные сообщения push ID и устранять некоторые проблемы, возникающие при переходе между PubNub / native push.
Я бы все еще использовал PubNub без сомнения! Это удивительно и очень удобно для быстрой пуш-сети. Я думаю, что объединение с Parse сделало бы это приложение намного лучше.
Вход в систему через Google / Facebook и т. Д. Был, вероятно, самой болезненной частью приложения, и я включаю push-уведомление в набор трудностей. Хотя это намного проще, чем раньше, и проще, чем нативная / веб-версии, я думаю, что основная проблема заключается в непрозрачности сетей и желании держать разработчиков близко. Боль меньше с нашей стороны и больше от утомительного создания приложений и передачи значений в Facebook / Google. Ключ хэша APK просто болезненный, были такие вещи, как «пригласить друга», которых я просто избегал из-за скуки.
Я мог бы сделать переписку с учетом этих мыслей, но я более склонен повторить это как cn1lib, а не как приложение. Основной мотивацией является поддержка приложений конечными пользователями, поэтому разработчики могут общаться с пользователями по вопросам, интегрируя в наше приложение одну cn1lib. Я не уверен, что у меня будет время разобраться с чем-то подобным, но я думаю, что это должно быть относительно легко, так как большая часть больших ресурсов (push, облачное хранилище и т. Д.) Уже обрабатывается этими замечательными сторонними сервисами.
Другие сообщения в этой серии
Это непрерывная серия постов, включающая следующие части:
- Часть 1 — Начальный интерфейс
- Часть 2 — Войти через Google
- Часть 3 — Войти через Facebook
- Часть 4 — Форма контактов
- Часть 5 — Форма чата
- Часть 6 — Родной Push & Finishing Up
Ссылка: | Создание приложения для чата с кодовым названием One Part 6 — Codename One от нашего партнера JCG Шая Альмога из блога Codename One . |