Pull to refresh

Разрабатываем приложение, которое отсылает данные другим приложениям (экосистемное приложение)

Reading time3 min
Views3.8K
Привет, ребята!

Это моя вторая статья про разработку своего проекта. Тем, кто не читал предыдущую статейку: она про то, как из одного места (гугл таблицы) автоматически экспортировать данные в другое (ноушн).

Сегодня я расскажу, как я писал (и проектировал) библиотеку для того, чтобы сторонние приложения могли получать данные, отправляемые моим приложением. Всех заинтересовавшихся прошу под кат.

Часть 1. Проблема


Вкратце про проект. Есть устройство, которое подключается к смартфону. Есть мое приложение, внутри которого нейросеть распознает данные от устройства и выдает результат. И есть другие приложения, которые хотят получить этот самый результат.

Результат бывает нескольких видов: голые данные с устройства, обработанные данные с устройства, информация о состоянии устройства, информация о правах доступа приложения к данным (например, что пользователь отозвал права доступа к данным устройства). Нужно как-то передавать этот самый результат в другие приложения.

Если вдруг я что-то неправильно поясню по своему коду — вот тут документация к моей библиотеке.

Часть 2. Планируем решение


Есть замечательный механизм — Broadcast'ы. Если вкратце — это сообщение от одного приложения другим приложениям. Можно отправить сразу всем, а можно — какому-то определенному.

Чтобы это дело отправлять и принимать, нужно:

  1. Как-то сделать из передаваемого объекта JSON
  2. Отправить Broadcast
  3. Принять Broadcast в другом приложении
  4. Восстановить передаваемый объект из JSON

Вообще делать из объекта JSON — это не всегда корректно. Можно отправлять через Broadcast штуку, называемую Parcelable, а можно — Serializable. Serializable — это стандартная вещица из Java, Parcelable — аналогичная штука, но оптимизированная для мобильных устройств.

У меня объекты достаточно маленькие. Кроме того, зачастую надо получить именно JSON: я сам написал стороннее приложение, чтобы оно отправляло на сервер сырые данные. Поэтому я выбрал именно «сделать из передаваемого объекта JSON». Возможно, потом я передумаю.

Часть 3. Пилим решение


Пункт 1 и пункт 4. В JSON, а потом обратно


Тут все просто. Есть библиотека Gson, которая чудесно подходит для наших нужд.

Чтобы сделать все круто, переопределим метод toString(). Ну и сделать fromString(), чтобы получить обратно наш объект.

class SecureData(val eeg1: Double?, val eeg2: Double?, date: Date) {
    override fun toString(): String {
        val gson = Gson()
        return gson.toJson(this)
    }

    companion object {
        fun fromString(model: String): SecureData {
            val gson = Gson()
            return gson.fromJson(model, SecureData::class.java)
        }
    }
}

Пункт 2. Посылаем объект


Вот пример такого кода:

val intent = Intent()
intent.action = BroadcastUtils.BROADCAST_GESTURE
intent.putExtra(BroadcastUtils.EXTRA_GESTRE, it.toString())
sendBroadcast(intent)

Тут мы создаем intent, задаем его действие, кладем объект и отправляем как broadcast.
BroadcastUtils.BROADCAST_GESTURE — это штучка, по которой мы будем фильтровать поступающие broadcast'ы в другом приложении (нужно ли обрабатывать это или не нужно).

Чтобы отправить сообщение конкретному приложению, нужно еще дополнительно задать следующее:

 intent.component = ComponentName(
         PermissionsFetcher.REFACE_APP,
         "${PermissionsFetcher.REFACE_APP}.receivers.ActionsReceiver"
 )

PermissionsFetcher.REFACE_APP — это APPLICATION_ID моего приложения, а ${PermissionsFetcher.REFACE_APP}.receivers.ActionsReceiver — путь до ресивера.

Пункт 3. Получаем объекты


Вот так мы регистрируем ресивер. Если вы регистрируете его, используя контекст приложения — он будет получать broadcast'ы, пока приложение не закрыто. Если используете контекст активити — пока она не закроется.

        registerReceiver(GesturesReceiver(), IntentFilter(BroadcastUtils.BROADCAST_GESTURE))

А вот GesturesReceiver:

class GesturesReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        Timber.i("Received gesture")

        val action = BroadcastUtils.reparseGestureIntent(intent)
        MainApp.actionSubject.onNext(action)
    }
}

Тут я, как видите, получил интент, переделал его обратно в объект и отправил куда-то-там с помощью RxJava.

Часть 4. Заключение


Вы прочитали статью по проектированию приложений, которые должны взаимодействовать с другими приложениями. Надеюсь, этот опыт вам чем-то поможет.

Для пущего эффекта можно посмотреть исходники моей библиотеки и пример работы с ней и поставить звездочку на случай, если вам когда-нибудь это пригодится: github.com/reface-tech/CodeSpecialApp
Tags:
Hubs:
+7
Comments0

Articles

Change theme settings