Если ты читаешь эту статью, наверно тебе, как и мне понадобилось подключить 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/
Добавить комментарий