Ни одно современное мобильное приложение сейчас не обходится без пуш уведомлений - сообщений, рассылаемых сервером на устройства клиентов. Google предоставляет сервис Cloud Messaging (GCM) для рассылки уведомлений на устройства Android.
Здесь будет рассказано, как интегрировать поддержку GCM в свое приложение.
(Реализация на серверной стороне будет рассмотрена отдельно)
Реализация GCM включает в себя 3 составляющих:
1. Сервер приложения, с которого исходят уведомления;
2. Мобильное устройство, которое принимает уведомления;
3. GCM серверы, которые отправляют сообщения с сервера приложения на мобильные устройства.
Для разработки понадобиться:
1. Установить Google Play services SDK, если он еще не установлен у вас. Инструкция по установке здесь.
2. Подключить Google Play Services для GCM в приложении, добавив строчку compile 'com.google.android.gms:play-services-gcm:7.5.0' в Gradle. Так же убедитесь, что все ссылки на Google Play Services в Gradle имеют одинаковую версию, иначе вы не сможете запустить отладку. Инструкция здесь.
3. Создать приложение в Google Developer Console и активировать в нем GCM API, как описано здесь. Это забота серверной стороны. Клиентскому приложению нужен только номер созданного приложения из Google Developer Console. Если вы создаете только клиентское приложение, уточните этот номер у разработчика серверной части.
Добавьте следующие строчки в manifest приложения:
1. <uses-permission android:name="android.permission.INTERNET" />
Для того, чтобы приложение могло отправить идентификатор устройства на сервер.
2. <uses-permission android:name="android.permission.WAKE_LOCK" />
Предотвращает засыпание процессора во время приема сообщений.
4. <permission android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
Нужен для запрета другим приложениям принимать уведомления создаваемого приложения.
Здесь нужно заменить com.example.gcm на имя пакета вашего приложения.
5. <uses-permission android:name="android.permission.GET_ACCOUNTS" />
Было в описании, но не сказано, для чего нужно.
Здесь будет рассказано, как интегрировать поддержку GCM в свое приложение.
(Реализация на серверной стороне будет рассмотрена отдельно)
Архитектура
Реализация GCM включает в себя 3 составляющих:
1. Сервер приложения, с которого исходят уведомления;
2. Мобильное устройство, которое принимает уведомления;
3. GCM серверы, которые отправляют сообщения с сервера приложения на мобильные устройства.
Перед началом работы
Для разработки понадобиться:
1. Установить Google Play services SDK, если он еще не установлен у вас. Инструкция по установке здесь.
2. Подключить Google Play Services для GCM в приложении, добавив строчку compile 'com.google.android.gms:play-services-gcm:7.5.0' в Gradle. Так же убедитесь, что все ссылки на Google Play Services в Gradle имеют одинаковую версию, иначе вы не сможете запустить отладку. Инструкция здесь.
3. Создать приложение в Google Developer Console и активировать в нем GCM API, как описано здесь. Это забота серверной стороны. Клиентскому приложению нужен только номер созданного приложения из Google Developer Console. Если вы создаете только клиентское приложение, уточните этот номер у разработчика серверной части.
Редактирование файла Manifest
Добавьте следующие строчки в manifest приложения:
1. <uses-permission android:name="android.permission.INTERNET" />
Для того, чтобы приложение могло отправить идентификатор устройства на сервер.
2. <uses-permission android:name="android.permission.WAKE_LOCK" />
Предотвращает засыпание процессора во время приема сообщений.
3. <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
Для разрешения приложению регистрировать и принимать сообщения4. <permission android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
Нужен для запрета другим приложениям принимать уведомления создаваемого приложения.
Здесь нужно заменить com.example.gcm на имя пакета вашего приложения.
5. <uses-permission android:name="android.permission.GET_ACCOUNTS" />
Было в описании, но не сказано, для чего нужно.
Полная инструкция здесь.
Чтобы удостовериться, что клиент и сервер приложения могут обмениваться сообщениями, они должны выполнить процедуру "рукопожатия". Для этого каждое устройство приобретает уникальный идентификационный токен, который нужно отправить на сервер приложения. Сервер сохраняет его и в дальнейшем использует для отправки уведомлений на соответствующие устройства.
Токен будем хранить в Shared Preferences. Так же нужно хранить информацию о том, отправлен токен на сервер или нет. Сначала напишем методы для этого:
// Имя Shared Preferences
private static final String SHARED_PREF_NAME = "Preferences";
// Ключ токена
private static final String PREF_DEVICE_TOKEN = "DeviceToken";
// Флаг, отвечающий за то, отправлен токен на сервер или нет
private static final String PREF_DEVICE_TOKEN_SENT = "DeviceTokenSent";
// Возвращает Shared Preferences
public static SharedPreferences getSharedPreferences(Context context) {
return context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
}
// Сохраняет токен в Shared Preferences
public static void setDeviceToken(Context context, String deviceToken) {
SharedPreferences sp = getSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PREF_DEVICE_TOKEN, deviceToken);
editor.commit();
}
// Достает токен из Shared Preferences
public static String getDeviceToken(Context context) {
SharedPreferences sp = getSharedPreferences(context);
return sp.getString(PREF_DEVICE_TOKEN, null);
}
// Возвращает true, если токен отправлен на сервер
public static boolean isDeviceTokenSent(Context context) {
SharedPreferences sp = getSharedPreferences(context);
return sp.getBoolean(PREF_DEVICE_TOKEN_SENT, false);
}
// Задает флаг, отправлен токен на сервер или нет
public static void setDeviceTokenSend(Context context, boolean sent) {
SharedPreferences sp = getSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(PREF_DEVICE_TOKEN_SENT, sent);
editor.commit();
}
Теперь пишем метод для создания и сохранения токена устройства. Для получения токена на мобильном устройстве используется Instance ID API:
Регистрация устройства
Чтобы удостовериться, что клиент и сервер приложения могут обмениваться сообщениями, они должны выполнить процедуру "рукопожатия". Для этого каждое устройство приобретает уникальный идентификационный токен, который нужно отправить на сервер приложения. Сервер сохраняет его и в дальнейшем использует для отправки уведомлений на соответствующие устройства.
Токен будем хранить в Shared Preferences. Так же нужно хранить информацию о том, отправлен токен на сервер или нет. Сначала напишем методы для этого:
// Имя Shared Preferences
private static final String SHARED_PREF_NAME = "Preferences";
// Ключ токена
private static final String PREF_DEVICE_TOKEN = "DeviceToken";
// Флаг, отвечающий за то, отправлен токен на сервер или нет
private static final String PREF_DEVICE_TOKEN_SENT = "DeviceTokenSent";
// Возвращает Shared Preferences
public static SharedPreferences getSharedPreferences(Context context) {
return context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
}
// Сохраняет токен в Shared Preferences
public static void setDeviceToken(Context context, String deviceToken) {
SharedPreferences sp = getSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PREF_DEVICE_TOKEN, deviceToken);
editor.commit();
}
// Достает токен из Shared Preferences
public static String getDeviceToken(Context context) {
SharedPreferences sp = getSharedPreferences(context);
return sp.getString(PREF_DEVICE_TOKEN, null);
}
// Возвращает true, если токен отправлен на сервер
public static boolean isDeviceTokenSent(Context context) {
SharedPreferences sp = getSharedPreferences(context);
return sp.getBoolean(PREF_DEVICE_TOKEN_SENT, false);
}
// Задает флаг, отправлен токен на сервер или нет
public static void setDeviceTokenSend(Context context, boolean sent) {
SharedPreferences sp = getSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(PREF_DEVICE_TOKEN_SENT, sent);
editor.commit();
}
Теперь пишем метод для создания и сохранения токена устройства. Для получения токена на мобильном устройстве используется Instance ID API:
// Номер проекта в Google Developer Console
public final static String PROJECT_NUMBER = "111233456789";
// Пространство для получение токена. Равно строке "GCM"
public final static String SCOPE = GoogleCloudMessaging.INSTANCE_ID_SCOPE;
// Возвращает токен устройства.
// Если его еще не существует, то создает его и сохраняет в Shared Preferences
public static String createDeviceToken(Context context) {
String token = getDeviceToken(context);
if(token == null) {
token = InstanceID.getInstance(context).getToken(PROJECT_NUMBER, SCOPE, null);
setDeviceToken(context, token);
}
return token;
}
Номер проекта можно найти во вкладке Overview:
Метод getToken в Instance ID API является долгой операцией, следовательно createDeviceToken должен быть выполнен в отдельном потоке.
// Отправляет токен на сервер.
// Если токена не существует, создает его.
public static void createAndSendDeviceToken(final Context context) {
// Если токен уже отправлен на сервер, то ничего не делаем
if(isDeviceTokenSent(context)) {
return;
}
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
return createDeviceToken(context)
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (s != null) {
sendTokenToServer(s);
} else {
// Действие при ошибке
}
}
}.execute();
}
Осталось реализовать отправку токена на сервер в методе sendTokenToServer. Если токен успешно отправлен, запомните это вызовом метода setDeviceTokenSend(context, true);
// Пространство для получение токена. Равно строке "GCM"
public final static String SCOPE = GoogleCloudMessaging.INSTANCE_ID_SCOPE;
// Возвращает токен устройства.
// Если его еще не существует, то создает его и сохраняет в Shared Preferences
public static String createDeviceToken(Context context) {
String token = getDeviceToken(context);
if(token == null) {
token = InstanceID.getInstance(context).getToken(PROJECT_NUMBER, SCOPE, null);
setDeviceToken(context, token);
}
return token;
}
Номер проекта можно найти во вкладке Overview:
Метод getToken в Instance ID API является долгой операцией, следовательно createDeviceToken должен быть выполнен в отдельном потоке.
// Отправляет токен на сервер.
// Если токена не существует, создает его.
public static void createAndSendDeviceToken(final Context context) {
// Если токен уже отправлен на сервер, то ничего не делаем
if(isDeviceTokenSent(context)) {
return;
}
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
return createDeviceToken(context)
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (s != null) {
sendTokenToServer(s);
} else {
// Действие при ошибке
}
}
}.execute();
}
Осталось реализовать отправку токена на сервер в методе sendTokenToServer. Если токен успешно отправлен, запомните это вызовом метода setDeviceTokenSend(context, true);