# Интеграция в мобильные приложения Android (v4)

В данной статье представлена подробная инструкция по интеграции **Webim Mobile SDK** версии **4.0** в ваше Android-приложение. C исходным кодом **Webim Mobile SDK** можно ознакомиться в [репозитории](https://github.com/webim/webim-android-sdk-demo), публикации Android package загружаются в [репозиторий Maven](https://mvnrepository.com/artifact/ru.webim.sdk/webimclientsdkandroid).

Публичный пакет SDK — `ru.webim.android.sdk`. Минимальная версия Android — **API 21** (Android 5.0).

!!! Note "N.B."
    При использовании **Webim Mobile SDK** без готового виджета отображение и обработка ссылок в интерфейсе чата выполняются на стороне приложения.

!!! Note "Линия 4.0"
    Этот раздел описывает **Mobile SDK 4.0.x**. Чтобы Gradle не подтянул более новую мажорную линию `4.1`, фиксируйте зависимость как `4.0.0` или `4.0.+`, а не `4.+`.

## Шаг 1. Установка библиотеки Webim Mobile SDK

  1. Откройте файл `build.gradle` приложения (модуля).
    Укажите адрес репозитория и добавьте следующий код:

    ```
    repositories {
        mavenCentral()
    }

    dependencies {
        ...
        implementation 'ru.webim.sdk:webimclientsdkandroid:4.0.+'
    }
    ```

    Для того, чтобы изменения применились, необходимо синхронизировать проект.
    Например, в **Android Studio** можно нажать **Sync Now** или выбрать в меню **File → Sync Project with Gradle Files**. Дождитесь окончания синхронизации.

    Если синхронизация завершилась успешно, при компиляции библиотека будет добавлена в проект автоматически. При ошибке компиляции, убедитесь что вы правильно указали репозиторий и зависимость и синхронизируйте проект снова.

  1. Для корректной работы SDK укажите его версию в файле `gradle.properties`, добавив параметр:

     ```
     sdkVersionName=4.0.0
     ```

    Замените `4.0.0` на фактическую используемую версию линии **4.0.x**.

  1. Редактируйте файл `AndroidManifest.xml`.
    Для работы SDK в корень `manifest` необходимо добавить разрешение на сеть:

    ```
    <uses-permission android:name="android.permission.INTERNET"/>
    ```

    Разрешения на внешнее хранилище (`READ_EXTERNAL_STORAGE` / `WRITE_EXTERNAL_STORAGE`) и `WAKE_LOCK` относятся к сценариям приложения (выбор файлов, удержание устройства активным), а не к обязательному минимуму библиотеки. История чата в SDK 4.0 хранится в локальной базе приложения (SQLCipher), данные посетителя — в зашифрованных `SharedPreferences`, если вы не передали собственные настройки методом [`setVisitorDataPreferences`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#set-visitor-data-preferences).

---

## Что нового в Mobile SDK 4.0

Версия **4.0** опирается на **Webim Server 10.8+** для полного набора функций, включая облегчённый режим и endpoint счётчиков непрочитанных. Минимальная заявленная версия сервера — `10.5.30`; подробности — в [информации о выпусках](https://webim.ru/kb/mobile/sdk/v-4-0/android-release-notes.html).

Кратко:

  * **Облегчённый режим** — [`SessionBuilder.setLightModeEnabled(true)`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#set-light-mode-enabled): сокращённый сетевой цикл без полного long poll (см. [раздел справочника](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#mobile-sdk-40-light-mode-and-counters)).

  * **Счётчики непрочитанных** — [`MessageStream.getInfo(GetInfoListener)`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#get-info) и [`GetInfoResponse`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#get-info-response): запрос к API сводной информации (`l/v/m/info` или URL из **meta** на сервере 10.8+).

  * **HTTP-заголовки** — [`SessionBuilder.setRequestHeader`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#set-request-header) при создании сессии и [`WebimSession.setRequestHeaders`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#set-request-headers) для уже созданной сессии.

  * **Push-уведомления.** Поддерживаются [`PushSystem.FCM`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#remote-notification-system) и [`PushSystem.HPK`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#remote-notification-system) (Huawei Push Kit). Система **GCM** и методы `parseGcmPushNotification` / `getGcmSenderId` / `setGCMSenderId` в SDK 4.0 **отсутствуют**. Разбор FCM-уведомления — [`Webim.parseFcmPushNotification`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#parse-fcm-push-notification).

  * **Резервные домены облака.** [`SessionBuilder.setExtraDomains`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#set-extra-domains) задаёт запасные хосты на случай недоступности основного; по умолчанию SDK использует `webim2.ru` и `webim.chat`.

Подробные сигнатуры — в [справочнике](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html).

---

## Шаг 2. Работа с Webim Mobile SDK

### Работа с сессией { #work-with-session }

После внедрения зависимости в приложение необходимо создать сессию. Сессия в **Webim Mobile SDK** является отдельной сущностью от `VisitSession`, которая реализуется на **Webim Server**.

Сессией называют сеанс, в течение которого приложение взаимодействует с сервисом. В текущей версии SDK он получает любую информацию от **Webim Server** только в рамках сессии. До её создания SDK не получит с сервера никакой информации.
Началом сессии считается выполнение метода `resume()`, а завершением — выполнение метода `destroy()`, либо аварийная остановка приложения.

![ ](https://webim.ru/kb/img/mobile/sdk/v-4-0/android-integration/sdk-methods.svg)

Но для того, чтобы начать выполнять действия с сессией, необходимо сначала создать объект сессии.

  1. **Создание сессии**. Объект сессии создаётся методом `newSessionBuilder` класса **Webim**, который возвращает объект класса-строителя `SessionBuilder` (оба класса и их методы описаны в файле `Webim.java`). После задания всех необходимых параметров на созданном объекте `SessionBuilder` вызывается метод `build()`, который возвращает объект `WebimSession`. Пример использования:

    ```
    WebimSession webimSession = Webim.newSessionBuilder()
        .setContext(this)
        .setAccountName(ACCOUNT_NAME)
        .setLocation(LOCATION_NAME)
        .build();
    ```

    Поле `ACCOUNT_NAME` должно соответствовать имени аккаунта, если чат размещён в облачной конфигурации (на серверах **Webim** — см. [Сетевые конфигурации сервиса Webim](https://webim.ru/kb/devops/webim-network-configurations.html)). Если же чат размещён на серверах заказчика, то вместо него должен быть указан полный URL (пример: `https://chat.company.local`).

    Поле `LOCATION_NAME` содержит наименование размещения. Если в нём указать несуществующее значение, то обращение будет в размещении `default`.

    Вызов метода `build()` завершает установку начальных параметров и создаёт сессию в приостановленном виде. Метод необходимо вызывать из потока с `android.os.Looper` (обычно главный поток приложения); дальнейшая работа с сессией ведётся из того же потока.

    Описание всех параметров, которые можно задать при создании сессии, а также ошибок, которые могут возникать в процессе, можно найти в [справочнике](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#session-builder). Обязательными являются контекст, имя аккаунта и размещение (`setContext`, `setAccountName`, `setLocation`). Без контекста `build()` выбрасывает `IllegalArgumentException`.

    Если не заданы поля авторизованного посетителя (`setVisitorFieldsJson` или предоставленный токен), сессия будет создана в неавторизованной зоне, тем не менее, это будет персональный чат.

  1. **Методы сессии**. Ниже описаны базовые методы, которые необходимо вызывать при работе с объектом сессии.

    | Метод                           | Описание                                                                                                                                                                                                                                                                                                                                                                     | Следующий метод                                                                               |
    | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
    | `resume`                        | После создания объекта сессии необходимо вызвать метод `resume()`, который запустит сетевую активность сессии. После ответов сервера могут быть вызваны методы интерфейсов `MessageListener`, `ChatStateListener`, `CurrentOperatorChangeListener` и `LocationSettingsChangeListener`. Этот метод также используется для возобновления сессии после вызова метода `pause()`. | `pause()`<br>`destroy()`<br>`destroyWithClearVisitorData()`                                   |
    | `pause()`                       | Метод, который используется для приостановки сетевой активности сессии (например, когда пользователь не находится в активном окне приложения). Если сессия уже находится в приостановленном состоянии, метод не произведёт никаких действий.                                                                                                                                 | `resume()`<br>`destroy()`<br>`destroyWithClearVisitorData()`                                  |
    | `destroy()`                     | Метод, который используется для деактивации сессии и экземпляра класса.                                                                                                                                                                                                                                                                                                      | После вызова данного метода никакие методы, относящиеся к сессии, использованы быть не могут. |
    | `destroyWithClearVisitorData()` | Метод, который используется для деактивации сессии и экземпляра класса с удалением информации о пользователе.                                                                                                                                                                                                                                                                | После вызова данного метода никакие методы, относящиеся к сессии, использованы быть не могут. |

    Примеры использования:

    ```
    public class MainActivity extends AppCompatActivity {
      private WebimSession session;
      private static final String ACCOUNT_NAME = "account";
      private static final String LOCATION_NAME = "mobile";
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          webimSession = Webim.newSessionBuilder()
              .setContext(this)
              .setAccountName(ACCOUNT_NAME)
              .setLocation(LOCATION_NAME)
              .build();
      }
      protected void onStart() {
          super.onStart();
          session.resume();
      }
      protected void onResume() {
          super.onResume();
          session.resume();
      }
      protected void onPause() {
          super.onPause();
          session.pause();
      }
      protected void onDestroy() {
          session.destroy();
          super.onDestroy();
      }
    }
    ```

---

### Установка интерфейсов

Для функционирования приложения на базе SDK обязательна реализация всех перечисленных ниже интерфейсов. Для использования методов интерфейса необходимо, чтобы сессия не находилась в приостановленном или деактивированном виде.

  1. `MessageStream` необходим для непосредственного взаимодействия с сервисом **Webim** (например, для отправки или получения сообщений). Возвращается методом `getStream()` экземпляра `WebimSession`. Примеры использования:

    * Отправить сообщение

        ```  
        session.getStream().sendMessage(message);
        ```

    * Удалить сообщение

        ```
        session.getStream().deleteMessage(message, callback);
        ```

    * Отследить изменения оператора текущего чата

        ```
        session.getStream().setCurrentOperatorChangeListener(
                new MessageStream.CurrentOperatorChangeListener() {
                @Override
                public void onOperatorChanged(@Nullable Operator oldOperator,
                                        @Nullable Operator newOperator) {
        //your code
               }
           });
        ```

    * Отследить изменения статуса сессии

        ```
        session.getStream().setVisitSessionStateListener(
                new MessageStream.VisitSessionStateListener() {
                @Override
                public void onStateChange(@NonNull MessageStream.VisitSessionState previousState,
                                        @NonNull MessageStream.VisitSessionState newState) {
        //your code
                }
            });
        ```

    * Отследить изменения состояния текущего чата

        ```
        session.getStream().setChatStateListener(
                new MessageStream.ChatStateListener() {
                @Override
                public void onStateChange(@NonNull MessageStream.ChatState oldState,
                                        @NonNull MessageStream.ChatState newState) {
        //your code
                }
            });
        ```

    Список всех методов, а также более подробную информацию о них можно найти в описании метода [`MessageStream`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#message-stream).

  1. `MessageListener` необходим для получения изменений в потоке сообщений. Его методы вызываются автоматически при осуществлении действий с сообщениями в чате: при добавлении сообщения, удаления сообщения, удаления всех сообщений и изменении сообщения, соответственно. В пользовательском приложении необходим класс, который реализует методы данного интерфейса: `messageAdded(Message, Message)`, `messageRemoved(Message)`, `allMessagesRemoved()`, `messageChanged(Message, Message)`.

    Пример использования:

    ```
    public class MainActivity extends AppCompatActivity {
        private WebimSession session;
        private ListController listController;
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            webimSession = Webim.newSessionBuilder()
                .setContext(this)
                .setAccountName(ACCOUNT_NAME)
                .setLocation(LOCATION_NAME)
                .build();
            initChatView(rootView);
        }
        private void initChatView(View rootView) {
            RecyclerView recyclerView = rootView.findViewById(R.id.chat_recycler_view);
            listController = ListController.install(this, recyclerView);
        }
        private static class ListController implements MessageListener {
            private static final int MESSAGES_PER_REQUEST = 25;
            private final RecyclerView recyclerView;
            private final MessagesAdapter adapter;
            static ListController install(WebimChatFragment webimChatFragment,
                                          RecyclerView recyclerView) {
                return new ListController(webimChatFragment, recyclerView);
            }
            private ListController(final WebimChatFragment webimChatFragment,
                                   final RecyclerView recyclerView) {
                this.recyclerView = recyclerView;
                this.adapter = new MessagesAdapter(webimChatFragment);
                this.recyclerView.setAdapter(this.adapter);
            }
            @Override
            public void messageAdded(@Nullable Message before, @NonNull Message message) {
                int index = (before == null) ? 0 : adapter.indexOf(before);
                if (index <= 0) {
                    adapter.add(message);
                    adapter.notifyItemInserted(0);
                } else {
                    adapter.add(index, message);
                    adapter.notifyItemInserted(adapter.getItemCount() - index - 1);
                }
            }

            @Override
            public void messageRemoved(@NonNull Message message) {
                int index = adapter.indexOf(message);
                if (index != -1) {
                    adapter.remove(index);
                    adapter.notifyItemRemoved(adapter.getItemCount() - index);
                }
            }

            @Override
            public void messageChanged(@NonNull Message from, @NonNull Message to) {
                int index = adapter.lastIndexOf(from);
                if (index != -1) {
                    adapter.set(index, to);
                    adapter.notifyItemChanged(adapter.getItemCount() - index - 1, 42);
                }
            }

            @Override
            public void allMessagesRemoved() {
                int size = adapter.getItemCount();
                adapter.clear();
                adapter.notifyItemRangeRemoved(0, size);
            }
        }
    }
    ```

    Список всех методов, а также полную информацию о них можно найти в описании [`MessageListener`](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#message-listener).

  1. `MessageTracker` необходим для получения истории сообщений, которая хранится на локальном устройстве. На сервере же история сообщений хранится без ограничений по времени. Объект класса `MessageTracker` можно получить через метод `newMessageTracker(MessageListener)` объекта `MessageStream`:

    ```
    MessageTracker tracker = session.getStream.newMessageTracker(this);
    ```

    Метод `newMessageTracker(MessageListener)` объекта `MessageStream` создает объект класса `MessageTracker`, с помощью которого можно управлять потоком сообщений в контексте приложения клиента. Для получения последних сообщений из истории можно использовать метод `getLastMessages(int limit, GetMessagesCallback callback)`, но не больше указанного лимита.

    Пример использования метода:

    ```
    int MESSAGES_PER_REQUEST = 25;
    tracker.getLastMessages(MESSAGES_PER_REQUEST, new MessageTracker.GetMessagesCallback() {
                    @Override
                    public void receive(@NonNull final List<? extends Message> received) {
                        //your code
                    }
                });
    ```

    Для дальнейшей итерации по истории сообщений вызывается метод `getNextMessages(int limit, GetMessagesCallback)` — он запрашивает определенное количество сообщений из истории.

    Пример использования метода:

    ```
    int MESSAGES_PER_REQUEST = 25;
    tracker.getNextMessages(MESSAGES_PER_REQUEST, new MessageTracker.GetMessagesCallback() {
                    @Override
                    public void receive(@NonNull final List<? extends Message> received) {
                        //your code
                    }
                });
    ```

    `Message` необходим для хранения информации о сообщениях. С помощью методов экземпляров класса `Message` можно получить все необходимые данные о конкретном сообщении: уникальный номер сообщения (метод `getId()`), текст сообщения (метод `getText()`), информацию о вложенном файле (метод `getAttachment()`) и т.д. Методы интерфейса `MessageListener` оперируют объектами класса `Message`. Все связанные с этим классом инструменты (методы для работы с вложениями, типы сообщений и пр.) описаны [здесь](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html#message).

    Подробное описание этих и других методов можно найти в [справочнике методов для Android](https://webim.ru/kb/mobile/sdk/v-4-0/android-sdk-handbook.html).

    !!! Note "N.B."
        Сервис Webim не поддерживает загрузку и отображение изображений в форматах **HEIC/HEIF**: такие файлы будут отклонены сервером, даже если расширения `heic`/`heif` добавлены в `allowed_upload_file_types` на стороне аккаунта. При реализации отправки файлов в Android-приложении необходимо либо исключить выбор файлов этих форматов, либо конвертировать изображение в поддерживаемый формат (например, `jpeg` или `png`) до отправки через Webim Mobile SDK.

## Шаг 3. Прочие настройки

Кроме установки перечисленных ранее интерфейсов для корректной работы приложения на базе **Webim Mobile SDK** необходимо произвести ряд настроек в коде приложения.

  1. Необходимо правильно настроить процедуру составления `visitor fields` и подсчёта `hash`.
  Приватный ключ аккаунта не должен храниться на устройстве или где бы то ни было, кроме сервера заказчика. В противном случае появляется серьёзная угроза безопасности и риск утечки переписок клиента третьим лицам.

    Пример передачи `json-encoded` объекта посетителя SDK:

    ```
    .setVisitorFieldsJson("{
        "fields": {
          "id":"1234567890987654321",
          "display_name":"Никита"
        },
        "hash":"ffadeb6aa3c788200824e311b9aa44cb"
    }")
    ```

    Подробно об идентификации авторизованных клиентов можно почитать в [этой статье](https://webim.ru/kb/dev/identification/id-2-0.html).

  1. Для приложения на базе SDK может быть использован обфускатор. В этом случае необходимо задавать исключения в правилах обфускатора, чтобы определённые классы не обфусцировались — это необходимо для корректной работы приложения на базе **Webim** Mobile SDK. В частности, при использовании обфускатора **Proguard** следует задать в его правилах следующее:

    ```
    -keep public class ru.webim.android.sdk.* { *; }

    # when using ru.webim.sdk:chatview dependency

    -keep class ru.webim.chatview.** { *; }
    ```

    Это будет означать, что указанный пакет/класс не будет "шифроваться" обфускатором.

  1. Обеспечить необходимые сетевые доступы.

    Для мобильного устройства, на котором установлено мобильное приложение, интегрированное с **Webim Mobile SDK**, должны быть открыты исходящие порты для следующих URL-адресов:

      * `https://*.webim.ru/l/v/m/action 443 (POST)` - используется для передачи действий от клиентов.

      * `https://*.webim.ru/l/v/m/init 443 (GET)` - используется для инициализации сессии

      * `https://*.webim.ru/l/v/m/delta 443 (GET)` - используется для получения инкрементальных обновлений.

      * `https://*.webim.ru/l/v/m/download 443 (GET)` (не используется в SDK, но нужно для скачивания файлов в мобильном приложении)

      * `https://*.webim.ru/l/v/m/upload 443 (POST)` - используется для отправки файлов с клиента на сервер.

      * `https://*.webim.ru/l/v/file-delete 443 (GET)` - используется для удаления файлов клиента с сервера.

      * `https://*.webim.ru/l/v/m/history 443 (GET)` - используется для получения истории чата из базы данных.

      * `https://*.webim.ru/l/v/m/search-messages 443 (GET)` - используется для поиска по истории сообщений.

      * `https://*.webim.ru/l/v/get-online-status 443 (GET)` - используется для получения информации о статусе размещения.

      * `https://*.webim.ru/api/visitor/v1/configs/* 443 (GET)` — используется для получения конфигурации аккаунта.

      * `https://*.webim.ru/l/v/m/auth 443 (POST)` - используется для аутентификации посетителя.

      * `https://*.webim.ru/l/v/m/info 443 (GET)` - используется для получения информации без создания сессии.

      * `https://*.webim.ru/api/visitor/meta 443 (GET)` — используется для получения метаданных и конфигурации endpoint’ов сессии посетителя (в т.ч. актуальных путей к API), а не для выборки истории сообщений.

    Если чат размещён на серверах заказчика, то домен должен быть изменен на их собственный.

    Для отправки push-уведомлений FCM вашей сети потребуется взаимодействовать со следующими серверами по протоколу HTTPS:

      * `fcm.googleapis.com`

      * `accounts.google.com`

      * `iid.googleapis.com`

    Данные порты должны быть доступны: 443, 5228, 5229, 5230.

    С более подробной информацией можно ознакомиться на сайте [Firebase](https://firebase.google.com/docs/cloud-messaging/network-configuration).

  1. Для того, чтобы после завершения чата пользователь мог поставить оценку работы оператора, необходимо описать соответствующий механизм в приложении. SDK не реализует механизм оценки, а получает её от приложения клиента.

  1. Включены и настроены push-уведомления (опционально). Подробнее параметры push-уведомлений и примеры можно посмотреть в статье [Push-уведомления](https://webim.ru/kb/mobile/push-notifications/).

  1. Для начала чата может вызываться метод `startChat()`. Если метод не будет вызван, чат будет начат после первого сообщения посетителя.

---

Источник: https://webim.ru/kb/mobile/sdk/v-4-0/android-integration.html
