# FAQ по Android SDK Pushwoosh

* [Как выглядят push-токен и HWID для Android?](#what-does-android-push-token-and-hwid-look-like)
* [Как получить push-токен моего Android-устройства?](#how-can-i-obtain-my-android-device-push-token)
* [Какие разрешения являются обязательными, а какие — необязательными?](#what-permissions-are-necessary-and-what-are-optional)
* [Как установить UserID?](#how-do-i-set-a-userid)
* [Насколько точно общее количество подписчиков на Android?](#how-accurate-is-the-total-number-of-android-subscribers)
* [Можно ли использовать HTML-теги в push-уведомлениях, отправляемых на Android?](#can-i-use-html-tags-in-pushes-sent-to-android)
* [Как установить иконку уведомления в Android Lollipop (и более поздних версиях)?](#how-to-set-a-notification-icon-in-android-lollipop-and-later-versions)
* [Использование Pushwoosh SDK с другими сервисами FCM](#using-pushwoosh-sdk-with-other-fcm-services)
* [Использование Pushwoosh с библиотеками LeakCanary или AppMetrica](#using-pushwoosh-with-leakcanary-or-appmetrica-libraries)
* [Удаление полученного уведомления с устройства](#deleting-particular-received-notifications-from-a-device)

### Как выглядят push-токен и HWID для Android?

Push-токены устройств Android различаются по длине (менее 255 символов) и начинаются с **APA91b**, например:

`APA91bFoi3lMMre9G3XzR1LrF4ZT82_15MsMdEICogXSLB8-MrdkRuRQFwNI5u8Dh0cI90ABD3BOKnxkEla8cGdisbDHl5cVIkZah5QUhSAxzx4Roa7b4xy9tvx9iNSYw-eXBYYd8k1XKf8Q_Qq1X9-x-U-Y79vdPq`

Токены часто содержат префикс, отделенный двоеточием, перед **APA91b**, например: `eQnyCE6ULAQ:APA91bGrh4ya3b_owo9tshZNVAGhZdGMGb3sA5HbM...`

Pushwoosh использует UUID в качестве HWID, то есть случайно сгенерированные строки из 32 буквенно-цифровых символов: `123e4567-e89b-12d3-a456-426655440000`

### Как получить push-токен моего Android-устройства?

Вы можете получить push-токен вашего Android-устройства в логе консоли. Используйте инструмент logcat в [Android Studio](https://developer.android.com/studio).

Откройте **monitor.bat** в `%USERPROFILE%\AppData\Local\Android\sdk\tools\monitor.bat`, подключите ваше устройство к ПК и разрешите отладку по USB в настройках Android. Запустите ваше приложение на устройстве. Найдите `/registerDevice`, найдите push-токен для вашего устройства, чтобы использовать его позже в Test Devices.

<img src="/android-push-notifications-android-faq-1.webp" alt="Скриншот, показывающий вывод logcat с информацией о регистрации push-токена в Android Studio"/>

### Какие разрешения являются обязательными, а какие — необязательными?

При установке на устройство Android приложение запросит следующие разрешения в связи с Pushwoosh SDK:

```java
<!-- FCM подключается к сервисам Firebase. -->
 <uses-permission android:name="android.permission.INTERNET"/>

<!-- Предотвращает переход процессора в спящий режим при получении сообщения. -->
 <uses-permission android:name="android.permission.WAKE_LOCK"/>

 <!-- Это разрешение используется для определения, может ли устройство получить доступ к сети. -->
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- Это приложение имеет разрешение на регистрацию и получение сообщений с данными. -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
```

Наш SDK не запрашивает разрешения на доступ к изображениям, контактам устройства и т. д.

### Как установить UserID?

Вы можете установить [идентификатор пользователя (UserID)](/ru/developer/first-steps/collecting-user-ids/), который может быть Facebook ID, именем пользователя, адресом электронной почты или любым другим уникальным идентификатором пользователя. Это позволяет сопоставлять данные и события на нескольких устройствах, связанных с одним и тем же пользователем. Чтобы установить UserID, вызовите метод **setUserId**.

**Пример**

```
Pushwoosh.getInstance().setUserId("testUser");
```

### Насколько точно общее количество подписчиков на Android?

Pushwoosh удаляет отписавшиеся Android-устройства из базы данных при получении ответа "NotRegistered" от FCM, который может быть возвращен после второй попытки связаться с конкретным устройством. Это означает, что вам нужно отправить 2 push-уведомления на отписавшееся устройство, чтобы оно было удалено из базы данных.

Ниже описан наиболее распространенный сценарий, описанный в [документации FCM](https://firebase.google.com/docs/cloud-messaging/):

1. Ваш подписчик удаляет приложение.
2. Pushwoosh отправляет сообщение на сервер FCM.
3. Сервер FCM отправляет сообщение на устройство вашего пользователя.
4. Клиент FCM на устройстве получает сообщение и обнаруживает, что ваше приложение было удалено; детали обнаружения зависят от платформы, на которой работает приложение.
5. Клиент FCM на устройстве информирует сервер FCM о том, что приложение было удалено.
6. Сервер FCM помечает регистрационный ID для удаления.
7. Pushwoosh отправляет еще одно сообщение в FCM.
8. FCM возвращает сообщение NotRegistered.
9. Pushwoosh удаляет push-токен из вашей пользовательской базы.

Может потребоваться некоторое время, чтобы регистрационный ID был полностью удален из FCM. Таким образом, возможно, что сообщение, отправленное на шаге 7, получит в ответ действительный ID сообщения, даже если сообщение не будет доставлено в клиентское приложение.

### Можно ли использовать HTML-теги в push-уведомлениях, отправляемых на Android?

Да, в Android вы можете использовать следующие HTML-теги для изменения внешнего вида push-уведомления:

```txt
<span style="color: green;"><b><i><span style="text-decoration: underline;">Hello world!
Hello hi hey</span></i></b></span>
```

Разместите эти HTML-теги в поле ввода **Message** и используйте их также в API-запросе. Некоторые устройства Android могут неверно обрабатывать эти HTML-теги, но большинство устройств отображают форматирование правильно.

### Как установить иконку уведомления в Android Lollipop (и более поздних версиях)?

В Android Lollipop иконки были изменены и стали только белыми. Поэтому, если вы выберете **targetSdkVersion >= 21** в вашем файле **AndroidManifest.xml**, Android будет использовать только альфа-канал иконки.\
Подробнее о поведении см. в [документации Android](https://developer.android.com/docs).

Система игнорирует все не-альфа каналы в иконках действий и в основной иконке уведомления. Предполагайте, что эти иконки будут только с альфа-каналом. Система рисует иконки уведомлений белым цветом, а иконки действий — темно-серым. _Это находится вне контроля Pushwoosh SDK_.

**1.** Создайте иконку уведомления в соответствии с [рекомендациями Android](https://material.io/design/platform-guidance/android-notifications.html#style). Согласно [документации](https://developer.android.com/about/versions/lollipop/android-5.0-changes), система проигнорирует все цвета.

**2.** Назовите иконку `pw_notification.png` и поместите ее в папку **res/drawable**. Pushwoosh SDK будет использовать эту иконку по умолчанию для уведомлений.

**3.** В качестве альтернативы вы можете использовать Remote API и установить значение параметра `"android_icon"` равным изображению иконки (без расширения файла).

### Использование Pushwoosh SDK с другими сервисами FCM

Вы можете использовать Pushwoosh вместе с другими SDK, которые используют FCM для push-сообщений. Для этого создайте сервис-маршрутизатор для распределения событий между сервисами. Сначала добавьте зависимость **pushwoosh-firebase** вместе с основным модулем Pushwoosh:

```groovy title="build.gradle"
implementation 'com.pushwoosh:pushwoosh-firebase:6.0.3'
```

Создайте класс маршрутизации:

<Tabs>
<TabItem label="FirebaseMessagingRouterService.kt">
```kotlin
import com.pushwoosh.firebase.PushwooshFcmHelper;

class FirebaseMessagingRouterService : FirebaseMessagingService() {

    override fun onNewToken(token: String?) {
        super.onNewToken(token)
        PushwooshFcmHelper.onTokenRefresh(token)
        sendTokenToAnotherService(token)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        if (PushwooshFcmHelper.isPushwooshMessage(remoteMessage)) {
           //this is a Pushwoosh push, SDK will handle it automatically
            PushwooshFcmHelper.onMessageReceived(this, remoteMessage)
        } else {
            //this is not a Pushwoosh push, you should handle it by yourself
            dispatchNonPushwooshMessage(remoteMessage);
        }
    }

    private fun dispatchNonPushwooshMessage(remoteMessage: RemoteMessage) {
       // Implement your push handling logics here
   }
}
```
</TabItem>

<TabItem label="FirebaseMessagingRouterService.java">
```java
import com.pushwoosh.firebase.PushwooshFcmHelper;

public class FirebaseMessagingRouterService extends FirebaseMessagingService {

    @Override
    public void onNewToken(String token) {
        super.onNewToken(token);
        PushwooshFcmHelper.onTokenRefresh(token);
        sendTokenToAnotherService(token);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        if (PushwooshFcmHelper.isPushwooshMessage(remoteMessage)) {
            //this is a Pushwoosh push, SDK will handle it automatically
            PushwooshFcmHelper.onMessageReceived(this, remoteMessage);
        } else {
            //this is not a Pushwoosh push, you should handle it by yourself
            dispatchNonPushwooshMessage(remoteMessage);
        }
    }

    private void dispatchNonPushwooshMessage(RemoteMessage remoteMessage) {
        // Implement your push handling logics here
    }
}
```
</TabItem>
</Tabs>

Зарегистрируйте маршрутизаторы в вашем AndroidManifest.xml:

```txt title="AndroidManifest.xml"
<service
    android:name=".FirebaseMessagingRouterService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
```

### Использование Pushwoosh с библиотеками LeakCanary или AppMetrica

Когда вы интегрируете инструменты аналитики, такие как LeakCanary, AppMetrica или другие, эти библиотеки запускают новый процесс, создавая новый экземпляр приложения. Поскольку вы не можете слушать push-уведомления в другом процессе, это приводит к возникновению `java.lang.NullPointerException`.

Если вы вызываете `registerForPushNotifications` внутри `Application.onCreate()`, вам следует проверить, находитесь ли вы в основном процессе приложения. Используйте следующий код для выполнения этой проверки:

```java
List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
if (runningAppProcesses != null && runningAppProcesses.size() != 0) {
    for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
        boolean isCurrentProcess = runningAppProcessInfo.pid == android.os.Process.myPid();
        boolean isMainProcessName = getPackageName().equals(runningAppProcessInfo.processName);
        if (isCurrentProcess && isMainProcessName) {

            Pushwoosh.getInstance().registerForPushNotifications(...);
            break;
        }
    }
}
```

### Локальное удаление определенных полученных уведомлений с устройства

Если вы хотите удалить неактуальное push-уведомление при выполнении определенного действия внутри вашего приложения, вы можете использовать следующий подход:

```java title="MainActivity.java"
public class MainActivity extends AppCompatActivity {

	List<NotificationCreatedEvent> savedPushes = new ArrayList<>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Pushwoosh.getInstance().registerForPushNotifications();

		PushwooshNotificationSettings.setMultiNotificationMode(true);

		findViewById(R.id.clear_button).setOnClickListener( v -> {
			cancelPushes();
		});

		EventBus.subscribe(NotificationCreatedEvent.class, event -> {
			try {
				if (event.getMessage().getCustomData() == null)
					return;

				//cancel pushes only with a specific flag
				if (new JSONObject(event.getMessage().getCustomData()).getBoolean("cancel")) {
					savedPushes.add(event);
				}
			} catch (JSONException e) {
			}
		});
	}
	private void cancelPushes() {
		NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

		if (manager == null) {
			return;
		}

		for (NotificationCreatedEvent event : savedPushes) {
			manager.cancel(event.getMessageTag(), event.getMessageId());
		}
	}
}
```

## Поделитесь с нами своим мнением

Ваши отзывы помогают нам создавать лучший опыт. Если вы столкнулись с какими-либо трудностями в процессе интеграции SDK, поделитесь своими мыслями с нами [через эту форму](https://docs.google.com/forms/d/e/1FAIpQLSd_0b8jwn-V_JmoPLIxIFYbHACCQhrzidOZV3ELywoQPXRSxw/viewform).