Подключение SignalR для Android на Kotlin

от автора

Если ты читаешь эту статью, наверно тебе, как и мне понадобилось подключить SignalR в своем мобильном приложении. К сожалению в русскоязычном сегменте не так уж много информации о том, как это сделать, а то что есть уже устарело.

В рамках этой статьи я не буду касаться серверной части, но постараюсь предоставить все необходимое примеры кода с комментариями для реализации SignalR в Android, а получившийся пример выложу на GitHub.

Что такое SignalR и когда он используется?

Это библиотека с открытым исходным кодом, которая упрощает добавление веб-функций в режиме реального времени в приложения. Веб-функции в режиме реального времени позволяют коду на стороне сервера мгновенно отправлять содержимое на клиенты.

  • Управляет автоматическим управлением соединениями.

  • Отправляет сообщения всем подключенным клиентам одновременно. Например, комната чатов.

  • Отправляет сообщения конкретным клиентам или группам клиентов.

  • Масштабируется для управления увеличением трафика.

Схематично

Более подробно здесь

Создаем проект и подключаем зависимости.

Создаем новый проект на основе Empty Activity, я назову его SignalR_Example

Создание нового проекта

Добавляем 3 необходимые зависимости в build.gradle проекта:

implementation «com.microsoft.signalr:signalr:5.0.10»
Смотрим актуальную версию здесь

implementation «com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2»
Смотрим актуальную версию здесь

implementation ‘com.google.code.gson:gson:2.8.8’
Смотрим актуальную версию здесь

Зависимости в build.gradle

Создаем необходимые классы

Класс SignalRListener и соответствующий ему интерфейс ISignalRListener
Он будет содержать подключение к HubConnection и основную реализацию слушателя внешних событий.

Класс SignalRListener
/**  * Представляет SignalR-реализацию слушателя внешних событий.  * @param sslSocketFactory Модифицированный протокол безопасной передачи данных.  * @param trustAllCerts Модифицированный X509TrustManager для доверия всем сертификатам.  */ class SignalRListener (     private val sslSocketFactory: SSLSocketFactory,     private val trustAllCerts: TrustAllCerts ) : ISignalRListener {      private val apiUrl = "https://something.com/api/"   //Адрес Вашего api     private val hubConnection = HubConnectionBuilder.create(apiUrl + "GatewayHub")   //         .setHttpClientBuilderCallback {             it.sslSocketFactory(sslSocketFactory, trustAllCerts)         }         .build()      override val connectionId: String?         get() = hubConnection.connectionId     override val connectionState: HubConnectionState         get() = hubConnection.connectionState      override fun startConnection() {         hubConnection.start()     }      override fun stopConnection() {         hubConnection.stop()     }      override fun subscribe(         eventName: String,         handler: (event: LinkedTreeMap<String, String>) -> Unit     ) {         hubConnection.on(             eventName,             handler,             LinkedTreeMap::class.java         )     }      override fun unsubscribe(eventName: String) {         hubConnection.remove(eventName)     } }
Интерфейс ISignalRListener
/**  * Описывает реализацию слушателя внешних событий.  */ interface ISignalRListener {     /**      * Возвращает id подключения к SignalR.      */     val connectionId: String?      /**      * Возвращает статус подключения к SignalR.      */     val connectionState: HubConnectionState      /**      * Выполняет подключение к серверу SignalR.      */     fun startConnection()      /**      * Выполняет отключение от сервера SignalR.      */     fun stopConnection()      /**      * Подписывается на событие.      * @param eventName Имя события.      * @param handler Обработчик события.      */     fun subscribe(eventName: String, handler: (LinkedTreeMap<String, String>) -> Unit)      /**      * Отписывается от события.      * @param eventName Имя события.      */     fun unsubscribe(eventName: String) }

Класс SignalRService и соответствующий ему интерфейс ISignalRService
Он будет содержать реализацию подписок на ресурсы.

Класс SignalRService
/**  * Представляет реализацию подписок на ресурсы.  */ class SignalRService (     private val signalRListener: ISignalRListener ) : ISignalRService {     /**      * Возвращает или устанавливает подписку на ресурсы.      */     private val resourcesSubscriptions = mutableListOf<ResourceSubscriptionModel>()      init {         subscribeOnResourceChanged()     }      /**      * Подписывается на события изменения ресурса.      */     private fun subscribeOnResourceChanged() {         signalRListener.subscribe(             "ResourceChangedEventOccurred"         ) { event ->             resourcesSubscriptions.forEach { subscription ->                 val resourceName = event["resourceName"]                 if (resourceName != null && resourceName.contains(subscription.resourceName)) {                     //Реагируем на изменение ресурса.                     subscription.callback()                 }             }         }     }      override fun subscribe(subscriptionsForAdd: List<ResourceSubscriptionModel>) {         subscriptionsForAdd.forEach { resourceSubscription ->             resourcesSubscriptions.add(resourceSubscription)         }     }      override fun unsubscribe(subscriptionsForRemove: List<ResourceSubscriptionModel>) {         subscriptionsForRemove.forEach { resourceSubscription ->             resourcesSubscriptions.remove(resourceSubscription)         }     } }
Интерфейс ISignalRService
/**  * Описывает методы подписки на внешние события.  */ interface ISignalRService {     /**      * Добавляет ресурсы в подписку.      * @param subscriptionsAdd Список ресурсов для подписки.      */     fun subscribe(subscriptionsAdd: List<ResourceSubscriptionModel>)      /**      * Удаляет ресурсы из подписки.      * @param subscriptionsRemove Список ресурсов для отписки.      */     fun unsubscribe(subscriptionsRemove: List<ResourceSubscriptionModel>) }

Дата класс ResourceSubscriptionModel

Он будет представлять подписку на ресурс.

Дата класс ResourceSubscriptionModel
/**  * Представляет подписку на ресурс.  */ data class ResourceSubscriptionModel(     /**      * Имя ресурса для отслеживания событий.      */     val resourceName: String,     /**      * Метод выполняемый при получении события.      */     val callback: () -> Unit )

Класс TrustAllCerts

Он позволит доверять всем сертификатам.

Класс TrustAllCerts
/**  * Позволяет доверять всем сертификатом.  */ class TrustAllCerts : X509TrustManager {     override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()     override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) = Unit     override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit }

Класс SignalRApplication
Он представляет класс нашего приложения и будет хранить синглтоны ISignalRListener и ISignalRService. По хорошему следует использовать какой ни будь DI инструмент, но для упрощения примера сделаем так. Не забываем добавлять его в манифест.

Класс SignalRApplication
/**  * Представляет приложение.  */ class SignalRApplication : Application() {      lateinit var signalRListener: ISignalRListener   // Слушатель внешних событий.     lateinit var signalRService: ISignalRService   // Сервис подписок на ресурсы.      companion object {         lateinit var application: SignalRApplication     }      override fun onCreate() {         super.onCreate()         application = this          // Модифицированный X509TrustManager для доверия всем сертификатам.         val trustAllCerts = TrustAllCerts()         // Модифицированный протокол безопасной передачи данных.         val sslSocketFactory = SSLContext.getInstance("TLSv1.2").apply {                 init(null, arrayOf<TrustManager>(trustAllCerts), SecureRandom())             }.socketFactory          signalRListener = SignalRListener(sslSocketFactory, trustAllCerts)         signalRService = SignalRService(signalRListener)     }  }

Абстрактный класс BaseActivity

Он будет представлять базовый класс для наших Activity и содержать методы на подписку и отписку от событий.

Абстрактный класс BaseActivity
/**  * Представляет базовый класс Activity  */ abstract class BaseActivity : AppCompatActivity() {      /**      * Сервис подписок на ресурсы.      */     private val _signalRService = SignalRApplication.application.signalRService      /**      * Лист подписок.      */     private val _resourceSubscriptions: MutableList<ResourceSubscriptionModel> = mutableListOf()      override fun onStop() {         super.onStop()         _signalRService.unsubscribe(_resourceSubscriptions)     }      /**      * Устанавливает подписки на ресурсы.      * @param resourceSubscriptions Лист подписок.      */     fun setSignalRSubscriptions(         resourceSubscriptions: List<ResourceSubscriptionModel>     ) {         _resourceSubscriptions.addAll(resourceSubscriptions)         _signalRService.subscribe(resourceSubscriptions)     } }

Скачать пример проекта можно здесь


ссылка на оригинал статьи https://habr.com/ru/articles/579916/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *